< prev index next >

src/java.base/share/classes/java/lang/invoke/AbstractBootstrapCallInfo.java

Print this page
rev 52749 : Bootstrap method consolidation
* clean up and simplify JDK support code for BSM invocation
* simplify JVM bootstrap handshake: use BootstrapCallInfo only
* remove unused JVM paths and data fields
* move bootstrap argument processing from MethodHandleNatives to ConstantPool
* remove ConstantGroup; merge argument access into BootstrapCallInfo
* adjust BSM argument access: remove copyArguments, add argumentRef API
* add metadata-free BSM modes, including symbolic arguments from CP


   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 }
< prev index next >