package java.lang.invoke;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.ValueConversions;
import java.util.ArrayList;
import java.util.List;
import static java.lang.invoke.LambdaForm.BasicType;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.LambdaForm.BasicType.V_TYPE_NUM;
import static java.lang.invoke.LambdaForm.BasicType.V_TYPE_NUM;
import static java.lang.invoke.LambdaForm.BasicType.V_TYPE_NUM;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.newInternalError;
import static java.lang.invoke.MethodHandleStatics.uncaughtException;
abstract class BoundMethodHandle extends MethodHandle {
BoundMethodHandle(MethodType type, LambdaForm form) {
super(type, form);
assert(speciesData() == speciesDataFor(form));
}
static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
try {
switch (xtype) {
case L_TYPE:
return bindSingle(type, form, x);
case I_TYPE:
return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(I_TYPE_NUM).factory().invokeBasic(type, form, ValueConversions.widenSubword(x));
case J_TYPE:
return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(J_TYPE_NUM).factory().invokeBasic(type, form, (long) x);
case F_TYPE:
return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(F_TYPE_NUM).factory().invokeBasic(type, form, (float) x);
case D_TYPE:
return (BoundMethodHandle) SPECIALIZER.topSpecies().extendWith(D_TYPE_NUM).factory().invokeBasic(type, form, (double) x);
default : throw newInternalError("unexpected xtype: " + xtype);
}
} catch (Throwable t) {
throw uncaughtException(t);
}
}
LambdaFormEditor editor() {
return form.editor();
}
static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
return Species_L.make(type, form, x);
}
@Override
BoundMethodHandle bindArgumentL(int pos, Object value) {
return editor().bindArgumentL(this, pos, value);
}
BoundMethodHandle bindArgumentI(int pos, int value) {
return editor().bindArgumentI(this, pos, value);
}
BoundMethodHandle bindArgumentJ(int pos, long value) {
return editor().bindArgumentJ(this, pos, value);
}
BoundMethodHandle bindArgumentF(int pos, float value) {
return editor().bindArgumentF(this, pos, value);
}
BoundMethodHandle bindArgumentD(int pos, double value) {
return editor().bindArgumentD(this, pos, value);
}
@Override
BoundMethodHandle rebind() {
if (!tooComplex()) {
return this;
}
return makeReinvoker(this);
}
private boolean tooComplex() {
return (fieldCount() > FIELD_COUNT_THRESHOLD ||
form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
}
private static final int FIELD_COUNT_THRESHOLD = 12;
private static final int FORM_EXPRESSION_THRESHOLD = 24;
static BoundMethodHandle makeReinvoker(MethodHandle target) {
LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
target, MethodTypeForm.LF_REBIND,
Species_L.BMH_SPECIES, Species_L.BMH_SPECIES.getterFunction(0));
return Species_L.make(target.type(), form, target);
}
abstract BoundMethodHandle.SpeciesData speciesData();
static BoundMethodHandle.SpeciesData speciesDataFor(LambdaForm form) {
Object c = form.names[0].constraint;
if (c instanceof SpeciesData) {
return (SpeciesData) c;
}
return SPECIALIZER.topSpecies();
}
final int fieldCount() { return speciesData().fieldCount(); }
@Override
Object internalProperties() {
return "\n& BMH="+internalValues();
}
@Override
final String internalValues() {
int count = fieldCount();
if (count == 1) {
return "[" + arg(0) + "]";
}
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < count; ++i) {
sb.append("\n ").append(i).append(": ( ").append(arg(i)).append(" )");
}
return sb.append("\n]").toString();
}
final Object arg(int i) {
try {
Class<?> fieldType = speciesData().fieldTypes().get(i);
switch (BasicType.basicType(fieldType)) {
case L_TYPE: return speciesData().getter(i).invokeBasic(this);
case I_TYPE: return (int) speciesData().getter(i).invokeBasic(this);
case J_TYPE: return (long) speciesData().getter(i).invokeBasic(this);
case F_TYPE: return (float) speciesData().getter(i).invokeBasic(this);
case D_TYPE: return (double) speciesData().getter(i).invokeBasic(this);
}
} catch (Throwable ex) {
throw uncaughtException(ex);
}
throw new InternalError("unexpected type: " + speciesData().key()+"."+i);
}
abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg);
abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg);
abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg);
abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
private
static final class Species_L extends BoundMethodHandle {
final Object argL0;
private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
super(mt, lf);
this.argL0 = argL0;
}
@Override
SpeciesData speciesData() {
return BMH_SPECIES;
}
static @Stable SpeciesData BMH_SPECIES;
static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
return new Species_L(mt, lf, argL0);
}
@Override
final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Species_L(mt, lf, argL0);
}
@Override
final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
try {
return (BoundMethodHandle) BMH_SPECIES.extendWith(L_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
}
@Override
final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
try {
return (BoundMethodHandle) BMH_SPECIES.extendWith(I_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
}
@Override
final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
try {
return (BoundMethodHandle) BMH_SPECIES.extendWith(J_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
}
@Override
final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
try {
return (BoundMethodHandle) BMH_SPECIES.extendWith(F_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
}
@Override
final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
try {
return (BoundMethodHandle) BMH_SPECIES.extendWith(D_TYPE_NUM).factory().invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
}
}
static final class SpeciesData extends ClassSpecializer<BoundMethodHandle, String, SpeciesData>.SpeciesData {
@Stable final private SpeciesData[] extensions = new SpeciesData[ARG_TYPE_LIMIT];
public SpeciesData(Specializer outer, String key) {
outer.super(key);
}
@Override
protected String deriveClassName() {
String typeString = deriveTypeString();
if (typeString.isEmpty()) {
return SimpleMethodHandle.class.getName();
}
return BoundMethodHandle.class.getName() + "$Species_" + typeString;
}
@Override
protected List<Class<?>> deriveFieldTypes(String key) {
ArrayList<Class<?>> types = new ArrayList<>(key.length());
for (int i = 0; i < key.length(); i++) {
types.add(basicType(key.charAt(i)).basicTypeClass());
}
return types;
}
@Override
protected String deriveTypeString() {
return key();
}
@Override
protected MethodHandle deriveTransformHelper(MemberName transform, int whichtm) {
if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
return factory();
} else if (whichtm < ARG_TYPE_LIMIT) {
return extendWith((byte) whichtm).factory();
} else {
throw newInternalError("bad transform");
}
}
@Override
protected <X> List<X> deriveTransformHelperArguments(MemberName transform, int whichtm, List<X> args, List<X> fields) {
assert(verifyTHAargs(transform, whichtm, args, fields));
args.addAll(2, fields);
return args;
}
private boolean verifyTHAargs(MemberName transform, int whichtm, List<?> args, List<?> fields) {
assert(transform == Specializer.BMH_TRANSFORMS.get(whichtm));
assert(args.size() == transform.getMethodType().parameterCount());
assert(fields.size() == this.fieldCount());
final int MH_AND_LF = 2;
if (whichtm == Specializer.TN_COPY_NO_EXTEND) {
assert(transform.getMethodType().parameterCount() == MH_AND_LF);
} else if (whichtm < ARG_TYPE_LIMIT) {
assert(transform.getMethodType().parameterCount() == MH_AND_LF+1);
final BasicType type = basicType((byte) whichtm);
assert(transform.getParameterTypes()[MH_AND_LF] == type.basicTypeClass());
} else {
return false;
}
return true;
}
SpeciesData extendWith(byte typeNum) {
SpeciesData sd = extensions[typeNum];
if (sd != null) return sd;
sd = SPECIALIZER.findSpecies(key() + BasicType.basicType(typeNum).basicTypeChar());
extensions[typeNum] = sd;
return sd;
}
}
static final Specializer SPECIALIZER = new Specializer();
static {
SimpleMethodHandle.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("");
Species_L.BMH_SPECIES = BoundMethodHandle.SPECIALIZER.findSpecies("L");
}
static final class Specializer extends ClassSpecializer<BoundMethodHandle, String, SpeciesData> {
private static final MemberName SPECIES_DATA_ACCESSOR;
static {
try {
SPECIES_DATA_ACCESSOR = IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BoundMethodHandle.class,
"speciesData", MethodType.methodType(BoundMethodHandle.SpeciesData.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError("Bootstrap link error", ex);
}
}
private Specializer() {
super(
BoundMethodHandle.class, String.class, BoundMethodHandle.SpeciesData.class,
MethodType.methodType(void.class, MethodType.class, LambdaForm.class),
SPECIES_DATA_ACCESSOR,
"BMH_SPECIES",
BMH_TRANSFORMS);
}
@Override
protected String topSpeciesKey() {
return "";
}
@Override
protected BoundMethodHandle.SpeciesData newSpeciesData(String key) {
return new BoundMethodHandle.SpeciesData(this, key);
}
static final List<MemberName> BMH_TRANSFORMS;
static final int TN_COPY_NO_EXTEND = V_TYPE_NUM;
static {
final Class<BoundMethodHandle> BMH = BoundMethodHandle.class;
try {
BMH_TRANSFORMS = List.of(
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendL", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, Object.class)),
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendI", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, int.class)),
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendJ", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, long.class)),
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendF", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, float.class)),
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWithExtendD", MethodType.methodType(BMH, MethodType.class, LambdaForm.class, double.class)),
IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, BMH, "copyWith", MethodType.methodType(BMH, MethodType.class, LambdaForm.class))
);
} catch (ReflectiveOperationException ex) {
throw newInternalError("Failed resolving copyWith methods", ex);
}
assert(BMH_TRANSFORMS.size() == TYPE_LIMIT);
}
class Factory extends ClassSpecializer<BoundMethodHandle, String, BoundMethodHandle.SpeciesData>.Factory {
@Override
protected String chooseFieldName(Class<?> type, int index) {
return "arg" + super.chooseFieldName(type, index);
}
}
@Override
protected Factory makeFactory() {
return new Factory();
}
}
static SpeciesData speciesData_L() { return Species_L.BMH_SPECIES; }
static SpeciesData speciesData_LL() { return SPECIALIZER.findSpecies("LL"); }
static SpeciesData speciesData_LLL() { return SPECIALIZER.findSpecies("LLL"); }
static SpeciesData speciesData_LLLL() { return SPECIALIZER.findSpecies("LLLL"); }
static SpeciesData speciesData_LLLLL() { return SPECIALIZER.findSpecies("LLLLL"); }
}