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