src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java
changeset 48826 c4d9d1b08e2e
child 59201 b24f4caa1411
equal deleted inserted replaced
48825:ef8a98bc71f8 48826:c4d9d1b08e2e
       
     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 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 }