提交 237bbe7d 编写于 作者: V vlivanov

8037210: Get rid of char-based descriptions 'J' of basic types

Reviewed-by: jrose, psandoz, twisti
上级 6aadd150
...@@ -26,11 +26,10 @@ ...@@ -26,11 +26,10 @@
package java.lang.invoke; package java.lang.invoke;
import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static java.lang.invoke.LambdaForm.basicTypes; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic; import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import java.lang.invoke.LambdaForm.Name;
import java.lang.invoke.LambdaForm.NamedFunction; import java.lang.invoke.LambdaForm.NamedFunction;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Field; import java.lang.reflect.Field;
...@@ -61,22 +60,22 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -61,22 +60,22 @@ import jdk.internal.org.objectweb.asm.Type;
// BMH API and internals // BMH API and internals
// //
static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) { static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
// for some type signatures, there exist pre-defined concrete BMH classes // for some type signatures, there exist pre-defined concrete BMH classes
try { try {
switch (xtype) { switch (xtype) {
case 'L': case L_TYPE:
if (true) return bindSingle(type, form, x); // Use known fast path. if (true) return bindSingle(type, form, x); // Use known fast path.
return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor[0].invokeBasic(type, form, x);
case 'I': case I_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x)); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
case 'J': case J_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor[0].invokeBasic(type, form, (long) x);
case 'F': case F_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor[0].invokeBasic(type, form, (float) x);
case 'D': case D_TYPE:
return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x); return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor[0].invokeBasic(type, form, (double) x);
default : throw new InternalError("unexpected xtype: " + xtype); default : throw newInternalError("unexpected xtype: " + xtype);
} }
} catch (Throwable t) { } catch (Throwable t) {
throw newInternalError(t); throw newInternalError(t);
...@@ -87,23 +86,23 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -87,23 +86,23 @@ import jdk.internal.org.objectweb.asm.Type;
return new Species_L(type, form, x); return new Species_L(type, form, x);
} }
MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) { MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) {
try { try {
switch (xtype) { switch (xtype) {
case 'L': return cloneExtendL(type, form, x); case L_TYPE: return copyWithExtendL(type, form, x);
case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x)); case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x));
case 'J': return cloneExtendJ(type, form, (long) x); case J_TYPE: return copyWithExtendJ(type, form, (long) x);
case 'F': return cloneExtendF(type, form, (float) x); case F_TYPE: return copyWithExtendF(type, form, (float) x);
case 'D': return cloneExtendD(type, form, (double) x); case D_TYPE: return copyWithExtendD(type, form, (double) x);
} }
} catch (Throwable t) { } catch (Throwable t) {
throw newInternalError(t); throw newInternalError(t);
} }
throw new InternalError("unexpected type: " + xtype); throw newInternalError("unexpected type: " + xtype);
} }
@Override @Override
MethodHandle bindArgument(int pos, char basicType, Object value) { MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
MethodType type = type().dropParameterTypes(pos, pos+1); MethodType type = type().dropParameterTypes(pos, pos+1);
LambdaForm form = internalForm().bind(1+pos, speciesData()); LambdaForm form = internalForm().bind(1+pos, speciesData());
return cloneExtend(type, form, basicType, value); return cloneExtend(type, form, basicType, value);
...@@ -111,9 +110,9 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -111,9 +110,9 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
MethodHandle dropArguments(MethodType srcType, int pos, int drops) { MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops)); LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops));
try { try {
return clone(srcType, form); return copyWith(srcType, form);
} catch (Throwable t) { } catch (Throwable t) {
throw newInternalError(t); throw newInternalError(t);
} }
...@@ -122,26 +121,23 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -122,26 +121,23 @@ import jdk.internal.org.objectweb.asm.Type;
@Override @Override
MethodHandle permuteArguments(MethodType newType, int[] reorder) { MethodHandle permuteArguments(MethodType newType, int[] reorder) {
try { try {
return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList()))); return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
} catch (Throwable t) { } catch (Throwable t) {
throw newInternalError(t); throw newInternalError(t);
} }
} }
static final String EXTENSION_TYPES = "LIJFD";
static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
static byte extensionIndex(char type) {
int i = EXTENSION_TYPES.indexOf(type);
if (i < 0) throw new InternalError();
return (byte) i;
}
/** /**
* Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
* static field containing this value, and they must accordingly implement this method. * static field containing this value, and they must accordingly implement this method.
*/ */
/*non-public*/ abstract SpeciesData speciesData(); /*non-public*/ abstract SpeciesData speciesData();
/**
* Return the number of fields in this BMH. Equivalent to speciesData().fieldCount().
*/
/*non-public*/ abstract int fieldCount();
@Override @Override
final Object internalProperties() { final Object internalProperties() {
return "/BMH="+internalValues(); return "/BMH="+internalValues();
...@@ -159,38 +155,33 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -159,38 +155,33 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/ final Object arg(int i) { /*non-public*/ final Object arg(int i) {
try { try {
switch (speciesData().fieldType(i)) { switch (speciesData().fieldType(i)) {
case 'L': return argL(i); case L_TYPE: return speciesData().getters[i].invokeBasic(this);
case 'I': return argI(i); case I_TYPE: return (int) speciesData().getters[i].invokeBasic(this);
case 'F': return argF(i); case J_TYPE: return (long) speciesData().getters[i].invokeBasic(this);
case 'D': return argD(i); case F_TYPE: return (float) speciesData().getters[i].invokeBasic(this);
case 'J': return argJ(i); case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
} }
} catch (Throwable ex) { } catch (Throwable ex) {
throw newInternalError(ex); throw newInternalError(ex);
} }
throw new InternalError("unexpected type: " + speciesData().types+"."+i); throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
} }
/*non-public*/ final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); }
/*non-public*/ final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); }
/*non-public*/ final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); }
/*non-public*/ final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
/*non-public*/ final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); }
// //
// cloning API // cloning API
// //
/*non-public*/ abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
/*non-public*/ abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
/*non-public*/ abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg);
/*non-public*/ abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg);
/*non-public*/ abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg);
/*non-public*/ abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable; /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
// The following is a grossly irregular hack: // The following is a grossly irregular hack:
@Override MethodHandle reinvokerTarget() { @Override MethodHandle reinvokerTarget() {
try { try {
return (MethodHandle) argL(0); return (MethodHandle) arg(0);
} catch (Throwable ex) { } catch (Throwable ex) {
throw newInternalError(ex); throw newInternalError(ex);
} }
...@@ -203,7 +194,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -203,7 +194,7 @@ import jdk.internal.org.objectweb.asm.Type;
private // make it private to force users to access the enclosing class first private // make it private to force users to access the enclosing class first
static final class Species_L extends BoundMethodHandle { static final class Species_L extends BoundMethodHandle {
final Object argL0; final Object argL0;
/*non-public*/ Species_L(MethodType mt, LambdaForm lf, Object argL0) { private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
super(mt, lf); super(mt, lf);
this.argL0 = argL0; this.argL0 = argL0;
} }
...@@ -213,140 +204,95 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -213,140 +204,95 @@ import jdk.internal.org.objectweb.asm.Type;
/*non-public*/ SpeciesData speciesData() { /*non-public*/ SpeciesData speciesData() {
return SPECIES_DATA; return SPECIES_DATA;
} }
/*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
@Override
/*non-public*/ final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
return new Species_L(mt, lf, argL0);
}
@Override
/*non-public*/ final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
}
@Override @Override
/*non-public*/ final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable { /*non-public*/ int fieldCount() {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg); return 1;
}
@Override
/*non-public*/ final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
}
@Override
/*non-public*/ final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
}
@Override
/*non-public*/ final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
}
}
/*
static final class Species_LL extends BoundMethodHandle {
final Object argL0;
final Object argL1;
public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
super(mt, lf);
this.argL0 = argL0;
this.argL1 = argL1;
}
@Override
public SpeciesData speciesData() {
return SPECIES_DATA;
}
public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
@Override
public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
return new Species_LL(mt, lf, argL0, argL1);
}
@Override
public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
@Override
public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
}
}
static final class Species_JL extends BoundMethodHandle {
final long argJ0;
final Object argL1;
public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
super(mt, lf);
this.argJ0 = argJ0;
this.argL1 = argL1;
} }
@Override /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
public SpeciesData speciesData() { /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
return SPECIES_DATA; return new Species_L(mt, lf, argL0);
} }
public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
@Override public final long argJ0() { return argJ0; }
@Override public final Object argL1() { return argL1; }
@Override @Override
public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable { /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new Species_JL(mt, lf, argJ0, argL1); return new Species_L(mt, lf, argL0);
} }
@Override @Override
public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable { /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg); try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
} }
@Override @Override
public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable { /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg); try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
} }
@Override @Override
public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable { /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg); try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
} }
@Override @Override
public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable { /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg); try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
} }
@Override @Override
public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable { /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg); try {
return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, narg);
} catch (Throwable ex) {
throw uncaughtException(ex);
}
} }
} }
*/
// //
// BMH species meta-data // BMH species meta-data
// //
/** /**
* Meta-data wrapper for concrete BMH classes. * Meta-data wrapper for concrete BMH types.
* Each BMH type corresponds to a given sequence of basic field types (LIJFD).
* The fields are immutable; their values are fully specified at object construction.
* Each BMH type supplies an array of getter functions which may be used in lambda forms.
* A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
* As a degenerate and common case, the "shorter BMH" can be missing, and contributes zero prior fields.
*/ */
static class SpeciesData { static class SpeciesData {
final String types; final String typeChars;
final BasicType[] typeCodes;
final Class<? extends BoundMethodHandle> clazz; final Class<? extends BoundMethodHandle> clazz;
// Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
// Therefore, we need a non-final link in the chain. Use array elements. // Therefore, we need a non-final link in the chain. Use array elements.
final MethodHandle[] constructor; final MethodHandle[] constructor;
final MethodHandle[] getters; final MethodHandle[] getters;
final NamedFunction[] nominalGetters;
final SpeciesData[] extensions; final SpeciesData[] extensions;
/*non-public*/ int fieldCount() { /*non-public*/ int fieldCount() {
return types.length(); return typeCodes.length;
}
/*non-public*/ BasicType fieldType(int i) {
return typeCodes[i];
} }
/*non-public*/ char fieldType(int i) { /*non-public*/ char fieldTypeChar(int i) {
return types.charAt(i); return typeChars.charAt(i);
} }
public String toString() { public String toString() {
return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]"; return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+typeChars+"]";
} }
/** /**
...@@ -354,45 +300,46 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -354,45 +300,46 @@ import jdk.internal.org.objectweb.asm.Type;
* represents a MH bound to a generic invoker, which in turn forwards to the corresponding * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
* getter. * getter.
*/ */
Name getterName(Name mhName, int i) {
MethodHandle mh = getters[i];
assert(mh != null) : this+"."+i;
return new Name(mh, mhName);
}
NamedFunction getterFunction(int i) { NamedFunction getterFunction(int i) {
return new NamedFunction(getters[i]); return nominalGetters[i];
} }
static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class); static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) { private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
this.types = types; this.typeChars = types;
this.typeCodes = basicTypes(types);
this.clazz = clazz; this.clazz = clazz;
if (!INIT_DONE) { if (!INIT_DONE) {
this.constructor = new MethodHandle[1]; this.constructor = new MethodHandle[1]; // only one ctor
this.getters = new MethodHandle[types.length()]; this.getters = new MethodHandle[types.length()];
this.nominalGetters = new NamedFunction[types.length()];
} else { } else {
this.constructor = Factory.makeCtors(clazz, types, null); this.constructor = Factory.makeCtors(clazz, types, null);
this.getters = Factory.makeGetters(clazz, types, null); this.getters = Factory.makeGetters(clazz, types, null);
this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
} }
this.extensions = new SpeciesData[EXTENSION_TYPES.length()]; this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
} }
private void initForBootstrap() { private void initForBootstrap() {
assert(!INIT_DONE); assert(!INIT_DONE);
if (constructor[0] == null) { if (constructor[0] == null) {
String types = typeChars;
Factory.makeCtors(clazz, types, this.constructor); Factory.makeCtors(clazz, types, this.constructor);
Factory.makeGetters(clazz, types, this.getters); Factory.makeGetters(clazz, types, this.getters);
Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
} }
} }
private SpeciesData(String types) { private SpeciesData(String typeChars) {
// Placeholder only. // Placeholder only.
this.types = types; this.typeChars = typeChars;
this.typeCodes = basicTypes(typeChars);
this.clazz = null; this.clazz = null;
this.constructor = null; this.constructor = null;
this.getters = null; this.getters = null;
this.nominalGetters = null;
this.extensions = null; this.extensions = null;
} }
private boolean isPlaceholder() { return clazz == null; } private boolean isPlaceholder() { return clazz == null; }
...@@ -401,18 +348,15 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -401,18 +348,15 @@ import jdk.internal.org.objectweb.asm.Type;
static { CACHE.put("", EMPTY); } // make bootstrap predictable static { CACHE.put("", EMPTY); } // make bootstrap predictable
private static final boolean INIT_DONE; // set after <clinit> finishes... private static final boolean INIT_DONE; // set after <clinit> finishes...
SpeciesData extendWithType(char type) { SpeciesData extendWith(byte type) {
int i = extensionIndex(type); return extendWith(BasicType.basicType(type));
SpeciesData d = extensions[i];
if (d != null) return d;
extensions[i] = d = get(types+type);
return d;
} }
SpeciesData extendWithIndex(byte index) { SpeciesData extendWith(BasicType type) {
SpeciesData d = extensions[index]; int ord = type.ordinal();
SpeciesData d = extensions[ord];
if (d != null) return d; if (d != null) return d;
extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index)); extensions[ord] = d = get(typeChars+type.basicTypeChar());
return d; return d;
} }
...@@ -456,8 +400,6 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -456,8 +400,6 @@ import jdk.internal.org.objectweb.asm.Type;
static { static {
// pre-fill the BMH speciesdata cache with BMH's inner classes // pre-fill the BMH speciesdata cache with BMH's inner classes
final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class; final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
SpeciesData d0 = BoundMethodHandle.SPECIES_DATA; // trigger class init
assert(d0 == null || d0 == lookupCache("")) : d0;
try { try {
for (Class<?> c : rootCls.getDeclaredClasses()) { for (Class<?> c : rootCls.getDeclaredClasses()) {
if (rootCls.isAssignableFrom(c)) { if (rootCls.isAssignableFrom(c)) {
...@@ -465,7 +407,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -465,7 +407,7 @@ import jdk.internal.org.objectweb.asm.Type;
SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh); SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
assert(d != null) : cbmh.getName(); assert(d != null) : cbmh.getName();
assert(d.clazz == cbmh); assert(d.clazz == cbmh);
assert(d == lookupCache(d.types)); assert(d == lookupCache(d.typeChars));
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
...@@ -516,11 +458,10 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -516,11 +458,10 @@ import jdk.internal.org.objectweb.asm.Type;
static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG; static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG; static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
static final String VOID_SIG = "()V"; static final String VOID_SIG = "()V";
static final String INT_SIG = "()I";
static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;"; static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" }; static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
/** /**
...@@ -551,31 +492,35 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -551,31 +492,35 @@ import jdk.internal.org.objectweb.asm.Type;
* final Object argL0; * final Object argL0;
* final Object argL1; * final Object argL1;
* final int argI2; * final int argI2;
* Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) { * private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
* super(mt, lf); * super(mt, lf);
* this.argL0 = argL0; * this.argL0 = argL0;
* this.argL1 = argL1; * this.argL1 = argL1;
* this.argI2 = argI2; * this.argI2 = argI2;
* } * }
* final SpeciesData speciesData() { return SPECIES_DATA; } * final SpeciesData speciesData() { return SPECIES_DATA; }
* final int fieldCount() { return 3; }
* static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class); * static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
* final BoundMethodHandle clone(MethodType mt, LambdaForm lf) { * static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
* return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2); * return new Species_LLI(mt, lf, argL0, argL1, argI2);
* }
* final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
* return new Species_LLI(mt, lf, argL0, argL1, argI2);
* } * }
* final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) { * final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
* return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(L_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) { * final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
* return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(I_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) { * final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
* return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(J_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) { * final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
* return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(F_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) { * public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
* return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * return SPECIES_DATA.extendWith(D_TYPE).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
* } * }
* } * }
* </pre> * </pre>
...@@ -586,8 +531,9 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -586,8 +531,9 @@ import jdk.internal.org.objectweb.asm.Type;
static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) { static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
final String className = SPECIES_PREFIX_PATH + types; String shortTypes = LambdaForm.shortenSignature(types);
final String sourceFile = SPECIES_PREFIX_NAME + types; final String className = SPECIES_PREFIX_PATH + shortTypes;
final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null); cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
cw.visitSource(sourceFile, null); cw.visitSource(sourceFile, null);
...@@ -606,11 +552,11 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -606,11 +552,11 @@ import jdk.internal.org.objectweb.asm.Type;
MethodVisitor mv; MethodVisitor mv;
// emit constructor // emit constructor
mv = cw.visitMethod(NOT_ACC_PUBLIC, "<init>", makeSignature(types, true), null, null); mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0); // this
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1); // type
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2); // form
mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false); mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
...@@ -647,39 +593,73 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -647,39 +593,73 @@ import jdk.internal.org.objectweb.asm.Type;
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
// emit clone() // emit implementation of fieldCount()
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE); mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
mv.visitCode(); mv.visitCode();
// return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...) int fc = types.length();
// obtain constructor if (fc <= (ICONST_5 - ICONST_0)) {
mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ICONST_0 + fc);
mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG); } else {
mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG); mv.visitIntInsn(SIPUSH, fc);
mv.visitInsn(ICONST_0); }
mv.visitInsn(AALOAD); mv.visitInsn(IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// emit make() ...factory method wrapping constructor
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
mv.visitCode();
// make instance
mv.visitTypeInsn(NEW, className);
mv.visitInsn(DUP);
// load mt, lf
mv.visitVarInsn(ALOAD, 0); // type
mv.visitVarInsn(ALOAD, 1); // form
// load factory method arguments
for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
// i counts the arguments, j counts corresponding argument slots
char t = types.charAt(i);
mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
if (t == 'J' || t == 'D') {
++j; // adjust argument register access
}
}
// finally, invoke the constructor and return
mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// emit copyWith()
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
mv.visitCode();
// make instance
mv.visitTypeInsn(NEW, className);
mv.visitInsn(DUP);
// load mt, lf // load mt, lf
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 2);
// put fields on the stack // put fields on the stack
emitPushFields(types, className, mv); emitPushFields(types, className, mv);
// finally, invoke the constructor and return // finally, invoke the constructor and return
mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false), false); mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
// for each type, emit cloneExtendT() // for each type, emit copyWithExtendT()
for (Class<?> c : TYPES) { for (BasicType type : BasicType.ARG_TYPES) {
char t = Wrapper.basicTypeChar(c); int ord = type.ordinal();
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE); char btChar = type.basicTypeChar();
mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
mv.visitCode(); mv.visitCode();
// return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg) // return SPECIES_DATA.extendWith(t).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
// obtain constructor // obtain constructor
mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG); mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
int iconstInsn = ICONST_0 + extensionIndex(t); int iconstInsn = ICONST_0 + ord;
assert(iconstInsn <= ICONST_5); assert(iconstInsn <= ICONST_5);
mv.visitInsn(iconstInsn); mv.visitInsn(iconstInsn);
mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG, false); mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG); mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
mv.visitInsn(ICONST_0); mv.visitInsn(ICONST_0);
mv.visitInsn(AALOAD); mv.visitInsn(AALOAD);
...@@ -689,9 +669,9 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -689,9 +669,9 @@ import jdk.internal.org.objectweb.asm.Type;
// put fields on the stack // put fields on the stack
emitPushFields(types, className, mv); emitPushFields(types, className, mv);
// put narg on stack // put narg on stack
mv.visitVarInsn(typeLoadOp(t), 3); mv.visitVarInsn(typeLoadOp(btChar), 3);
// finally, invoke the constructor and return // finally, invoke the constructor and return
mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false), false); mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
...@@ -730,7 +710,7 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -730,7 +710,7 @@ import jdk.internal.org.objectweb.asm.Type;
case 'J': return LLOAD; case 'J': return LLOAD;
case 'F': return FLOAD; case 'F': return FLOAD;
case 'D': return DLOAD; case 'D': return DLOAD;
default : throw new InternalError("unrecognized type " + t); default : throw newInternalError("unrecognized type " + t);
} }
} }
...@@ -771,10 +751,19 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -771,10 +751,19 @@ import jdk.internal.org.objectweb.asm.Type;
static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) { static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
if (mhs == null) mhs = new MethodHandle[1]; if (mhs == null) mhs = new MethodHandle[1];
if (types.equals("")) return mhs; // hack for empty BMH species
mhs[0] = makeCbmhCtor(cbmh, types); mhs[0] = makeCbmhCtor(cbmh, types);
return mhs; return mhs;
} }
static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
if (nfs == null) nfs = new NamedFunction[types.length()];
for (int i = 0; i < nfs.length; ++i) {
nfs[i] = new NamedFunction(getters[i]);
}
return nfs;
}
// //
// Auxiliary methods. // Auxiliary methods.
// //
...@@ -808,52 +797,11 @@ import jdk.internal.org.objectweb.asm.Type; ...@@ -808,52 +797,11 @@ import jdk.internal.org.objectweb.asm.Type;
static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) { static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
try { try {
return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null))); return LOOKUP.findStatic(cbmh, "make", MethodType.fromMethodDescriptorString(makeSignature(types, false), null));
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) { } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
throw newInternalError(e); throw newInternalError(e);
} }
} }
/**
* Wrap a constructor call in a {@link LambdaForm}.
*
* If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
* are turned into bytecode, because the call to the allocator is routed through an MH, and the
* verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
* {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
* {@link MethodHandle#linkToSpecial}.
*
* The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
* result of the {@code <init>} invocation. This entry is replaced.
*/
private static MethodHandle linkConstructor(MethodHandle cmh) {
final LambdaForm lf = cmh.form;
final int initNameIndex = lf.names.length - 1;
final Name initName = lf.names[initNameIndex];
final MemberName ctorMN = initName.function.member;
final MethodType ctorMT = ctorMN.getInvocationType();
// obtain function member (call target)
// linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
try {
linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
assert(linkerMN.isStatic());
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
// extend arguments array
Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
newArgs[newArgs.length - 1] = ctorMN;
// replace function
final NamedFunction nf = new NamedFunction(linkerMN);
final Name linkedCtor = new Name(nf, newArgs);
linkedCtor.initIndex(initNameIndex);
lf.names[initNameIndex] = linkedCtor;
return cmh;
}
} }
private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP; private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
......
...@@ -31,6 +31,7 @@ import java.util.Arrays; ...@@ -31,6 +31,7 @@ import java.util.Arrays;
import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyAccess;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodTypeForm.*; import static java.lang.invoke.MethodTypeForm.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
...@@ -124,11 +125,6 @@ class DirectMethodHandle extends MethodHandle { ...@@ -124,11 +125,6 @@ class DirectMethodHandle extends MethodHandle {
return new Constructor(mtype, lform, ctor, init, instanceClass); return new Constructor(mtype, lform, ctor, init, instanceClass);
} }
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new DirectMethodHandle(mt, lf, member);
}
@Override @Override
String internalProperties() { String internalProperties() {
return "/DMH="+member.toString(); return "/DMH="+member.toString();
...@@ -146,9 +142,9 @@ class DirectMethodHandle extends MethodHandle { ...@@ -146,9 +142,9 @@ class DirectMethodHandle extends MethodHandle {
} }
@Override @Override
MethodHandle bindArgument(int pos, char basicType, Object value) { MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
// If the member needs dispatching, do so. // If the member needs dispatching, do so.
if (pos == 0 && basicType == 'L') { if (pos == 0 && basicType == L_TYPE) {
DirectMethodHandle concrete = maybeRebind(value); DirectMethodHandle concrete = maybeRebind(value);
if (concrete != null) if (concrete != null)
return concrete.bindReceiver(value); return concrete.bindReceiver(value);
...@@ -274,7 +270,7 @@ class DirectMethodHandle extends MethodHandle { ...@@ -274,7 +270,7 @@ class DirectMethodHandle extends MethodHandle {
result = NEW_OBJ; result = NEW_OBJ;
} }
names[LINKER_CALL] = new Name(linker, outArgs); names[LINKER_CALL] = new Name(linker, outArgs);
lambdaName += "_" + LambdaForm.basicTypeSignature(mtype); lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result); LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
// This is a tricky bit of code. Don't send it through the LF interpreter. // This is a tricky bit of code. Don't send it through the LF interpreter.
lform.compileToBytecode(); lform.compileToBytecode();
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
package java.lang.invoke; package java.lang.invoke;
import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyAccess;
import java.lang.invoke.LambdaForm.Name; import static java.lang.invoke.LambdaForm.*;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
...@@ -38,6 +38,7 @@ import jdk.internal.org.objectweb.asm.*; ...@@ -38,6 +38,7 @@ import jdk.internal.org.objectweb.asm.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.LambdaForm.BasicType.*;
import sun.invoke.util.VerifyType; import sun.invoke.util.VerifyType;
import sun.reflect.misc.ReflectUtil; import sun.reflect.misc.ReflectUtil;
...@@ -116,7 +117,7 @@ class InvokerBytecodeGenerator { ...@@ -116,7 +117,7 @@ class InvokerBytecodeGenerator {
Name[] names = form.names; Name[] names = form.names;
for (int i = 0, index = 0; i < localsMap.length; i++) { for (int i = 0, index = 0; i < localsMap.length; i++) {
localsMap[i] = index; localsMap[i] = index;
index += Wrapper.forBasicType(names[i].type).stackSlots(); index += names[i].type.basicTypeSlots();
} }
} }
...@@ -359,47 +360,52 @@ class InvokerBytecodeGenerator { ...@@ -359,47 +360,52 @@ class InvokerBytecodeGenerator {
/* /*
* NOTE: These load/store methods use the localsMap to find the correct index! * NOTE: These load/store methods use the localsMap to find the correct index!
*/ */
private void emitLoadInsn(char type, int index) { private void emitLoadInsn(BasicType type, int index) {
int opcode; int opcode = loadInsnOpcode(type);
mv.visitVarInsn(opcode, localsMap[index]);
}
private int loadInsnOpcode(BasicType type) throws InternalError {
switch (type) { switch (type) {
case 'I': opcode = Opcodes.ILOAD; break; case I_TYPE: return Opcodes.ILOAD;
case 'J': opcode = Opcodes.LLOAD; break; case J_TYPE: return Opcodes.LLOAD;
case 'F': opcode = Opcodes.FLOAD; break; case F_TYPE: return Opcodes.FLOAD;
case 'D': opcode = Opcodes.DLOAD; break; case D_TYPE: return Opcodes.DLOAD;
case 'L': opcode = Opcodes.ALOAD; break; case L_TYPE: return Opcodes.ALOAD;
default: default:
throw new InternalError("unknown type: " + type); throw new InternalError("unknown type: " + type);
} }
mv.visitVarInsn(opcode, localsMap[index]);
} }
private void emitAloadInsn(int index) { private void emitAloadInsn(int index) {
emitLoadInsn('L', index); emitLoadInsn(L_TYPE, index);
} }
private void emitStoreInsn(char type, int index) { private void emitStoreInsn(BasicType type, int index) {
int opcode; int opcode = storeInsnOpcode(type);
mv.visitVarInsn(opcode, localsMap[index]);
}
private int storeInsnOpcode(BasicType type) throws InternalError {
switch (type) { switch (type) {
case 'I': opcode = Opcodes.ISTORE; break; case I_TYPE: return Opcodes.ISTORE;
case 'J': opcode = Opcodes.LSTORE; break; case J_TYPE: return Opcodes.LSTORE;
case 'F': opcode = Opcodes.FSTORE; break; case F_TYPE: return Opcodes.FSTORE;
case 'D': opcode = Opcodes.DSTORE; break; case D_TYPE: return Opcodes.DSTORE;
case 'L': opcode = Opcodes.ASTORE; break; case L_TYPE: return Opcodes.ASTORE;
default: default:
throw new InternalError("unknown type: " + type); throw new InternalError("unknown type: " + type);
} }
mv.visitVarInsn(opcode, localsMap[index]);
} }
private void emitAstoreInsn(int index) { private void emitAstoreInsn(int index) {
emitStoreInsn('L', index); emitStoreInsn(L_TYPE, index);
} }
/** /**
* Emit a boxing call. * Emit a boxing call.
* *
* @param type primitive type class to box. * @param wrapper primitive type class to box.
*/ */
private void emitBoxing(Class<?> type) { private void emitBoxing(Wrapper wrapper) {
Wrapper wrapper = Wrapper.forPrimitiveType(type);
String owner = "java/lang/" + wrapper.wrapperType().getSimpleName(); String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
String name = "valueOf"; String name = "valueOf";
String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";"; String desc = "(" + wrapper.basicTypeChar() + ")L" + owner + ";";
...@@ -409,10 +415,9 @@ class InvokerBytecodeGenerator { ...@@ -409,10 +415,9 @@ class InvokerBytecodeGenerator {
/** /**
* Emit an unboxing call (plus preceding checkcast). * Emit an unboxing call (plus preceding checkcast).
* *
* @param type wrapper type class to unbox. * @param wrapper wrapper type class to unbox.
*/ */
private void emitUnboxing(Class<?> type) { private void emitUnboxing(Wrapper wrapper) {
Wrapper wrapper = Wrapper.forWrapperType(type);
String owner = "java/lang/" + wrapper.wrapperType().getSimpleName(); String owner = "java/lang/" + wrapper.wrapperType().getSimpleName();
String name = wrapper.primitiveSimpleName() + "Value"; String name = wrapper.primitiveSimpleName() + "Value";
String desc = "()" + wrapper.basicTypeChar(); String desc = "()" + wrapper.basicTypeChar();
...@@ -426,9 +431,12 @@ class InvokerBytecodeGenerator { ...@@ -426,9 +431,12 @@ class InvokerBytecodeGenerator {
* @param ptype type of value present on stack * @param ptype type of value present on stack
* @param pclass type of value required on stack * @param pclass type of value required on stack
*/ */
private void emitImplicitConversion(char ptype, Class<?> pclass) { private void emitImplicitConversion(BasicType ptype, Class<?> pclass) {
assert(basicType(pclass) == ptype); // boxing/unboxing handled by caller
if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
return; // nothing to do
switch (ptype) { switch (ptype) {
case 'L': case L_TYPE:
if (VerifyType.isNullConversion(Object.class, pclass)) if (VerifyType.isNullConversion(Object.class, pclass))
return; return;
if (isStaticallyNameable(pclass)) { if (isStaticallyNameable(pclass)) {
...@@ -442,18 +450,9 @@ class InvokerBytecodeGenerator { ...@@ -442,18 +450,9 @@ class InvokerBytecodeGenerator {
mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY); mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
} }
return; return;
case 'I': case I_TYPE:
if (!VerifyType.isNullConversion(int.class, pclass)) if (!VerifyType.isNullConversion(int.class, pclass))
emitPrimCast(ptype, Wrapper.basicTypeChar(pclass)); emitPrimCast(ptype.basicTypeWrapper(), Wrapper.forPrimitiveType(pclass));
return;
case 'J':
assert(pclass == long.class);
return;
case 'F':
assert(pclass == float.class);
return;
case 'D':
assert(pclass == double.class);
return; return;
} }
throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass); throw new InternalError("bad implicit conversion: tc="+ptype+": "+pclass);
...@@ -462,15 +461,15 @@ class InvokerBytecodeGenerator { ...@@ -462,15 +461,15 @@ class InvokerBytecodeGenerator {
/** /**
* Emits an actual return instruction conforming to the given return type. * Emits an actual return instruction conforming to the given return type.
*/ */
private void emitReturnInsn(Class<?> type) { private void emitReturnInsn(BasicType type) {
int opcode; int opcode;
switch (Wrapper.basicTypeChar(type)) { switch (type) {
case 'I': opcode = Opcodes.IRETURN; break; case I_TYPE: opcode = Opcodes.IRETURN; break;
case 'J': opcode = Opcodes.LRETURN; break; case J_TYPE: opcode = Opcodes.LRETURN; break;
case 'F': opcode = Opcodes.FRETURN; break; case F_TYPE: opcode = Opcodes.FRETURN; break;
case 'D': opcode = Opcodes.DRETURN; break; case D_TYPE: opcode = Opcodes.DRETURN; break;
case 'L': opcode = Opcodes.ARETURN; break; case L_TYPE: opcode = Opcodes.ARETURN; break;
case 'V': opcode = Opcodes.RETURN; break; case V_TYPE: opcode = Opcodes.RETURN; break;
default: default:
throw new InternalError("unknown return type: " + type); throw new InternalError("unknown return type: " + type);
} }
...@@ -532,7 +531,7 @@ class InvokerBytecodeGenerator { ...@@ -532,7 +531,7 @@ class InvokerBytecodeGenerator {
// avoid store/load/return and just return) // avoid store/load/return and just return)
if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) { if (i == lambdaForm.names.length - 1 && i == lambdaForm.result) {
// return value - do nothing // return value - do nothing
} else if (name.type != 'V') { } else if (name.type != V_TYPE) {
// non-void: actually assign // non-void: actually assign
emitStoreInsn(name.type, name.index()); emitStoreInsn(name.type, name.index());
} }
...@@ -870,20 +869,24 @@ class InvokerBytecodeGenerator { ...@@ -870,20 +869,24 @@ class InvokerBytecodeGenerator {
private void emitPushArgument(Name name, int paramIndex) { private void emitPushArgument(Name name, int paramIndex) {
Object arg = name.arguments[paramIndex]; Object arg = name.arguments[paramIndex];
char ptype = name.function.parameterType(paramIndex); Class<?> ptype = name.function.methodType().parameterType(paramIndex);
MethodType mtype = name.function.methodType(); emitPushArgument(ptype, arg);
}
private void emitPushArgument(Class<?> ptype, Object arg) {
BasicType bptype = basicType(ptype);
if (arg instanceof Name) { if (arg instanceof Name) {
Name n = (Name) arg; Name n = (Name) arg;
emitLoadInsn(n.type, n.index()); emitLoadInsn(n.type, n.index());
emitImplicitConversion(n.type, mtype.parameterType(paramIndex)); emitImplicitConversion(n.type, ptype);
} else if ((arg == null || arg instanceof String) && ptype == 'L') { } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
emitConst(arg); emitConst(arg);
} else { } else {
if (Wrapper.isWrapperType(arg.getClass()) && ptype != 'L') { if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
emitConst(arg); emitConst(arg);
} else { } else {
mv.visitLdcInsn(constantPlaceholder(arg)); mv.visitLdcInsn(constantPlaceholder(arg));
emitImplicitConversion('L', mtype.parameterType(paramIndex)); emitImplicitConversion(L_TYPE, ptype);
} }
} }
} }
...@@ -893,52 +896,33 @@ class InvokerBytecodeGenerator { ...@@ -893,52 +896,33 @@ class InvokerBytecodeGenerator {
*/ */
private void emitReturn() { private void emitReturn() {
// return statement // return statement
if (lambdaForm.result == -1) { Class<?> rclass = invokerType.returnType();
BasicType rtype = lambdaForm.returnType();
assert(rtype == basicType(rclass)); // must agree
if (rtype == V_TYPE) {
// void // void
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
// it doesn't matter what rclass is; the JVM will discard any value
} else { } else {
LambdaForm.Name rn = lambdaForm.names[lambdaForm.result]; LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
char rtype = Wrapper.basicTypeChar(invokerType.returnType());
// put return value on the stack if it is not already there // put return value on the stack if it is not already there
if (lambdaForm.result != lambdaForm.names.length - 1) { if (lambdaForm.result != lambdaForm.names.length - 1 ||
lambdaForm.result < lambdaForm.arity) {
emitLoadInsn(rn.type, lambdaForm.result); emitLoadInsn(rn.type, lambdaForm.result);
} }
// potentially generate cast emitImplicitConversion(rtype, rclass);
// rtype is the return type of the invoker - generated code must conform to this
// rn.type is the type of the result Name in the LF
if (rtype != rn.type) {
// need cast
if (rtype == 'L') {
// possibly cast the primitive to the correct type for boxing
char boxedType = Wrapper.forWrapperType(invokerType.returnType()).basicTypeChar();
if (boxedType != rn.type) {
emitPrimCast(rn.type, boxedType);
}
// cast primitive to reference ("boxing")
emitBoxing(invokerType.returnType());
} else {
// to-primitive cast
if (rn.type != 'L') {
// prim-to-prim cast
emitPrimCast(rn.type, rtype);
} else {
// ref-to-prim cast ("unboxing")
throw new InternalError("no ref-to-prim (unboxing) casts supported right now");
}
}
}
// generate actual return statement // generate actual return statement
emitReturnInsn(invokerType.returnType()); emitReturnInsn(rtype);
} }
} }
/** /**
* Emit a type conversion bytecode casting from "from" to "to". * Emit a type conversion bytecode casting from "from" to "to".
*/ */
private void emitPrimCast(char from, char to) { private void emitPrimCast(Wrapper from, Wrapper to) {
// Here's how. // Here's how.
// - indicates forbidden // - indicates forbidden
// <-> indicates implicit // <-> indicates implicit
...@@ -955,17 +939,15 @@ class InvokerBytecodeGenerator { ...@@ -955,17 +939,15 @@ class InvokerBytecodeGenerator {
// no cast required, should be dead code anyway // no cast required, should be dead code anyway
return; return;
} }
Wrapper wfrom = Wrapper.forBasicType(from); if (from.isSubwordOrInt()) {
Wrapper wto = Wrapper.forBasicType(to);
if (wfrom.isSubwordOrInt()) {
// cast from {byte,short,char,int} to anything // cast from {byte,short,char,int} to anything
emitI2X(to); emitI2X(to);
} else { } else {
// cast from {long,float,double} to anything // cast from {long,float,double} to anything
if (wto.isSubwordOrInt()) { if (to.isSubwordOrInt()) {
// cast to {byte,short,char,int} // cast to {byte,short,char,int}
emitX2I(from); emitX2I(from);
if (wto.bitWidth() < 32) { if (to.bitWidth() < 32) {
// targets other than int require another conversion // targets other than int require another conversion
emitI2X(to); emitI2X(to);
} }
...@@ -973,20 +955,26 @@ class InvokerBytecodeGenerator { ...@@ -973,20 +955,26 @@ class InvokerBytecodeGenerator {
// cast to {long,float,double} - this is verbose // cast to {long,float,double} - this is verbose
boolean error = false; boolean error = false;
switch (from) { switch (from) {
case 'J': case LONG:
if (to == 'F') { mv.visitInsn(Opcodes.L2F); } switch (to) {
else if (to == 'D') { mv.visitInsn(Opcodes.L2D); } case FLOAT: mv.visitInsn(Opcodes.L2F); break;
else error = true; case DOUBLE: mv.visitInsn(Opcodes.L2D); break;
default: error = true; break;
}
break; break;
case 'F': case FLOAT:
if (to == 'J') { mv.visitInsn(Opcodes.F2L); } switch (to) {
else if (to == 'D') { mv.visitInsn(Opcodes.F2D); } case LONG : mv.visitInsn(Opcodes.F2L); break;
else error = true; case DOUBLE: mv.visitInsn(Opcodes.F2D); break;
default: error = true; break;
}
break; break;
case 'D': case DOUBLE:
if (to == 'J') { mv.visitInsn(Opcodes.D2L); } switch (to) {
else if (to == 'F') { mv.visitInsn(Opcodes.D2F); } case LONG : mv.visitInsn(Opcodes.D2L); break;
else error = true; case FLOAT: mv.visitInsn(Opcodes.D2F); break;
default: error = true; break;
}
break; break;
default: default:
error = true; error = true;
...@@ -999,16 +987,16 @@ class InvokerBytecodeGenerator { ...@@ -999,16 +987,16 @@ class InvokerBytecodeGenerator {
} }
} }
private void emitI2X(char type) { private void emitI2X(Wrapper type) {
switch (type) { switch (type) {
case 'B': mv.visitInsn(Opcodes.I2B); break; case BYTE: mv.visitInsn(Opcodes.I2B); break;
case 'S': mv.visitInsn(Opcodes.I2S); break; case SHORT: mv.visitInsn(Opcodes.I2S); break;
case 'C': mv.visitInsn(Opcodes.I2C); break; case CHAR: mv.visitInsn(Opcodes.I2C); break;
case 'I': /* naught */ break; case INT: /* naught */ break;
case 'J': mv.visitInsn(Opcodes.I2L); break; case LONG: mv.visitInsn(Opcodes.I2L); break;
case 'F': mv.visitInsn(Opcodes.I2F); break; case FLOAT: mv.visitInsn(Opcodes.I2F); break;
case 'D': mv.visitInsn(Opcodes.I2D); break; case DOUBLE: mv.visitInsn(Opcodes.I2D); break;
case 'Z': case BOOLEAN:
// For compatibility with ValueConversions and explicitCastArguments: // For compatibility with ValueConversions and explicitCastArguments:
mv.visitInsn(Opcodes.ICONST_1); mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IAND); mv.visitInsn(Opcodes.IAND);
...@@ -1017,39 +1005,24 @@ class InvokerBytecodeGenerator { ...@@ -1017,39 +1005,24 @@ class InvokerBytecodeGenerator {
} }
} }
private void emitX2I(char type) { private void emitX2I(Wrapper type) {
switch (type) { switch (type) {
case 'J': mv.visitInsn(Opcodes.L2I); break; case LONG: mv.visitInsn(Opcodes.L2I); break;
case 'F': mv.visitInsn(Opcodes.F2I); break; case FLOAT: mv.visitInsn(Opcodes.F2I); break;
case 'D': mv.visitInsn(Opcodes.D2I); break; case DOUBLE: mv.visitInsn(Opcodes.D2I); break;
default: throw new InternalError("unknown type: " + type); default: throw new InternalError("unknown type: " + type);
} }
} }
private static String basicTypeCharSignature(String prefix, MethodType type) {
StringBuilder buf = new StringBuilder(prefix);
for (Class<?> ptype : type.parameterList())
buf.append(Wrapper.forBasicType(ptype).basicTypeChar());
buf.append('_').append(Wrapper.forBasicType(type.returnType()).basicTypeChar());
return buf.toString();
}
/** /**
* Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments. * Generate bytecode for a LambdaForm.vmentry which calls interpretWithArguments.
*/ */
static MemberName generateLambdaFormInterpreterEntryPoint(String sig) { static MemberName generateLambdaFormInterpreterEntryPoint(String sig) {
assert(LambdaForm.isValidSignature(sig)); assert(isValidSignature(sig));
//System.out.println("generateExactInvoker "+sig); String name = "interpret_"+signatureReturn(sig).basicTypeChar();
// compute method type MethodType type = signatureType(sig); // sig includes leading argument
// first parameter and return type type = type.changeParameterType(0, MethodHandle.class);
char tret = LambdaForm.signatureReturn(sig); InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", name, type);
MethodType type = MethodType.methodType(LambdaForm.typeClass(tret), MethodHandle.class);
// other parameter types
int arity = LambdaForm.signatureArity(sig);
for (int i = 1; i < arity; i++) {
type = type.appendParameterTypes(LambdaForm.typeClass(sig.charAt(i)));
}
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("LFI", "interpret_"+tret, type);
return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes()); return g.loadMethod(g.generateLambdaFormInterpreterEntryPointBytes());
} }
...@@ -1071,10 +1044,10 @@ class InvokerBytecodeGenerator { ...@@ -1071,10 +1044,10 @@ class InvokerBytecodeGenerator {
Class<?> ptype = invokerType.parameterType(i); Class<?> ptype = invokerType.parameterType(i);
mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.DUP);
emitIconstInsn(i); emitIconstInsn(i);
emitLoadInsn(Wrapper.basicTypeChar(ptype), i); emitLoadInsn(basicType(ptype), i);
// box if primitive type // box if primitive type
if (ptype.isPrimitive()) { if (ptype.isPrimitive()) {
emitBoxing(ptype); emitBoxing(Wrapper.forPrimitiveType(ptype));
} }
mv.visitInsn(Opcodes.AASTORE); mv.visitInsn(Opcodes.AASTORE);
} }
...@@ -1087,11 +1060,11 @@ class InvokerBytecodeGenerator { ...@@ -1087,11 +1060,11 @@ class InvokerBytecodeGenerator {
// maybe unbox // maybe unbox
Class<?> rtype = invokerType.returnType(); Class<?> rtype = invokerType.returnType();
if (rtype.isPrimitive() && rtype != void.class) { if (rtype.isPrimitive() && rtype != void.class) {
emitUnboxing(Wrapper.asWrapperType(rtype)); emitUnboxing(Wrapper.forPrimitiveType(rtype));
} }
// return statement // return statement
emitReturnInsn(rtype); emitReturnInsn(basicType(rtype));
classFileEpilogue(); classFileEpilogue();
bogusMethod(invokerType); bogusMethod(invokerType);
...@@ -1105,14 +1078,12 @@ class InvokerBytecodeGenerator { ...@@ -1105,14 +1078,12 @@ class InvokerBytecodeGenerator {
* Generate bytecode for a NamedFunction invoker. * Generate bytecode for a NamedFunction invoker.
*/ */
static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) { static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
MethodType invokerType = LambdaForm.NamedFunction.INVOKER_METHOD_TYPE; MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
String invokerName = basicTypeCharSignature("invoke_", typeForm.erasedType()); String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType); InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm)); return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
} }
static int nfi = 0;
private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) { private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
MethodType dstType = typeForm.erasedType(); MethodType dstType = typeForm.erasedType();
classFilePrologue(); classFilePrologue();
...@@ -1138,8 +1109,8 @@ class InvokerBytecodeGenerator { ...@@ -1138,8 +1109,8 @@ class InvokerBytecodeGenerator {
Class<?> sptype = dstType.basicType().wrap().parameterType(i); Class<?> sptype = dstType.basicType().wrap().parameterType(i);
Wrapper dstWrapper = Wrapper.forBasicType(dptype); Wrapper dstWrapper = Wrapper.forBasicType(dptype);
Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int Wrapper srcWrapper = dstWrapper.isSubwordOrInt() ? Wrapper.INT : dstWrapper; // narrow subword from int
emitUnboxing(srcWrapper.wrapperType()); emitUnboxing(srcWrapper);
emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar()); emitPrimCast(srcWrapper, dstWrapper);
} }
} }
...@@ -1153,15 +1124,15 @@ class InvokerBytecodeGenerator { ...@@ -1153,15 +1124,15 @@ class InvokerBytecodeGenerator {
Wrapper srcWrapper = Wrapper.forBasicType(rtype); Wrapper srcWrapper = Wrapper.forBasicType(rtype);
Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
// boolean casts not allowed // boolean casts not allowed
emitPrimCast(srcWrapper.basicTypeChar(), dstWrapper.basicTypeChar()); emitPrimCast(srcWrapper, dstWrapper);
emitBoxing(dstWrapper.primitiveType()); emitBoxing(dstWrapper);
} }
// If the return type is void we return a null reference. // If the return type is void we return a null reference.
if (rtype == void.class) { if (rtype == void.class) {
mv.visitInsn(Opcodes.ACONST_NULL); mv.visitInsn(Opcodes.ACONST_NULL);
} }
emitReturnInsn(Object.class); // NOTE: NamedFunction invokers always return a reference value. emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
classFileEpilogue(); classFileEpilogue();
bogusMethod(dstType); bogusMethod(dstType);
......
...@@ -30,14 +30,14 @@ import java.lang.reflect.Method; ...@@ -30,14 +30,14 @@ import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.List; import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import java.lang.reflect.Field;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import java.lang.reflect.Field;
import java.util.Objects;
/** /**
* The symbolic, non-executable form of a method handle's invocation semantics. * The symbolic, non-executable form of a method handle's invocation semantics.
...@@ -130,13 +130,119 @@ class LambdaForm { ...@@ -130,13 +130,119 @@ class LambdaForm {
public static final int VOID_RESULT = -1, LAST_RESULT = -2; public static final int VOID_RESULT = -1, LAST_RESULT = -2;
enum BasicType {
L_TYPE('L', Object.class, Wrapper.OBJECT), // all reference types
I_TYPE('I', int.class, Wrapper.INT),
J_TYPE('J', long.class, Wrapper.LONG),
F_TYPE('F', float.class, Wrapper.FLOAT),
D_TYPE('D', double.class, Wrapper.DOUBLE), // all primitive types
V_TYPE('V', void.class, Wrapper.VOID); // not valid in all contexts
static final BasicType[] ALL_TYPES = BasicType.values();
static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
static final int ARG_TYPE_LIMIT = ARG_TYPES.length;
static final int TYPE_LIMIT = ALL_TYPES.length;
private final char btChar;
private final Class<?> btClass;
private final Wrapper btWrapper;
private BasicType(char btChar, Class<?> btClass, Wrapper wrapper) {
this.btChar = btChar;
this.btClass = btClass;
this.btWrapper = wrapper;
}
char basicTypeChar() {
return btChar;
}
Class<?> basicTypeClass() {
return btClass;
}
Wrapper basicTypeWrapper() {
return btWrapper;
}
int basicTypeSlots() {
return btWrapper.stackSlots();
}
static BasicType basicType(byte type) {
return ALL_TYPES[type];
}
static BasicType basicType(char type) {
switch (type) {
case 'L': return L_TYPE;
case 'I': return I_TYPE;
case 'J': return J_TYPE;
case 'F': return F_TYPE;
case 'D': return D_TYPE;
case 'V': return V_TYPE;
// all subword types are represented as ints
case 'Z':
case 'B':
case 'S':
case 'C':
return I_TYPE;
default:
throw newInternalError("Unknown type char: '"+type+"'");
}
}
static BasicType basicType(Wrapper type) {
char c = type.basicTypeChar();
return basicType(c);
}
static BasicType basicType(Class<?> type) {
if (!type.isPrimitive()) return L_TYPE;
return basicType(Wrapper.forPrimitiveType(type));
}
static char basicTypeChar(Class<?> type) {
return basicType(type).btChar;
}
static BasicType[] basicTypes(List<Class<?>> types) {
BasicType[] btypes = new BasicType[types.size()];
for (int i = 0; i < btypes.length; i++) {
btypes[i] = basicType(types.get(i));
}
return btypes;
}
static BasicType[] basicTypes(String types) {
BasicType[] btypes = new BasicType[types.length()];
for (int i = 0; i < btypes.length; i++) {
btypes[i] = basicType(types.charAt(i));
}
return btypes;
}
static boolean isBasicTypeChar(char c) {
return "LIJFDV".indexOf(c) >= 0;
}
static boolean isArgBasicTypeChar(char c) {
return "LIJFD".indexOf(c) >= 0;
}
static { assert(checkBasicType()); }
private static boolean checkBasicType() {
for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
assert ARG_TYPES[i].ordinal() == i;
assert ARG_TYPES[i] == ALL_TYPES[i];
}
for (int i = 0; i < TYPE_LIMIT; i++) {
assert ALL_TYPES[i].ordinal() == i;
}
assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
return true;
}
}
LambdaForm(String debugName, LambdaForm(String debugName,
int arity, Name[] names, int result) { int arity, Name[] names, int result) {
assert(namesOK(arity, names)); assert(namesOK(arity, names));
this.arity = arity; this.arity = arity;
this.result = fixResult(result, names); this.result = fixResult(result, names);
this.names = names.clone(); this.names = names.clone();
this.debugName = debugName; this.debugName = fixDebugName(debugName);
normalize(); normalize();
} }
...@@ -168,12 +274,12 @@ class LambdaForm { ...@@ -168,12 +274,12 @@ class LambdaForm {
// Called only from getPreparedForm. // Called only from getPreparedForm.
assert(isValidSignature(sig)); assert(isValidSignature(sig));
this.arity = signatureArity(sig); this.arity = signatureArity(sig);
this.result = (signatureReturn(sig) == 'V' ? -1 : arity); this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
this.names = buildEmptyNames(arity, sig); this.names = buildEmptyNames(arity, sig);
this.debugName = "LF.zero"; this.debugName = "LF.zero";
assert(nameRefsAreLegal()); assert(nameRefsAreLegal());
assert(isEmpty()); assert(isEmpty());
assert(sig.equals(basicTypeSignature())); assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
} }
private static Name[] buildEmptyNames(int arity, String basicTypeSignature) { private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
...@@ -181,24 +287,55 @@ class LambdaForm { ...@@ -181,24 +287,55 @@ class LambdaForm {
int resultPos = arity + 1; // skip '_' int resultPos = arity + 1; // skip '_'
if (arity < 0 || basicTypeSignature.length() != resultPos+1) if (arity < 0 || basicTypeSignature.length() != resultPos+1)
throw new IllegalArgumentException("bad arity for "+basicTypeSignature); throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1); int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity)); Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
for (int i = 0; i < numRes; i++) { for (int i = 0; i < numRes; i++) {
names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i)); Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
names[arity + i] = zero.newIndex(arity + i);
} }
return names; return names;
} }
private static int fixResult(int result, Name[] names) { private static int fixResult(int result, Name[] names) {
if (result >= 0) { if (result == LAST_RESULT)
if (names[result].type == 'V') result = names.length - 1; // might still be void
return -1; if (result >= 0 && names[result].type == V_TYPE)
} else if (result == LAST_RESULT) { result = VOID_RESULT;
return names.length - 1;
}
return result; return result;
} }
private static String fixDebugName(String debugName) {
if (DEBUG_NAME_COUNTERS != null) {
int under = debugName.indexOf('_');
int length = debugName.length();
if (under < 0) under = length;
String debugNameStem = debugName.substring(0, under);
Integer ctr;
synchronized (DEBUG_NAME_COUNTERS) {
ctr = DEBUG_NAME_COUNTERS.get(debugNameStem);
if (ctr == null) ctr = 0;
DEBUG_NAME_COUNTERS.put(debugNameStem, ctr+1);
}
StringBuilder buf = new StringBuilder(debugNameStem);
buf.append('_');
int leadingZero = buf.length();
buf.append((int) ctr);
for (int i = buf.length() - leadingZero; i < 3; i++)
buf.insert(leadingZero, '0');
if (under < length) {
++under; // skip "_"
while (under < length && Character.isDigit(debugName.charAt(under))) {
++under;
}
if (under < length && debugName.charAt(under) == '_') ++under;
if (under < length)
buf.append('_').append(debugName, under, length);
}
return buf.toString();
}
return debugName;
}
private static boolean namesOK(int arity, Name[] names) { private static boolean namesOK(int arity, Name[] names) {
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
Name n = names[i]; Name n = names[i];
...@@ -294,14 +431,14 @@ class LambdaForm { ...@@ -294,14 +431,14 @@ class LambdaForm {
// } // }
/** Report the return type. */ /** Report the return type. */
char returnType() { BasicType returnType() {
if (result < 0) return 'V'; if (result < 0) return V_TYPE;
Name n = names[result]; Name n = names[result];
return n.type; return n.type;
} }
/** Report the N-th argument type. */ /** Report the N-th argument type. */
char parameterType(int n) { BasicType parameterType(int n) {
assert(n < arity); assert(n < arity);
return names[n].type; return names[n].type;
} }
...@@ -319,15 +456,15 @@ class LambdaForm { ...@@ -319,15 +456,15 @@ class LambdaForm {
final String basicTypeSignature() { final String basicTypeSignature() {
StringBuilder buf = new StringBuilder(arity() + 3); StringBuilder buf = new StringBuilder(arity() + 3);
for (int i = 0, a = arity(); i < a; i++) for (int i = 0, a = arity(); i < a; i++)
buf.append(parameterType(i)); buf.append(parameterType(i).basicTypeChar());
return buf.append('_').append(returnType()).toString(); return buf.append('_').append(returnType().basicTypeChar()).toString();
} }
static int signatureArity(String sig) { static int signatureArity(String sig) {
assert(isValidSignature(sig)); assert(isValidSignature(sig));
return sig.indexOf('_'); return sig.indexOf('_');
} }
static char signatureReturn(String sig) { static BasicType signatureReturn(String sig) {
return sig.charAt(signatureArity(sig)+1); return basicType(sig.charAt(signatureArity(sig)+1));
} }
static boolean isValidSignature(String sig) { static boolean isValidSignature(String sig) {
int arity = sig.indexOf('_'); int arity = sig.indexOf('_');
...@@ -339,27 +476,15 @@ class LambdaForm { ...@@ -339,27 +476,15 @@ class LambdaForm {
char c = sig.charAt(i); char c = sig.charAt(i);
if (c == 'V') if (c == 'V')
return (i == siglen - 1 && arity == siglen - 2); return (i == siglen - 1 && arity == siglen - 2);
if (ALL_TYPES.indexOf(c) < 0) return false; // must be [LIJFD] if (!isArgBasicTypeChar(c)) return false; // must be [LIJFD]
} }
return true; // [LIJFD]*_[LIJFDV] return true; // [LIJFD]*_[LIJFDV]
} }
static Class<?> typeClass(char t) {
switch (t) {
case 'I': return int.class;
case 'J': return long.class;
case 'F': return float.class;
case 'D': return double.class;
case 'L': return Object.class;
case 'V': return void.class;
default: assert false;
}
return null;
}
static MethodType signatureType(String sig) { static MethodType signatureType(String sig) {
Class<?>[] ptypes = new Class<?>[signatureArity(sig)]; Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
for (int i = 0; i < ptypes.length; i++) for (int i = 0; i < ptypes.length; i++)
ptypes[i] = typeClass(sig.charAt(i)); ptypes[i] = basicType(sig.charAt(i)).btClass;
Class<?> rtype = typeClass(signatureReturn(sig)); Class<?> rtype = signatureReturn(sig).btClass;
return MethodType.methodType(rtype, ptypes); return MethodType.methodType(rtype, ptypes);
} }
...@@ -543,21 +668,21 @@ class LambdaForm { ...@@ -543,21 +668,21 @@ class LambdaForm {
assert(mt.parameterCount() == arity-1); assert(mt.parameterCount() == arity-1);
for (int i = 0; i < av.length; i++) { for (int i = 0; i < av.length; i++) {
Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1)); Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
assert(valueMatches(sig.charAt(i), pt, av[i])); assert(valueMatches(basicType(sig.charAt(i)), pt, av[i]));
} }
return true; return true;
} }
private static boolean valueMatches(char tc, Class<?> type, Object x) { private static boolean valueMatches(BasicType tc, Class<?> type, Object x) {
// The following line is needed because (...)void method handles can use non-void invokers // The following line is needed because (...)void method handles can use non-void invokers
if (type == void.class) tc = 'V'; // can drop any kind of value if (type == void.class) tc = V_TYPE; // can drop any kind of value
assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type); assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
switch (tc) { switch (tc) {
case 'I': assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break; case I_TYPE: assert checkInt(type, x) : "checkInt(" + type + "," + x +")"; break;
case 'J': assert x instanceof Long : "instanceof Long: " + x; break; case J_TYPE: assert x instanceof Long : "instanceof Long: " + x; break;
case 'F': assert x instanceof Float : "instanceof Float: " + x; break; case F_TYPE: assert x instanceof Float : "instanceof Float: " + x; break;
case 'D': assert x instanceof Double : "instanceof Double: " + x; break; case D_TYPE: assert x instanceof Double : "instanceof Double: " + x; break;
case 'L': assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break; case L_TYPE: assert checkRef(type, x) : "checkRef(" + type + "," + x + ")"; break;
case 'V': break; // allow anything here; will be dropped case V_TYPE: break; // allow anything here; will be dropped
default: assert(false); default: assert(false);
} }
return true; return true;
...@@ -736,7 +861,7 @@ class LambdaForm { ...@@ -736,7 +861,7 @@ class LambdaForm {
* The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
* accepted as valid. * accepted as valid.
*/ */
LambdaForm bindImmediate(int pos, char basicType, Object value) { LambdaForm bindImmediate(int pos, BasicType basicType, Object value) {
// must be an argument, and the types must match // must be an argument, and the types must match
assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value); assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
...@@ -782,8 +907,8 @@ class LambdaForm { ...@@ -782,8 +907,8 @@ class LambdaForm {
LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) { LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
Name name = names[namePos]; Name name = names[namePos];
BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type); BoundMethodHandle.SpeciesData newData = oldData.extendWith(name.type);
return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData); return bind(name, new Name(newData.getterFunction(oldData.fieldCount()), names[0]), oldData, newData);
} }
LambdaForm bind(Name name, Name binding, LambdaForm bind(Name name, Name binding,
BoundMethodHandle.SpeciesData oldData, BoundMethodHandle.SpeciesData oldData,
...@@ -874,7 +999,7 @@ class LambdaForm { ...@@ -874,7 +999,7 @@ class LambdaForm {
return false; return false;
} }
LambdaForm addArguments(int pos, char... types) { LambdaForm addArguments(int pos, BasicType... types) {
assert(pos <= arity); assert(pos <= arity);
int length = names.length; int length = names.length;
int inTypes = types.length; int inTypes = types.length;
...@@ -895,13 +1020,10 @@ class LambdaForm { ...@@ -895,13 +1020,10 @@ class LambdaForm {
} }
LambdaForm addArguments(int pos, List<Class<?>> types) { LambdaForm addArguments(int pos, List<Class<?>> types) {
char[] basicTypes = new char[types.size()]; return addArguments(pos, basicTypes(types));
for (int i = 0; i < basicTypes.length; i++)
basicTypes[i] = basicType(types.get(i));
return addArguments(pos, basicTypes);
} }
LambdaForm permuteArguments(int skip, int[] reorder, char[] types) { LambdaForm permuteArguments(int skip, int[] reorder, BasicType[] types) {
// Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg. // Note: When inArg = reorder[outArg], outArg is fed by a copy of inArg.
// The types are the types of the new (incoming) arguments. // The types are the types of the new (incoming) arguments.
int length = names.length; int length = names.length;
...@@ -960,7 +1082,7 @@ class LambdaForm { ...@@ -960,7 +1082,7 @@ class LambdaForm {
return new LambdaForm(debugName, arity2, names2, result2); return new LambdaForm(debugName, arity2, names2, result2);
} }
static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) { static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
int inTypes = types.length; int inTypes = types.length;
int outArgs = reorder.length; int outArgs = reorder.length;
for (int i = 0; i < outArgs; i++) { for (int i = 0; i < outArgs; i++) {
...@@ -1044,7 +1166,7 @@ class LambdaForm { ...@@ -1044,7 +1166,7 @@ class LambdaForm {
String sig = m.getName().substring("invoke_".length()); String sig = m.getName().substring("invoke_".length());
int arity = LambdaForm.signatureArity(sig); int arity = LambdaForm.signatureArity(sig);
MethodType srcType = MethodType.genericMethodType(arity); MethodType srcType = MethodType.genericMethodType(arity);
if (LambdaForm.signatureReturn(sig) == 'V') if (LambdaForm.signatureReturn(sig) == V_TYPE)
srcType = srcType.changeReturnType(void.class); srcType = srcType.changeReturnType(void.class);
MethodTypeForm typeForm = srcType.form(); MethodTypeForm typeForm = srcType.form();
typeForm.namedFunctionInvoker = DirectMethodHandle.make(m); typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
...@@ -1134,7 +1256,7 @@ class LambdaForm { ...@@ -1134,7 +1256,7 @@ class LambdaForm {
MethodHandle mh2 = typeForm.namedFunctionInvoker; MethodHandle mh2 = typeForm.namedFunctionInvoker;
if (mh2 != null) return mh2; // benign race if (mh2 != null) return mh2; // benign race
if (!mh.type().equals(INVOKER_METHOD_TYPE)) if (!mh.type().equals(INVOKER_METHOD_TYPE))
throw new InternalError(mh.debugString()); throw newInternalError(mh.debugString());
return typeForm.namedFunctionInvoker = mh; return typeForm.namedFunctionInvoker = mh;
} }
...@@ -1193,11 +1315,6 @@ class LambdaForm { ...@@ -1193,11 +1315,6 @@ class LambdaForm {
return true; return true;
} }
String basicTypeSignature() {
//return LambdaForm.basicTypeSignature(resolvedHandle.type());
return LambdaForm.basicTypeSignature(methodType());
}
MethodType methodType() { MethodType methodType() {
if (resolvedHandle != null) if (resolvedHandle != null)
return resolvedHandle.type(); return resolvedHandle.type();
...@@ -1224,18 +1341,15 @@ class LambdaForm { ...@@ -1224,18 +1341,15 @@ class LambdaForm {
return (member == null) ? null : member.getDeclaringClass(); return (member == null) ? null : member.getDeclaringClass();
} }
char returnType() { BasicType returnType() {
return basicType(methodType().returnType()); return basicType(methodType().returnType());
} }
char parameterType(int n) { BasicType parameterType(int n) {
return basicType(methodType().parameterType(n)); return basicType(methodType().parameterType(n));
} }
int arity() { int arity() {
//int siglen = member.getMethodType().parameterCount();
//if (!member.isStatic()) siglen += 1;
//return siglen;
return methodType().parameterCount(); return methodType().parameterCount();
} }
...@@ -1243,44 +1357,63 @@ class LambdaForm { ...@@ -1243,44 +1357,63 @@ class LambdaForm {
if (member == null) return String.valueOf(resolvedHandle); if (member == null) return String.valueOf(resolvedHandle);
return member.getDeclaringClass().getSimpleName()+"."+member.getName(); return member.getDeclaringClass().getSimpleName()+"."+member.getName();
} }
}
void resolve() { public boolean isIdentity() {
for (Name n : names) n.resolve(); return this.equals(identity(returnType()));
} }
public static char basicType(Class<?> type) { public boolean isConstantZero() {
char c = Wrapper.basicTypeChar(type); return this.equals(constantZero(returnType()));
if ("ZBSC".indexOf(c) >= 0) c = 'I';
assert("LIJFDV".indexOf(c) >= 0);
return c;
}
public static char[] basicTypes(List<Class<?>> types) {
char[] btypes = new char[types.size()];
for (int i = 0; i < btypes.length; i++) {
btypes[i] = basicType(types.get(i));
} }
return btypes;
} }
public static String basicTypeSignature(MethodType type) { public static String basicTypeSignature(MethodType type) {
char[] sig = new char[type.parameterCount() + 2]; char[] sig = new char[type.parameterCount() + 2];
int sigp = 0; int sigp = 0;
for (Class<?> pt : type.parameterList()) { for (Class<?> pt : type.parameterList()) {
sig[sigp++] = basicType(pt); sig[sigp++] = basicTypeChar(pt);
} }
sig[sigp++] = '_'; sig[sigp++] = '_';
sig[sigp++] = basicType(type.returnType()); sig[sigp++] = basicTypeChar(type.returnType());
assert(sigp == sig.length); assert(sigp == sig.length);
return String.valueOf(sig); return String.valueOf(sig);
} }
public static String shortenSignature(String signature) {
// Hack to make signatures more readable when they show up in method names.
final int NO_CHAR = -1, MIN_RUN = 3;
int c0, c1 = NO_CHAR, c1reps = 0;
StringBuilder buf = null;
int len = signature.length();
if (len < MIN_RUN) return signature;
for (int i = 0; i <= len; i++) {
// shift in the next char:
c0 = c1; c1 = (i == len ? NO_CHAR : signature.charAt(i));
if (c1 == c0) { ++c1reps; continue; }
// shift in the next count:
int c0reps = c1reps; c1reps = 1;
// end of a character run
if (c0reps < MIN_RUN) {
if (buf != null) {
while (--c0reps >= 0)
buf.append((char)c0);
}
continue;
}
// found three or more in a row
if (buf == null)
buf = new StringBuilder().append(signature, 0, i - c0reps);
buf.append((char)c0).append(c0reps);
}
return (buf == null) ? signature : buf.toString();
}
static final class Name { static final class Name {
final char type; final BasicType type;
private short index; private short index;
final NamedFunction function; final NamedFunction function;
@Stable final Object[] arguments; @Stable final Object[] arguments;
private Name(int index, char type, NamedFunction function, Object[] arguments) { private Name(int index, BasicType type, NamedFunction function, Object[] arguments) {
this.index = (short)index; this.index = (short)index;
this.type = type; this.type = type;
this.function = function; this.function = function;
...@@ -1292,7 +1425,7 @@ class LambdaForm { ...@@ -1292,7 +1425,7 @@ class LambdaForm {
} }
Name(MethodType functionType, Object... arguments) { Name(MethodType functionType, Object... arguments) {
this(new NamedFunction(functionType), arguments); this(new NamedFunction(functionType), arguments);
assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L'); assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == L_TYPE);
} }
Name(MemberName function, Object... arguments) { Name(MemberName function, Object... arguments) {
this(new NamedFunction(function), arguments); this(new NamedFunction(function), arguments);
...@@ -1303,14 +1436,14 @@ class LambdaForm { ...@@ -1303,14 +1436,14 @@ class LambdaForm {
for (int i = 0; i < arguments.length; i++) for (int i = 0; i < arguments.length; i++)
assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString(); assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
} }
Name(int index, char type) { /** Create a raw parameter of the given type, with an expected index. */
Name(int index, BasicType type) {
this(index, type, null, null); this(index, type, null, null);
} }
Name(char type) { /** Create a raw parameter of the given type. */
this(-1, type); Name(BasicType type) { this(-1, type); }
}
char type() { return type; } BasicType type() { return type; }
int index() { return index; } int index() { return index; }
boolean initIndex(int i) { boolean initIndex(int i) {
if (index != i) { if (index != i) {
...@@ -1319,7 +1452,9 @@ class LambdaForm { ...@@ -1319,7 +1452,9 @@ class LambdaForm {
} }
return true; return true;
} }
char typeChar() {
return type.btChar;
}
void resolve() { void resolve() {
if (function != null) if (function != null)
...@@ -1397,18 +1532,18 @@ class LambdaForm { ...@@ -1397,18 +1532,18 @@ class LambdaForm {
return function == null; return function == null;
} }
boolean isConstantZero() { boolean isConstantZero() {
return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function); return !isParam() && arguments.length == 0 && function.isConstantZero();
} }
public String toString() { public String toString() {
return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type; return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+typeChar();
} }
public String debugString() { public String debugString() {
String s = toString(); String s = toString();
return (function == null) ? s : s + "=" + exprString(); return (function == null) ? s : s + "=" + exprString();
} }
public String exprString() { public String exprString() {
if (function == null) return "null"; if (function == null) return toString();
StringBuilder buf = new StringBuilder(function.toString()); StringBuilder buf = new StringBuilder(function.toString());
buf.append("("); buf.append("(");
String cma = ""; String cma = "";
...@@ -1423,17 +1558,17 @@ class LambdaForm { ...@@ -1423,17 +1558,17 @@ class LambdaForm {
return buf.toString(); return buf.toString();
} }
private static boolean typesMatch(char parameterType, Object object) { static boolean typesMatch(BasicType parameterType, Object object) {
if (object instanceof Name) { if (object instanceof Name) {
return ((Name)object).type == parameterType; return ((Name)object).type == parameterType;
} }
switch (parameterType) { switch (parameterType) {
case 'I': return object instanceof Integer; case I_TYPE: return object instanceof Integer;
case 'J': return object instanceof Long; case J_TYPE: return object instanceof Long;
case 'F': return object instanceof Float; case F_TYPE: return object instanceof Float;
case 'D': return object instanceof Double; case D_TYPE: return object instanceof Double;
} }
assert(parameterType == 'L'); assert(parameterType == L_TYPE);
return true; return true;
} }
...@@ -1510,7 +1645,7 @@ class LambdaForm { ...@@ -1510,7 +1645,7 @@ class LambdaForm {
@Override @Override
public int hashCode() { public int hashCode() {
if (isParam()) if (isParam())
return index | (type << 8); return index | (type.ordinal() << 8);
return function.hashCode() ^ Arrays.hashCode(arguments); return function.hashCode() ^ Arrays.hashCode(arguments);
} }
} }
...@@ -1545,10 +1680,12 @@ class LambdaForm { ...@@ -1545,10 +1680,12 @@ class LambdaForm {
} }
static Name argument(int which, char type) { static Name argument(int which, char type) {
int tn = ALL_TYPES.indexOf(type); return argument(which, basicType(type));
if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT) }
static Name argument(int which, BasicType type) {
if (which >= INTERNED_ARGUMENT_LIMIT)
return new Name(which, type); return new Name(which, type);
return INTERNED_ARGUMENTS[tn][which]; return INTERNED_ARGUMENTS[type.ordinal()][which];
} }
static Name internArgument(Name n) { static Name internArgument(Name n) {
assert(n.isParam()) : "not param: " + n; assert(n.isParam()) : "not param: " + n;
...@@ -1590,57 +1727,119 @@ class LambdaForm { ...@@ -1590,57 +1727,119 @@ class LambdaForm {
names[i] = argument(i, basicType(types.parameterType(i))); names[i] = argument(i, basicType(types.parameterType(i)));
return names; return names;
} }
static final String ALL_TYPES = "LIJFD"; // omit V, not an argument type
static final int INTERNED_ARGUMENT_LIMIT = 10; static final int INTERNED_ARGUMENT_LIMIT = 10;
private static final Name[][] INTERNED_ARGUMENTS private static final Name[][] INTERNED_ARGUMENTS
= new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT]; = new Name[ARG_TYPE_LIMIT][INTERNED_ARGUMENT_LIMIT];
static { static {
for (int tn = 0; tn < ALL_TYPES.length(); tn++) { for (BasicType type : BasicType.ARG_TYPES) {
for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) { int ord = type.ordinal();
char type = ALL_TYPES.charAt(tn); for (int i = 0; i < INTERNED_ARGUMENTS[ord].length; i++) {
INTERNED_ARGUMENTS[tn][i] = new Name(i, type); INTERNED_ARGUMENTS[ord][i] = new Name(i, type);
} }
} }
} }
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
static Name constantZero(int which, char type) { static LambdaForm identityForm(BasicType type) {
return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which); return LF_identityForm[type.ordinal()];
} }
private static final Name[] CONSTANT_ZERO static LambdaForm zeroForm(BasicType type) {
= new Name[ALL_TYPES.length()]; return LF_zeroForm[type.ordinal()];
static { }
for (int tn = 0; tn < ALL_TYPES.length(); tn++) { static NamedFunction identity(BasicType type) {
char bt = ALL_TYPES.charAt(tn); return NF_identity[type.ordinal()];
Wrapper wrap = Wrapper.forBasicType(bt); }
MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic); static NamedFunction constantZero(BasicType type) {
return NF_zero[type.ordinal()];
}
private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
private static void createIdentityForms() {
for (BasicType type : BasicType.ALL_TYPES) {
int ord = type.ordinal();
char btChar = type.basicTypeChar();
boolean isVoid = (type == V_TYPE);
Class<?> btClass = type.btClass;
MethodType zeType = MethodType.methodType(btClass);
MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
// Look up some symbolic names. It might not be necessary to have these,
// but if we need to emit direct references to bytecodes, it helps.
// Zero is built from a call to an identity function with a constant zero input.
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
try { try {
zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class); zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
} catch (IllegalAccessException|NoSuchMethodException ex) { } catch (IllegalAccessException|NoSuchMethodException ex) {
throw newInternalError(ex); throw newInternalError(ex);
} }
NamedFunction zcon = new NamedFunction(zmem);
Name n = new Name(zcon).newIndex(0); NamedFunction idFun = new NamedFunction(idMem);
assert(n.type == ALL_TYPES.charAt(tn)); LambdaForm idForm;
CONSTANT_ZERO[tn] = n; if (isVoid) {
assert(n.isConstantZero()); Name[] idNames = new Name[] { argument(0, L_TYPE) };
idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
} else {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
}
LF_identityForm[ord] = idForm;
NF_identity[ord] = idFun;
NamedFunction zeFun = new NamedFunction(zeMem);
LambdaForm zeForm;
if (isVoid) {
zeForm = idForm;
} else {
Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
}
LF_zeroForm[ord] = zeForm;
NF_zero[ord] = zeFun;
assert(idFun.isIdentity());
assert(zeFun.isConstantZero());
assert(new Name(zeFun).isConstantZero());
} }
}
// Avoid appealing to ValueConversions at bootstrap time: // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
private static int zeroI() { return 0; } for (BasicType type : BasicType.ALL_TYPES) {
private static long zeroJ() { return 0; } int ord = type.ordinal();
private static float zeroF() { return 0; } NamedFunction idFun = NF_identity[ord];
private static double zeroD() { return 0; } LambdaForm idForm = LF_identityForm[ord];
private static Object zeroL() { return null; } MemberName idMem = idFun.member;
idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
// Put this last, so that previous static inits can run before. NamedFunction zeFun = NF_zero[ord];
static { LambdaForm zeForm = LF_zeroForm[ord];
if (USE_PREDEFINED_INTERPRET_METHODS) MemberName zeMem = zeFun.member;
PREPARED_FORMS.putAll(computeInitialPreparedForms()); zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
assert(idFun.isIdentity());
assert(zeFun.isConstantZero());
assert(new Name(zeFun).isConstantZero());
}
} }
// Avoid appealing to ValueConversions at bootstrap time:
private static int identity_I(int x) { return x; }
private static long identity_J(long x) { return x; }
private static float identity_F(float x) { return x; }
private static double identity_D(double x) { return x; }
private static Object identity_L(Object x) { return x; }
private static void identity_V() { return; } // same as zeroV, but that's OK
private static int zero_I() { return 0; }
private static long zero_J() { return 0; }
private static float zero_F() { return 0; }
private static double zero_D() { return 0; }
private static Object zero_L() { return null; }
private static void zero_V() { return; }
/** /**
* Internal marker for byte-compiled LambdaForms. * Internal marker for byte-compiled LambdaForms.
*/ */
...@@ -1690,7 +1889,21 @@ class LambdaForm { ...@@ -1690,7 +1889,21 @@ class LambdaForm {
static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable; static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
*/ */
static { NamedFunction.initializeInvokers(); } private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
static {
if (debugEnabled())
DEBUG_NAME_COUNTERS = new HashMap<>();
else
DEBUG_NAME_COUNTERS = null;
}
// Put this last, so that previous static inits can run before.
static {
createIdentityForms();
if (USE_PREDEFINED_INTERPRET_METHODS)
PREPARED_FORMS.putAll(computeInitialPreparedForms());
NamedFunction.initializeInvokers();
}
// The following hack is necessary in order to suppress TRACE_INTERPRETER // The following hack is necessary in order to suppress TRACE_INTERPRETER
// during execution of the static initializes of this class. // during execution of the static initializes of this class.
......
...@@ -27,12 +27,12 @@ package java.lang.invoke; ...@@ -27,12 +27,12 @@ package java.lang.invoke;
import java.util.*; import java.util.*;
import java.lang.invoke.LambdaForm.BasicType;
import sun.invoke.util.*; import sun.invoke.util.*;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import java.util.logging.Level; import static java.lang.invoke.LambdaForm.BasicType.*;
import java.util.logging.Logger;
/** /**
* A method handle is a typed, directly executable reference to an underlying method, * A method handle is a typed, directly executable reference to an underlying method,
...@@ -731,7 +731,7 @@ public abstract class MethodHandle { ...@@ -731,7 +731,7 @@ public abstract class MethodHandle {
* <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive, * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
* a zero value is introduced. * a zero value is introduced.
* </ul> * </ul>
* (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types, * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
* because neither corresponds specifically to the <em>dynamic type</em> of any * because neither corresponds specifically to the <em>dynamic type</em> of any
* actual argument or return value.) * actual argument or return value.)
* <p> * <p>
...@@ -1376,7 +1376,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1376,7 +1376,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
} }
/*non-public*/ /*non-public*/
MethodHandle bindArgument(int pos, char basicType, Object value) { MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
// Override this if it can be improved. // Override this if it can be improved.
return rebind().bindArgument(pos, basicType, value); return rebind().bindArgument(pos, basicType, value);
} }
...@@ -1384,26 +1384,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1384,26 +1384,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/ /*non-public*/
MethodHandle bindReceiver(Object receiver) { MethodHandle bindReceiver(Object receiver) {
// Override this if it can be improved. // Override this if it can be improved.
return bindArgument(0, 'L', receiver); return bindArgument(0, L_TYPE, receiver);
}
/*non-public*/
MethodHandle bindImmediate(int pos, char basicType, Object value) {
// Bind an immediate value to a position in the arguments.
// This means, elide the respective argument,
// and replace all references to it in NamedFunction args with the specified value.
// CURRENT RESTRICTIONS
// * only for pos 0 and UNSAFE (position is adjusted in MHImpl to make API usable for others)
assert pos == 0 && basicType == 'L' && value instanceof Unsafe;
MethodType type2 = type.dropParameterTypes(pos, pos + 1); // adjustment: ignore receiver!
LambdaForm form2 = form.bindImmediate(pos + 1, basicType, value); // adjust pos to form-relative pos
return copyWith(type2, form2);
}
/*non-public*/
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
throw new InternalError("copyWith: " + this.getClass());
} }
/*non-public*/ /*non-public*/
......
...@@ -412,7 +412,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -412,7 +412,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
@Override @Override
MethodHandle bindArgument(int pos, char basicType, Object value) { MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
return asFixedArity().bindArgument(pos, basicType, value); return asFixedArity().bindArgument(pos, basicType, value);
} }
......
...@@ -78,7 +78,7 @@ class MethodHandleNatives { ...@@ -78,7 +78,7 @@ class MethodHandleNatives {
// The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed: // The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
MethodHandleImpl.initStatics(); MethodHandleImpl.initStatics();
} }
// All compile-time constants go here. // All compile-time constants go here.
// There is an opportunity to check them against the JVM's idea of them. // There is an opportunity to check them against the JVM's idea of them.
...@@ -293,6 +293,17 @@ class MethodHandleNatives { ...@@ -293,6 +293,17 @@ class MethodHandleNatives {
Class<?> caller = (Class<?>)callerObj; Class<?> caller = (Class<?>)callerObj;
String name = nameObj.toString().intern(); String name = nameObj.toString().intern();
MethodType type = (MethodType)typeObj; MethodType type = (MethodType)typeObj;
if (!TRACE_METHOD_LINKAGE)
return linkCallSiteImpl(caller, bootstrapMethod, name, type,
staticArguments, appendixResult);
return linkCallSiteTracing(caller, bootstrapMethod, name, type,
staticArguments, appendixResult);
}
static MemberName linkCallSiteImpl(Class<?> caller,
MethodHandle bootstrapMethod,
String name, MethodType type,
Object staticArguments,
Object[] appendixResult) {
CallSite callSite = CallSite.makeSite(bootstrapMethod, CallSite callSite = CallSite.makeSite(bootstrapMethod,
name, name,
type, type,
...@@ -306,6 +317,30 @@ class MethodHandleNatives { ...@@ -306,6 +317,30 @@ class MethodHandleNatives {
return Invokers.linkToCallSiteMethod(type); return Invokers.linkToCallSiteMethod(type);
} }
} }
// Tracing logic:
static MemberName linkCallSiteTracing(Class<?> caller,
MethodHandle bootstrapMethod,
String name, MethodType type,
Object staticArguments,
Object[] appendixResult) {
Object bsmReference = bootstrapMethod.internalMemberName();
if (bsmReference == null) bsmReference = bootstrapMethod;
Object staticArglist = (staticArguments instanceof Object[] ?
java.util.Arrays.asList((Object[]) staticArguments) :
staticArguments);
System.out.println("linkCallSite "+caller.getName()+" "+
bsmReference+" "+
name+type+"/"+staticArglist);
try {
MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type,
staticArguments, appendixResult);
System.out.println("linkCallSite => "+res+" + "+appendixResult[0]);
return res;
} catch (Throwable ex) {
System.out.println("linkCallSite => throw "+ex);
throw ex;
}
}
/** /**
* The JVM wants a pointer to a MethodType. Oblige it by finding or creating one. * The JVM wants a pointer to a MethodType. Oblige it by finding or creating one.
......
...@@ -65,6 +65,16 @@ import sun.misc.Unsafe; ...@@ -65,6 +65,16 @@ import sun.misc.Unsafe;
COMPILE_THRESHOLD = (Integer) values[4]; COMPILE_THRESHOLD = (Integer) values[4];
} }
/** Tell if any of the debugging switches are turned on.
* If this is the case, it is reasonable to perform extra checks or save extra information.
*/
/*non-public*/ static boolean debugEnabled() {
return (DEBUG_METHOD_HANDLE_NAMES |
DUMP_CLASS_FILES |
TRACE_INTERPRETER |
TRACE_METHOD_LINKAGE);
}
/*non-public*/ static String getNameString(MethodHandle target, MethodType type) { /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
if (type == null) if (type == null)
type = target.type(); type = target.type();
...@@ -93,6 +103,9 @@ import sun.misc.Unsafe; ...@@ -93,6 +103,9 @@ import sun.misc.Unsafe;
} }
// handy shared exception makers (they simplify the common case code) // handy shared exception makers (they simplify the common case code)
/*non-public*/ static InternalError newInternalError(String message) {
return new InternalError(message);
}
/*non-public*/ static InternalError newInternalError(String message, Throwable cause) { /*non-public*/ static InternalError newInternalError(String message, Throwable cause) {
return new InternalError(message, cause); return new InternalError(message, cause);
} }
......
...@@ -37,13 +37,13 @@ import sun.reflect.CallerSensitive; ...@@ -37,13 +37,13 @@ import sun.reflect.CallerSensitive;
import sun.reflect.Reflection; import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil; import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants; import sun.security.util.SecurityConstants;
import java.lang.invoke.LambdaForm.BasicType;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import sun.security.util.SecurityConstants;
/** /**
* This class consists exclusively of static methods that operate on or return * This class consists exclusively of static methods that operate on or return
* method handles. They fall into several categories: * method handles. They fall into several categories:
...@@ -2202,12 +2202,12 @@ assert((int)twice.invokeExact(21) == 42); ...@@ -2202,12 +2202,12 @@ assert((int)twice.invokeExact(21) == 42);
Object value = values[i]; Object value = values[i];
Class<?> ptype = oldType.parameterType(pos+i); Class<?> ptype = oldType.parameterType(pos+i);
if (ptype.isPrimitive()) { if (ptype.isPrimitive()) {
char btype = 'I'; BasicType btype = I_TYPE;
Wrapper w = Wrapper.forPrimitiveType(ptype); Wrapper w = Wrapper.forPrimitiveType(ptype);
switch (w) { switch (w) {
case LONG: btype = 'J'; break; case LONG: btype = J_TYPE; break;
case FLOAT: btype = 'F'; break; case FLOAT: btype = F_TYPE; break;
case DOUBLE: btype = 'D'; break; case DOUBLE: btype = D_TYPE; break;
} }
// perform unboxing and/or primitive conversion // perform unboxing and/or primitive conversion
value = w.convert(value, ptype); value = w.convert(value, ptype);
...@@ -2218,7 +2218,7 @@ assert((int)twice.invokeExact(21) == 42); ...@@ -2218,7 +2218,7 @@ assert((int)twice.invokeExact(21) == 42);
if (pos == 0) { if (pos == 0) {
result = result.bindReceiver(value); result = result.bindReceiver(value);
} else { } else {
result = result.bindArgument(pos, 'L', value); result = result.bindArgument(pos, L_TYPE, value);
} }
} }
return result; return result;
......
...@@ -26,9 +26,7 @@ ...@@ -26,9 +26,7 @@
package java.lang.invoke; package java.lang.invoke;
import static java.lang.invoke.LambdaForm.*; import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.LambdaForm.BasicType.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* A method handle whose behavior is determined only by its LambdaForm. * A method handle whose behavior is determined only by its LambdaForm.
...@@ -44,7 +42,7 @@ final class SimpleMethodHandle extends MethodHandle { ...@@ -44,7 +42,7 @@ final class SimpleMethodHandle extends MethodHandle {
} }
@Override @Override
MethodHandle bindArgument(int pos, char basicType, Object value) { MethodHandle bindArgument(int pos, BasicType basicType, Object value) {
MethodType type2 = type().dropParameterTypes(pos, pos+1); MethodType type2 = type().dropParameterTypes(pos, pos+1);
LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY); LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY);
return BoundMethodHandle.bindSingle(type2, form2, basicType, value); return BoundMethodHandle.bindSingle(type2, form2, basicType, value);
...@@ -61,10 +59,4 @@ final class SimpleMethodHandle extends MethodHandle { ...@@ -61,10 +59,4 @@ final class SimpleMethodHandle extends MethodHandle {
LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList())); LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList()));
return new SimpleMethodHandle(newType, form2); return new SimpleMethodHandle(newType, form2);
} }
@Override
MethodHandle copyWith(MethodType mt, LambdaForm lf) {
return new SimpleMethodHandle(mt, lf);
}
} }
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @summary unit tests for java.lang.invoke.LambdaForm
* @run junit/othervm test.java.lang.invoke.LambdaFormTest
*/
package test.java.lang.invoke;
import org.junit.Test;
import java.lang.reflect.Method;
import static org.junit.Assert.*;
public class LambdaFormTest {
static final Method M_shortenSignature;
static {
try {
Class<?> impl = Class.forName("java.lang.invoke.LambdaForm", false, null);
Method m = impl.getDeclaredMethod("shortenSignature", String.class);
m.setAccessible(true);
M_shortenSignature = m;
} catch(Exception e) {
throw new AssertionError(e);
}
}
public static String shortenSignature(String signature) throws ReflectiveOperationException {
return (String)M_shortenSignature.invoke(null, signature);
}
@Test
public void testShortenSignature() throws ReflectiveOperationException {
for (String s : new String[] {
// invariant strings:
"L", "LL", "ILL", "LIL", "LLI", "IILL", "ILIL", "ILLI",
// a few mappings:
"LLL=L3", "LLLL=L4", "LLLLLLLLLL=L10",
"IIIDDD=I3D3", "IDDD=ID3", "IIDDD=IID3", "IIID=I3D", "IIIDD=I3DD"
}) {
String s2 = s.substring(s.indexOf('=')+1);
String s1 = s.equals(s2) ? s : s.substring(0, s.length() - s2.length() - 1);
// mix the above cases with before and after reps of Z*
for (int k = -3; k <= 3; k++) {
String beg = (k < 0 ? "ZZZZ".substring(-k) : "");
String end = (k > 0 ? "ZZZZ".substring(+k) : "");
String ks1 = beg+s1+end;
String ks2 = shortenSignature(beg)+s2+shortenSignature(end);
String ks3 = shortenSignature(ks1);
assertEquals(ks2, ks3);
}
}
}
public static void main(String[] args) throws ReflectiveOperationException {
LambdaFormTest test = new LambdaFormTest();
test.testShortenSignature();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册