1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import jdk.internal.vm.annotation.Stable; 29 30 import java.lang.constant.ClassDesc; 31 import java.lang.constant.Constable; 32 import java.lang.constant.ConstantDesc; 33 import java.lang.constant.MethodTypeDesc; 34 import java.lang.invoke.MethodHandles.Lookup; 35 import java.util.*; 36 import java.util.function.IntFunction; 37 38 import static java.lang.invoke.BootstrapMethodInvoker.VM_BSCI; 39 import static java.lang.invoke.MethodHandleNatives.Constants.*; 40 import static java.lang.invoke.MethodHandleStatics.rangeCheck1; 41 import static java.lang.invoke.MethodHandleStatics.rangeCheck2; 42 43 /** 44 * Utility class for implementing BootstrapCallInfo. 45 * Implements the three list-views on top of the three indexes accessors. 46 * The {@link WithCache} subclass adds a backing store. 47 */ 48 /*non-public*/ 49 abstract class AbstractBootstrapCallInfo<T extends TypeDescriptor & Constable<T>> 50 implements BootstrapCallInfo<T> { 51 /** The size of this constant group, set permanently by the constructor. */ 52 private final MethodHandle bsm; 53 private final String name; 54 private final TypeView<T> typeView; 55 private final IntFunction<ConstantDesc<?>> symFinder = null; //@@ 56 protected final int argumentCount; 57 58 // view caches: 59 private @Stable ArgList argListF; 60 private ArgList argListI; // can be reassigned for differing ifPresent values 61 private @Stable List<ConstantDesc<?>> argListS; 62 63 /** 64 * Constructor, which takes permanent settings for the properties of the BSCI. 65 * @param bsm bootstrap method, which must be previously resolved 66 * @param name name string used for invocation or constant 67 * @param typeView type used for invocation or constant (wrapped as resolved or unresolved) 68 * @param argumentCount number of static arguments for bootstrap method 69 */ 70 AbstractBootstrapCallInfo(MethodHandle bsm, String name, TypeView<T> typeView, int argumentCount) { 71 this.bsm = bsm; 72 this.name = name; 73 this.typeView = typeView; 74 this.argumentCount = argumentCount; 75 } 76 77 @Override public MethodHandle bootstrapMethod() { return bsm; } 78 79 @Override public String invocationName() { return name; } 80 81 @Override public T invocationType() { return typeView.invocationType(); } 82 83 @Override public ConstantDesc<T> invocationTypeDesc() { return typeView.invocationTypeDesc(); } 84 85 @Override public final int argumentCount() { return argumentCount; } 86 87 @Override 88 public abstract Object argument(int index) throws LinkageError; 89 90 @Override 91 public abstract Object argument(int index, Object ifNotPresent); 92 93 @Override 94 public abstract ConstantDesc<?> argumentDesc(int index); 95 96 @Override 97 public abstract boolean argumentIsPresent(int index); 98 99 /** 100 * Produce a string that briefly reports the BSM, name, type, 101 * and argument list. For arguments, use a non-resolving list view, 102 * with unresolved elements being presented as asterisks. 103 * @return {@code this.asList("*").toString()} 104 */ 105 @Override public String toString() { 106 return BootstrapCallInfo.toString(this); 107 } 108 // (Do not override equals or hashCode, since this type is stateful.) 109 110 /** 111 * Representative of a resolved type mirror, an unresolved type descriptor, or both. 112 * If one component is null, the {@code TypeView} can lazily resolve it from the other. 113 * If the type component is null, a {@code Lookup} object must be supplied to resolve the type descriptor. 114 * @param <T> the type {@code MethodType} or {@code Class} 115 */ 116 static 117 class TypeView<T extends TypeDescriptor & Constable<T>> { 118 private @Stable T type; 119 private @Stable ConstantDesc<T> typeDesc; 120 private final Lookup lookup; // used only to resolve typeDesc 121 122 public T invocationType() { 123 if (type == null) resolve(); 124 return type; 125 } 126 public ConstantDesc<T> invocationTypeDesc() { 127 if (typeDesc == null) resolve(); 128 return typeDesc; 129 } 130 131 private TypeView(T type, ConstantDesc<T> typeDesc) { 132 Objects.requireNonNull(type); 133 // typeDesc can be null, will be lazily reverse-resolved 134 this.type = type; 135 if (typeDesc != null) this.typeDesc = typeDesc; 136 this.lookup = null; 137 check(); 138 } 139 140 TypeView(T type) { 141 this(type, null); 142 } 143 144 TypeView(ConstantDesc<T> typeDesc, Lookup lookup) { 145 Objects.requireNonNull(typeDesc); 146 Objects.requireNonNull(lookup); 147 this.typeDesc = typeDesc; 148 this.lookup = lookup; 149 check(); 150 } 151 private void check() { 152 if (!(type == null || 153 type instanceof Class || 154 type instanceof MethodType)) { 155 throw new IllegalArgumentException("must be class or method type: " + type); 156 } 157 if (!(typeDesc == null || 158 typeDesc instanceof ClassDesc || 159 typeDesc instanceof MethodTypeDesc)) { 160 throw new IllegalArgumentException("must be class or method type descriptor: " + typeDesc); 161 } 162 } 163 @Override 164 public String toString() { 165 Object res = typeDesc; 166 if (type != null) { 167 res = type; 168 if (res instanceof Class) 169 res = ((Class<?>)type).getSimpleName(); 170 } 171 return res.toString(); 172 } 173 174 /** Fill in either field if it is null. */ 175 void resolve() { 176 if (type != null && typeDesc == null) { 177 typeDesc = type.describeConstable().orElse(null); 178 } 179 if (typeDesc != null && type == null) { 180 try { 181 type = typeDesc.resolveConstantDesc(lookup); 182 } catch (ReflectiveOperationException ex) { 183 Object what; 184 if (typeDesc instanceof TypeDescriptor) 185 what = ((TypeDescriptor) typeDesc).descriptorString(); 186 else what = typeDesc.toString(); 187 throw new NoClassDefFoundError("cannot resolve: " + what); 188 } 189 } 190 // check required end-state 191 if (type == null || typeDesc == null) { 192 throw new InternalError("cannot resolve type"); 193 } 194 } 195 } 196 197 /// List-view machinery 198 199 @Override 200 public List<Object> argumentList() { 201 ArgList args = argListF; 202 if (args == null) 203 argListF = args = new ArgList(this, 0, argumentCount()); 204 return args; 205 } 206 207 @Override 208 public List<Object> argumentList(Object ifNotPresent) { 209 ArgList args = argListI; 210 if (args == null || args.ifNotPresent != ifNotPresent) 211 argListI = args = new ArgList(this, 0, argumentCount(), ifNotPresent); 212 return args; 213 214 } 215 216 @Override 217 public List<ConstantDesc<?>> argumentDescList() { 218 List<ConstantDesc<?>> args = argListS; 219 if (args == null) 220 argListS = args = argumentDescList(this); 221 return args; 222 } 223 224 static List<Object> argumentList(AbstractBootstrapCallInfo<?> self) { 225 return new ArgList(self, 0, self.argumentCount()); 226 } 227 static List<Object> argumentList(AbstractBootstrapCallInfo<?> self, Object ifPresent) { 228 return new ArgList(self, 0, self.argumentCount(), ifPresent); 229 } 230 static List<ConstantDesc<?>> argumentDescList(AbstractBootstrapCallInfo<?> self) { 231 ArgList args = new ArgList(self, true, 0, self.argumentCount()); 232 @SuppressWarnings({"unchecked", "rawtypes"}) 233 List<ConstantDesc<?>> result = (List) args; 234 return result; 235 } 236 237 /** Non-public implementation of the three List views for BootstrapCallInfo. */ 238 static class ArgList extends AbstractList<Object> { 239 private final BootstrapCallInfo<?> self; 240 private final int size; 241 private final int offset; 242 private final byte resolving; 243 private final Object ifNotPresent; 244 245 private ArgList(BootstrapCallInfo<?> self, int start, int end, 246 byte resolving, Object ifNotPresent) { 247 this.self = self; 248 this.size = end - start; 249 this.offset = start; 250 this.resolving = resolving; 251 this.ifNotPresent = ifNotPresent; 252 rangeCheck2(start, end, self.argumentCount()); 253 } 254 ArgList(BootstrapCallInfo<?> self, int start, int end) { 255 this(self, start, end, BAR_FORCE, null); 256 } 257 ArgList(BootstrapCallInfo<?> self, int start, int end, 258 Object ifNotPresent) { 259 this(self, start, end, BAR_IFPRESENT, ifNotPresent); 260 } 261 ArgList(BootstrapCallInfo<?> self, boolean symRefs, int start, int end) { 262 this(self, start, end, BAR_SYMREF, null); 263 } 264 265 private int mapIndex(int index) { 266 return rangeCheck1(index, size) + offset; 267 } 268 269 @Override public final int size() { 270 return size; 271 } 272 273 @Override public Object get(int index) { 274 if (resolving == BAR_FORCE) 275 return self.argument(mapIndex(index)); 276 else if (resolving == BAR_SYMREF) 277 return self.argumentDesc(index); 278 else 279 return self.argument(mapIndex(index), ifNotPresent); 280 } 281 282 @Override public List<Object> subList(int start, int end) { 283 rangeCheck2(start, end, size); 284 return new ArgList(self, offset + start, offset + end, 285 resolving, ifNotPresent); 286 } 287 288 @Override public Object[] toArray() { 289 return toArray(new Object[size]); 290 } 291 @Override public <T> T[] toArray(T[] a) { 292 if (!(self instanceof VM_BSCI)) 293 return super.toArray(a); 294 int pad = a.length - size; 295 Object[] buf = a; 296 if (pad < 0) { 297 pad = 0; 298 buf = a = Arrays.copyOf(a, size); 299 } 300 if (a.getClass() != Object[].class || resolving == BAR_SYMREF) 301 buf = new Object[size]; // VM might store any kind of Object 302 ((VM_BSCI<?>) self).copyVMArguments(offset, offset + size, a, 0, resolving, ifNotPresent); 303 if (buf != a) { 304 // If a is the wrong array type, and the VM sends us a bad 305 // object, the arraycopy call is where the error will be reported. 306 System.arraycopy(buf, 0, a, 0, buf.length); 307 } 308 if (pad > 0) a[size] = null; 309 return a; 310 } 311 } 312 313 abstract static 314 class WithCache<T extends TypeDescriptor & Constable<T>> 315 extends AbstractBootstrapCallInfo<T> { 316 protected @Stable final Object[] cache; 317 protected @Stable ConstantDesc<?>[] symCache; 318 319 WithCache(MethodHandle bsm, String name, TypeView<T> typeView, int argumentCount) { 320 super(bsm, name, typeView, argumentCount); 321 // It is caller's responsibility to initialize the cache. 322 // Initial contents are all-null, which means nothing is present. 323 cache = new Object[argumentCount]; 324 // create symCache lazily 325 } 326 327 WithCache(MethodHandle bsm, String name, TypeView<T> typeView, Object[] arguments) { 328 super(bsm, name, typeView, arguments.length); 329 cache = arguments; // caller may have pre-loaded stuff into the cache 330 } 331 332 WithCache(MethodHandle bsm, String name, TypeView<T> typeView, ConstantDesc<?>[] symbolicRefs) { 333 super(bsm, name, typeView, symbolicRefs.length); 334 cache = new Object[argumentCount]; 335 symCache = symbolicRefs; 336 } 337 338 // WithCache(MethodHandle bsm, String name, TypeView<T> typeView, List<Object> allResolved) { 339 // this(bsm, name, typeView, allResolved.size()); 340 // initializeCache(allResolved); 341 // } 342 343 void initializeCache(List<Object> cacheContents) { 344 initializeCache(cacheContents, new Object()); 345 } 346 void initializeCache(List<Object> cacheContents, Object ifNotPresent) { 347 // Replace ifNotPresent with null, 348 // and null with RESOLVED_TO_NULL. 349 // Then forget about the user-provided ifNotPresent. 350 for (int i = 0; i < cache.length; i++) { 351 Object x = cacheContents.get(i); 352 if (x == ifNotPresent) 353 continue; // leave the null in place 354 cache[i] = wrapNull(x); 355 } 356 } 357 358 @Override public Object argument(int i) { 359 Object x = cache[i]; 360 // @Stable array must use null for sentinel 361 if (x == null) { 362 x = wrapNull(resolveConstant(i)); 363 // racy CAS: 364 Object x2 = cache[i]; 365 if (x2 != null) x = x2; 366 else cache[i] = x; 367 } 368 return unwrapNull(x); 369 } 370 371 @Override public Object argument(int i, Object ifNotAvailable) { 372 Object x = cache[i]; 373 // @Stable array must use null for sentinel 374 if (x == null) return ifNotAvailable; 375 return unwrapNull(x); 376 } 377 378 @Override public ConstantDesc<?> argumentDesc(int i) { 379 ConstantDesc<?>[] symCache = this.symCache; 380 if (symCache == null) { 381 this.symCache = symCache = new ConstantDesc<?>[argumentCount()]; 382 } 383 ConstantDesc<?> x = symCache[i]; 384 if (x == null) { 385 x = findSymbol(i); 386 // racy CAS: 387 ConstantDesc<?> x2 = symCache[i]; 388 if (x2 != null) x = x2; 389 else symCache[i] = x; 390 } 391 return x; 392 } 393 394 @Override 395 public boolean argumentIsPresent(int i) { 396 return cache[i] != null; //NULL_MEANS_NOT_PRESENT 397 } 398 399 /** hook for local subclasses */ 400 abstract Object resolveConstant(int i) throws LinkageError; 401 402 /** hook for local subclasses */ 403 abstract ConstantDesc<?> findSymbol(int i); 404 405 // carefully try to expose the underlying object array of arguments 406 // return null if this is not possible 407 Object[] maybeShareArguments() { 408 // fill in missing cache items, and look for null 409 for (int i = 0; i < cache.length; i++) { 410 Object cx = cache[i]; 411 Object rx = cx; 412 if (cx == null) { // empty cache entry 413 rx = argument(i); 414 cx = cache[i]; // reload filled cache entry 415 } else if (cx == RESOLVED_TO_NULL) { 416 rx = null; 417 } 418 // Punt if the cache contains a masked null value. 419 // Also punt if cache doesn't contain a value. 420 if (cx == null || rx == null) return null; 421 } 422 return cache; 423 } 424 425 /// routines for mapping between null sentinel and true resolved null 426 427 Object wrapNull(Object x) { 428 return x == null ? RESOLVED_TO_NULL : x; 429 } 430 431 Object unwrapNull(Object x) { 432 assert(x != null); 433 return x == RESOLVED_TO_NULL ? null : x; 434 } 435 436 // secret sentinel for an actual null resolved value, in the cache 437 private static final Object RESOLVED_TO_NULL = new Object(); 438 } 439 440 static Object[] maybeShareArguments(BootstrapCallInfo<?> bsci) { 441 if (bsci instanceof WithCache) { 442 WithCache<?> wc = (WithCache<?>) bsci; 443 return wc.maybeShareArguments(); 444 } 445 return null; 446 } 447 }