|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.lang.invoke; |
|
|
|
import java.util.*; |
|
import jdk.internal.vm.annotation.Stable; |
|
|
|
import static java.lang.invoke.MethodHandleStatics.rangeCheck1; |
|
import static java.lang.invoke.MethodHandleStatics.rangeCheck2; |
|
|
|
/** Utility class for implementing ConstantGroup. */ |
|
|
|
abstract class AbstractConstantGroup implements ConstantGroup { |
|
|
|
protected final int size; |
|
|
|
|
|
|
|
*/ |
|
AbstractConstantGroup(int size) { |
|
this.size = size; |
|
} |
|
|
|
@Override public final int size() { |
|
return size; |
|
} |
|
|
|
public abstract Object get(int index) throws LinkageError; |
|
|
|
public abstract Object get(int index, Object ifNotPresent); |
|
|
|
public abstract boolean isPresent(int index); |
|
|
|
// Do not override equals or hashCode, since this type is stateful. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override public String toString() { |
|
return asList("*").toString(); |
|
} |
|
|
|
static class AsIterator implements Iterator<Object> { |
|
private final ConstantGroup self; |
|
private final int end; |
|
private final boolean resolving; |
|
private final Object ifNotPresent; |
|
|
|
|
|
private int index; |
|
|
|
private AsIterator(ConstantGroup self, int start, int end, |
|
boolean resolving, Object ifNotPresent) { |
|
this.self = self; |
|
this.end = end; |
|
this.index = start; |
|
this.resolving = resolving; |
|
this.ifNotPresent = ifNotPresent; |
|
} |
|
AsIterator(ConstantGroup self, int start, int end) { |
|
this(self, start, end, true, null); |
|
} |
|
AsIterator(ConstantGroup self, int start, int end, |
|
Object ifNotPresent) { |
|
this(self, start, end, false, ifNotPresent); |
|
} |
|
|
|
@Override |
|
public boolean hasNext() { |
|
return index < end; |
|
} |
|
|
|
@Override |
|
public Object next() { |
|
int i = bumpIndex(); |
|
if (resolving) |
|
return self.get(i); |
|
else |
|
return self.get(i, ifNotPresent); |
|
} |
|
|
|
private int bumpIndex() { |
|
int i = index; |
|
if (i >= end) throw new NoSuchElementException(); |
|
index = i+1; |
|
return i; |
|
} |
|
} |
|
|
|
static class SubGroup extends AbstractConstantGroup { |
|
private final ConstantGroup self; |
|
private final int offset; |
|
SubGroup(ConstantGroup self, int start, int end) { |
|
super(end - start); |
|
this.self = self; |
|
this.offset = start; |
|
rangeCheck2(start, end, size); |
|
} |
|
|
|
private int mapIndex(int index) { |
|
return rangeCheck1(index, size) + offset; |
|
} |
|
|
|
@Override |
|
public Object get(int index) { |
|
return self.get(mapIndex(index)); |
|
} |
|
|
|
@Override |
|
public Object get(int index, Object ifNotPresent) { |
|
return self.get(mapIndex(index), ifNotPresent); |
|
} |
|
|
|
@Override |
|
public boolean isPresent(int index) { |
|
return self.isPresent(mapIndex(index)); |
|
} |
|
|
|
@Override |
|
public ConstantGroup subGroup(int start, int end) { |
|
rangeCheck2(start, end, size); |
|
return new SubGroup(self, offset + start, offset + end); |
|
} |
|
|
|
@Override |
|
public List<Object> asList() { |
|
return new AsList(self, offset, offset + size); |
|
} |
|
|
|
@Override |
|
public List<Object> asList(Object ifNotPresent) { |
|
return new AsList(self, offset, offset + size, ifNotPresent); |
|
} |
|
|
|
@Override |
|
public int copyConstants(int start, int end, |
|
Object[] buf, int pos) throws LinkageError { |
|
rangeCheck2(start, end, size); |
|
return self.copyConstants(offset + start, offset + end, |
|
buf, pos); |
|
} |
|
|
|
@Override |
|
public int copyConstants(int start, int end, |
|
Object[] buf, int pos, |
|
Object ifNotPresent) { |
|
rangeCheck2(start, end, size); |
|
return self.copyConstants(offset + start, offset + end, |
|
buf, pos, ifNotPresent); |
|
} |
|
} |
|
|
|
static class AsList extends AbstractList<Object> { |
|
private final ConstantGroup self; |
|
private final int size; |
|
private final int offset; |
|
private final boolean resolving; |
|
private final Object ifNotPresent; |
|
|
|
private AsList(ConstantGroup self, int start, int end, |
|
boolean resolving, Object ifNotPresent) { |
|
this.self = self; |
|
this.size = end - start; |
|
this.offset = start; |
|
this.resolving = resolving; |
|
this.ifNotPresent = ifNotPresent; |
|
rangeCheck2(start, end, self.size()); |
|
} |
|
AsList(ConstantGroup self, int start, int end) { |
|
this(self, start, end, true, null); |
|
} |
|
AsList(ConstantGroup self, int start, int end, |
|
Object ifNotPresent) { |
|
this(self, start, end, false, ifNotPresent); |
|
} |
|
|
|
private int mapIndex(int index) { |
|
return rangeCheck1(index, size) + offset; |
|
} |
|
|
|
@Override public final int size() { |
|
return size; |
|
} |
|
|
|
@Override public Object get(int index) { |
|
if (resolving) |
|
return self.get(mapIndex(index)); |
|
else |
|
return self.get(mapIndex(index), ifNotPresent); |
|
} |
|
|
|
@Override |
|
public Iterator<Object> iterator() { |
|
if (resolving) |
|
return new AsIterator(self, offset, offset + size); |
|
else |
|
return new AsIterator(self, offset, offset + size, ifNotPresent); |
|
} |
|
|
|
@Override public List<Object> subList(int start, int end) { |
|
rangeCheck2(start, end, size); |
|
return new AsList(self, offset + start, offset + end, |
|
resolving, ifNotPresent); |
|
} |
|
|
|
@Override public Object[] toArray() { |
|
return toArray(new Object[size]); |
|
} |
|
@Override public <T> T[] toArray(T[] a) { |
|
int pad = a.length - size; |
|
if (pad < 0) { |
|
pad = 0; |
|
a = Arrays.copyOf(a, size); |
|
} |
|
if (resolving) |
|
self.copyConstants(offset, offset + size, a, 0); |
|
else |
|
self.copyConstants(offset, offset + size, a, 0, |
|
ifNotPresent); |
|
if (pad > 0) a[size] = null; |
|
return a; |
|
} |
|
} |
|
|
|
static abstract |
|
class WithCache extends AbstractConstantGroup { |
|
@Stable final Object[] cache; |
|
|
|
WithCache(int size) { |
|
super(size); |
|
// It is caller's responsibility to initialize the cache. |
|
|
|
cache = new Object[size]; |
|
} |
|
|
|
void initializeCache(List<Object> cacheContents, Object ifNotPresent) { |
|
// Replace ifNotPresent with NOT_PRESENT, |
|
// and null with RESOLVED_TO_NULL. |
|
|
|
for (int i = 0; i < cache.length; i++) { |
|
Object x = cacheContents.get(i); |
|
if (x == ifNotPresent) |
|
continue; |
|
if (x == null) |
|
x = RESOLVED_TO_NULL; |
|
cache[i] = x; |
|
} |
|
} |
|
|
|
@Override public Object get(int i) { |
|
Object x = cache[i]; |
|
|
|
if (x == null) x = fillCache(i); |
|
return unwrapNull(x); |
|
} |
|
|
|
@Override public Object get(int i, Object ifNotAvailable) { |
|
Object x = cache[i]; |
|
|
|
if (x == null) return ifNotAvailable; |
|
return unwrapNull(x); |
|
} |
|
|
|
@Override |
|
public boolean isPresent(int i) { |
|
return cache[i] != null; |
|
} |
|
|
|
|
|
Object fillCache(int i) { |
|
throw new NoSuchElementException("constant group does not contain element #"+i); |
|
} |
|
|
|
/// routines for mapping between null sentinel and true resolved null |
|
|
|
static Object wrapNull(Object x) { |
|
return x == null ? RESOLVED_TO_NULL : x; |
|
} |
|
|
|
static Object unwrapNull(Object x) { |
|
assert(x != null); |
|
return x == RESOLVED_TO_NULL ? null : x; |
|
} |
|
|
|
|
|
static final Object RESOLVED_TO_NULL = new Object(); |
|
|
|
|
|
static final Object NOT_PRESENT = new Object(); |
|
|
|
} |
|
|
|
|
|
static |
|
class BSCIWithCache<T> extends WithCache implements BootstrapCallInfo<T> { |
|
private final MethodHandle bsm; |
|
private final String name; |
|
private final T type; |
|
|
|
@Override public String toString() { |
|
return bsm+"/"+name+":"+type+super.toString(); |
|
} |
|
|
|
BSCIWithCache(MethodHandle bsm, String name, T type, int size) { |
|
super(size); |
|
this.type = type; |
|
this.bsm = bsm; |
|
this.name = name; |
|
assert(type instanceof Class || type instanceof MethodType); |
|
} |
|
|
|
@Override public MethodHandle bootstrapMethod() { return bsm; } |
|
@Override public String invocationName() { return name; } |
|
@Override public T invocationType() { return type; } |
|
} |
|
} |