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 java.util.*;
29 import jdk.internal.vm.annotation.Stable;
30
31 import static java.lang.invoke.MethodHandleStatics.rangeCheck1;
32 import static java.lang.invoke.MethodHandleStatics.rangeCheck2;
33
34 /** Utility class for implementing ConstantGroup. */
35 /*non-public*/
36 abstract class AbstractConstantGroup implements ConstantGroup {
37 /** The size of this constant group, set permanently by the constructor. */
38 protected final int size;
39
40 /** The constructor requires the size of the constant group being represented.
41 * @param size the size of this constant group, set permanently by the constructor
42 */
43 AbstractConstantGroup(int size) {
44 this.size = size;
45 }
46
47 @Override public final int size() {
48 return size;
49 }
50
51 public abstract Object get(int index) throws LinkageError;
52
53 public abstract Object get(int index, Object ifNotPresent);
54
55 public abstract boolean isPresent(int index);
56
57 // Do not override equals or hashCode, since this type is stateful.
58
59 /**
60 * Produce a string using the non-resolving list view,
61 * where unresolved elements are presented as asterisks.
62 * @return {@code this.asList("*").toString()}
63 */
64 @Override public String toString() {
65 return asList("*").toString();
66 }
67
68 static class AsIterator implements Iterator<Object> {
69 private final ConstantGroup self;
70 private final int end;
71 private final boolean resolving;
72 private final Object ifNotPresent;
73
74 // Mutable state:
75 private int index;
76
77 private AsIterator(ConstantGroup self, int start, int end,
78 boolean resolving, Object ifNotPresent) {
79 this.self = self;
80 this.end = end;
81 this.index = start;
82 this.resolving = resolving;
83 this.ifNotPresent = ifNotPresent;
84 }
85 AsIterator(ConstantGroup self, int start, int end) {
86 this(self, start, end, true, null);
87 }
88 AsIterator(ConstantGroup self, int start, int end,
89 Object ifNotPresent) {
90 this(self, start, end, false, ifNotPresent);
91 }
92
93 @Override
94 public boolean hasNext() {
95 return index < end;
96 }
97
98 @Override
99 public Object next() {
100 int i = bumpIndex();
101 if (resolving)
102 return self.get(i);
103 else
104 return self.get(i, ifNotPresent);
105 }
106
107 private int bumpIndex() {
108 int i = index;
109 if (i >= end) throw new NoSuchElementException();
110 index = i+1;
111 return i;
112 }
113 }
114
115 static class SubGroup extends AbstractConstantGroup {
116 private final ConstantGroup self; // the real CG
117 private final int offset; // offset within myself
118 SubGroup(ConstantGroup self, int start, int end) {
119 super(end - start);
120 this.self = self;
121 this.offset = start;
122 rangeCheck2(start, end, size);
123 }
124
125 private int mapIndex(int index) {
126 return rangeCheck1(index, size) + offset;
127 }
128
129 @Override
130 public Object get(int index) {
131 return self.get(mapIndex(index));
132 }
133
134 @Override
135 public Object get(int index, Object ifNotPresent) {
136 return self.get(mapIndex(index), ifNotPresent);
137 }
138
139 @Override
140 public boolean isPresent(int index) {
141 return self.isPresent(mapIndex(index));
142 }
143
144 @Override
145 public ConstantGroup subGroup(int start, int end) {
146 rangeCheck2(start, end, size);
147 return new SubGroup(self, offset + start, offset + end);
148 }
149
150 @Override
151 public List<Object> asList() {
152 return new AsList(self, offset, offset + size);
153 }
154
155 @Override
156 public List<Object> asList(Object ifNotPresent) {
157 return new AsList(self, offset, offset + size, ifNotPresent);
158 }
159
160 @Override
161 public int copyConstants(int start, int end,
162 Object[] buf, int pos) throws LinkageError {
163 rangeCheck2(start, end, size);
164 return self.copyConstants(offset + start, offset + end,
165 buf, pos);
166 }
167
168 @Override
169 public int copyConstants(int start, int end,
170 Object[] buf, int pos,
171 Object ifNotPresent) {
172 rangeCheck2(start, end, size);
173 return self.copyConstants(offset + start, offset + end,
174 buf, pos, ifNotPresent);
175 }
176 }
177
178 static class AsList extends AbstractList<Object> {
179 private final ConstantGroup self;
180 private final int size;
181 private final int offset;
182 private final boolean resolving;
183 private final Object ifNotPresent;
184
185 private AsList(ConstantGroup self, int start, int end,
186 boolean resolving, Object ifNotPresent) {
187 this.self = self;
188 this.size = end - start;
189 this.offset = start;
190 this.resolving = resolving;
191 this.ifNotPresent = ifNotPresent;
192 rangeCheck2(start, end, self.size());
193 }
194 AsList(ConstantGroup self, int start, int end) {
195 this(self, start, end, true, null);
196 }
197 AsList(ConstantGroup self, int start, int end,
198 Object ifNotPresent) {
199 this(self, start, end, false, ifNotPresent);
200 }
201
202 private int mapIndex(int index) {
203 return rangeCheck1(index, size) + offset;
204 }
205
206 @Override public final int size() {
207 return size;
208 }
209
210 @Override public Object get(int index) {
211 if (resolving)
212 return self.get(mapIndex(index));
213 else
214 return self.get(mapIndex(index), ifNotPresent);
215 }
216
217 @Override
218 public Iterator<Object> iterator() {
219 if (resolving)
220 return new AsIterator(self, offset, offset + size);
221 else
222 return new AsIterator(self, offset, offset + size, ifNotPresent);
223 }
224
225 @Override public List<Object> subList(int start, int end) {
226 rangeCheck2(start, end, size);
227 return new AsList(self, offset + start, offset + end,
228 resolving, ifNotPresent);
229 }
230
231 @Override public Object[] toArray() {
232 return toArray(new Object[size]);
233 }
234 @Override public <T> T[] toArray(T[] a) {
235 int pad = a.length - size;
236 if (pad < 0) {
237 pad = 0;
238 a = Arrays.copyOf(a, size);
239 }
240 if (resolving)
241 self.copyConstants(offset, offset + size, a, 0);
242 else
243 self.copyConstants(offset, offset + size, a, 0,
244 ifNotPresent);
245 if (pad > 0) a[size] = null;
246 return a;
247 }
248 }
249
250 static abstract
251 class WithCache extends AbstractConstantGroup {
252 @Stable final Object[] cache;
253
254 WithCache(int size) {
255 super(size);
256 // It is caller's responsibility to initialize the cache.
257 // Initial contents are all-null, which means nothing is present.
258 cache = new Object[size];
259 }
260
261 void initializeCache(List<Object> cacheContents, Object ifNotPresent) {
262 // Replace ifNotPresent with NOT_PRESENT,
263 // and null with RESOLVED_TO_NULL.
264 // Then forget about the user-provided ifNotPresent.
265 for (int i = 0; i < cache.length; i++) {
266 Object x = cacheContents.get(i);
267 if (x == ifNotPresent)
268 continue; // leave the null in place
269 if (x == null)
270 x = RESOLVED_TO_NULL;
271 cache[i] = x;
272 }
273 }
274
275 @Override public Object get(int i) {
276 Object x = cache[i];
277 // @Stable array must use null for sentinel
278 if (x == null) x = fillCache(i);
279 return unwrapNull(x);
280 }
281
282 @Override public Object get(int i, Object ifNotAvailable) {
283 Object x = cache[i];
284 // @Stable array must use null for sentinel
285 if (x == null) return ifNotAvailable;
286 return unwrapNull(x);
287 }
288
289 @Override
290 public boolean isPresent(int i) {
291 return cache[i] != null;
292 }
293
294 /** hook for local subclasses */
295 Object fillCache(int i) {
296 throw new NoSuchElementException("constant group does not contain element #"+i);
297 }
298
299 /// routines for mapping between null sentinel and true resolved null
300
301 static Object wrapNull(Object x) {
302 return x == null ? RESOLVED_TO_NULL : x;
303 }
304
305 static Object unwrapNull(Object x) {
306 assert(x != null);
307 return x == RESOLVED_TO_NULL ? null : x;
308 }
309
310 // secret sentinel for an actual null resolved value, in the cache
311 static final Object RESOLVED_TO_NULL = new Object();
312
313 // secret sentinel for a "hole" in the cache:
314 static final Object NOT_PRESENT = new Object();
315
316 }
317
318 /** Skeleton implementation of BootstrapCallInfo. */
319 static
320 class BSCIWithCache<T> extends WithCache implements BootstrapCallInfo<T> {
321 private final MethodHandle bsm;
322 private final String name;
323 private final T type;
324
325 @Override public String toString() {
326 return bsm+"/"+name+":"+type+super.toString();
327 }
328
329 BSCIWithCache(MethodHandle bsm, String name, T type, int size) {
330 super(size);
331 this.type = type;
332 this.bsm = bsm;
333 this.name = name;
334 assert(type instanceof Class || type instanceof MethodType);
335 }
336
337 @Override public MethodHandle bootstrapMethod() { return bsm; }
338 @Override public String invocationName() { return name; }
339 @Override public T invocationType() { return type; }
340 }
341 }
|
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 }
|