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      */
AbstractConstantGroup(int size)43     AbstractConstantGroup(int size) {
44         this.size = size;
45     }
46 
size()47     @Override public final int size() {
48         return size;
49     }
50 
get(int index)51     public abstract Object get(int index) throws LinkageError;
52 
get(int index, Object ifNotPresent)53     public abstract Object get(int index, Object ifNotPresent);
54 
isPresent(int index)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      */
toString()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 
AsIterator(ConstantGroup self, int start, int end, boolean resolving, Object ifNotPresent)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         }
AsIterator(ConstantGroup self, int start, int end)85         AsIterator(ConstantGroup self, int start, int end) {
86             this(self, start, end, true, null);
87         }
AsIterator(ConstantGroup self, int start, int end, Object ifNotPresent)88         AsIterator(ConstantGroup self, int start, int end,
89                  Object ifNotPresent) {
90             this(self, start, end, false, ifNotPresent);
91         }
92 
93         @Override
hasNext()94         public boolean hasNext() {
95             return index < end;
96         }
97 
98         @Override
next()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 
bumpIndex()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
SubGroup(ConstantGroup self, int start, int end)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 
mapIndex(int index)125         private int mapIndex(int index) {
126             return rangeCheck1(index, size) + offset;
127         }
128 
129         @Override
get(int index)130         public Object get(int index) {
131             return self.get(mapIndex(index));
132         }
133 
134         @Override
get(int index, Object ifNotPresent)135         public Object get(int index, Object ifNotPresent) {
136             return self.get(mapIndex(index), ifNotPresent);
137         }
138 
139         @Override
isPresent(int index)140         public boolean isPresent(int index) {
141             return self.isPresent(mapIndex(index));
142         }
143 
144         @Override
subGroup(int start, int end)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
asList()151         public List<Object> asList() {
152             return new AsList(self, offset, offset + size);
153         }
154 
155         @Override
asList(Object ifNotPresent)156         public List<Object> asList(Object ifNotPresent) {
157             return new AsList(self, offset, offset + size, ifNotPresent);
158         }
159 
160         @Override
copyConstants(int start, int end, Object[] buf, int pos)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
copyConstants(int start, int end, Object[] buf, int pos, Object ifNotPresent)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 
AsList(ConstantGroup self, int start, int end, boolean resolving, Object ifNotPresent)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         }
AsList(ConstantGroup self, int start, int end)194         AsList(ConstantGroup self, int start, int end) {
195             this(self, start, end, true, null);
196         }
AsList(ConstantGroup self, int start, int end, Object ifNotPresent)197         AsList(ConstantGroup self, int start, int end,
198                Object ifNotPresent) {
199             this(self, start, end, false, ifNotPresent);
200         }
201 
mapIndex(int index)202         private int mapIndex(int index) {
203             return rangeCheck1(index, size) + offset;
204         }
205 
size()206         @Override public final int size() {
207             return size;
208         }
209 
get(int index)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
iterator()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 
subList(int start, int end)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 
toArray()231         @Override public Object[] toArray() {
232             return toArray(new Object[size]);
233         }
toArray(T[] a)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 
WithCache(int size)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 
initializeCache(List<Object> cacheContents, Object ifNotPresent)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 
get(int i)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 
get(int i, Object ifNotAvailable)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
isPresent(int i)290         public boolean isPresent(int i) {
291             return cache[i] != null;
292         }
293 
294         /** hook for local subclasses */
fillCache(int i)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 
wrapNull(Object x)301         static Object wrapNull(Object x) {
302             return x == null ? RESOLVED_TO_NULL : x;
303         }
304 
unwrapNull(Object x)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 
toString()325         @Override public String toString() {
326             return bsm+"/"+name+":"+type+super.toString();
327         }
328 
BSCIWithCache(MethodHandle bsm, String name, T type, int size)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 
bootstrapMethod()337         @Override public MethodHandle bootstrapMethod() { return bsm; }
invocationName()338         @Override public String invocationName() { return name; }
invocationType()339         @Override public T invocationType() { return type; }
340     }
341 }
342