--- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Aug 24 13:54:17 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Aug 24 16:09:34 2016 +0200
@@ -492,7 +492,7 @@
}
// Caching machinery for field accessors:
- private static final byte
+ static final byte
AF_GETFIELD = 0,
AF_PUTFIELD = 1,
AF_GETSTATIC = 2,
@@ -502,7 +502,7 @@
AF_LIMIT = 6;
// Enumerate the different field kinds using Wrapper,
// with an extra case added for checked references.
- private static final int
+ static final int
FT_LAST_WRAPPER = Wrapper.COUNT-1,
FT_UNCHECKED_REF = Wrapper.OBJECT.ordinal(),
FT_CHECKED_REF = FT_LAST_WRAPPER+1,
@@ -515,7 +515,7 @@
@Stable
private static final LambdaForm[] ACCESSOR_FORMS
= new LambdaForm[afIndex(AF_LIMIT, false, 0)];
- private static int ftypeKind(Class<?> ftype) {
+ static int ftypeKind(Class<?> ftype) {
if (ftype.isPrimitive())
return Wrapper.forPrimitiveType(ftype).ordinal();
else if (VerifyType.isNullReferenceConversion(Object.class, ftype))
@@ -566,7 +566,64 @@
private static final Wrapper[] ALL_WRAPPERS = Wrapper.values();
- private static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
+ private static Kind getFieldKind(boolean isGetter, boolean isVolatile, Wrapper wrapper) {
+ if (isGetter) {
+ if (isVolatile) {
+ switch (wrapper) {
+ case BOOLEAN: return GET_BOOLEAN_VOLATILE;
+ case BYTE: return GET_BYTE_VOLATILE;
+ case SHORT: return GET_SHORT_VOLATILE;
+ case CHAR: return GET_CHAR_VOLATILE;
+ case INT: return GET_INT_VOLATILE;
+ case LONG: return GET_LONG_VOLATILE;
+ case FLOAT: return GET_FLOAT_VOLATILE;
+ case DOUBLE: return GET_DOUBLE_VOLATILE;
+ case OBJECT: return GET_OBJECT_VOLATILE;
+ }
+ } else {
+ switch (wrapper) {
+ case BOOLEAN: return GET_BOOLEAN;
+ case BYTE: return GET_BYTE;
+ case SHORT: return GET_SHORT;
+ case CHAR: return GET_CHAR;
+ case INT: return GET_INT;
+ case LONG: return GET_LONG;
+ case FLOAT: return GET_FLOAT;
+ case DOUBLE: return GET_DOUBLE;
+ case OBJECT: return GET_OBJECT;
+ }
+ }
+ } else {
+ if (isVolatile) {
+ switch (wrapper) {
+ case BOOLEAN: return PUT_BOOLEAN_VOLATILE;
+ case BYTE: return PUT_BYTE_VOLATILE;
+ case SHORT: return PUT_SHORT_VOLATILE;
+ case CHAR: return PUT_CHAR_VOLATILE;
+ case INT: return PUT_INT_VOLATILE;
+ case LONG: return PUT_LONG_VOLATILE;
+ case FLOAT: return PUT_FLOAT_VOLATILE;
+ case DOUBLE: return PUT_DOUBLE_VOLATILE;
+ case OBJECT: return PUT_OBJECT_VOLATILE;
+ }
+ } else {
+ switch (wrapper) {
+ case BOOLEAN: return PUT_BOOLEAN;
+ case BYTE: return PUT_BYTE;
+ case SHORT: return PUT_SHORT;
+ case CHAR: return PUT_CHAR;
+ case INT: return PUT_INT;
+ case LONG: return PUT_LONG;
+ case FLOAT: return PUT_FLOAT;
+ case DOUBLE: return PUT_DOUBLE;
+ case OBJECT: return PUT_OBJECT;
+ }
+ }
+ }
+ throw new AssertionError("Invalid arguments");
+ }
+
+ static LambdaForm makePreparedFieldLambdaForm(byte formOp, boolean isVolatile, int ftypeKind) {
boolean isGetter = (formOp & 1) == (AF_GETFIELD & 1);
boolean isStatic = (formOp >= AF_GETSTATIC);
boolean needsInit = (formOp >= AF_GETSTATIC_INIT);
@@ -576,24 +633,14 @@
assert(ftypeKind(needsCast ? String.class : ft) == ftypeKind);
// getObject, putIntVolatile, etc.
- StringBuilder nameBuilder = new StringBuilder();
- if (isGetter) {
- nameBuilder.append("get");
- } else {
- nameBuilder.append("put");
- }
- nameBuilder.append(fw.primitiveSimpleName());
- nameBuilder.setCharAt(3, Character.toUpperCase(nameBuilder.charAt(3)));
- if (isVolatile) {
- nameBuilder.append("Volatile");
- }
+ Kind kind = getFieldKind(isGetter, isVolatile, fw);
MethodType linkerType;
if (isGetter)
linkerType = MethodType.methodType(ft, Object.class, long.class);
else
linkerType = MethodType.methodType(void.class, Object.class, long.class, ft);
- MemberName linker = new MemberName(Unsafe.class, nameBuilder.toString(), linkerType, REF_invokeVirtual);
+ MemberName linker = new MemberName(Unsafe.class, kind.methodName, linkerType, REF_invokeVirtual);
try {
linker = IMPL_NAMES.resolveOrFail(REF_invokeVirtual, linker, null, NoSuchMethodException.class);
} catch (ReflectiveOperationException ex) {
@@ -620,6 +667,7 @@
final int F_HOLDER = (isStatic ? nameCursor++ : -1); // static base if any
final int F_OFFSET = nameCursor++; // Either static offset or field offset.
final int OBJ_CHECK = (OBJ_BASE >= 0 ? nameCursor++ : -1);
+ final int U_HOLDER = nameCursor++; // UNSAFE holder
final int INIT_BAR = (needsInit ? nameCursor++ : -1);
final int PRE_CAST = (needsCast && !isGetter ? nameCursor++ : -1);
final int LINKER_CALL = nameCursor++;
@@ -632,7 +680,7 @@
names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
assert(outArgs.length == (isGetter ? 3 : 4));
- outArgs[0] = UNSAFE;
+ outArgs[0] = names[U_HOLDER] = new Name(NF_UNSAFE);
if (isStatic) {
outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]);
outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
@@ -650,6 +698,7 @@
for (Name n : names) assert(n != null);
// add some detail to the lambdaForm debugname,
// significant only for debugging
+ StringBuilder nameBuilder = new StringBuilder(kind.methodName);
if (isStatic) {
nameBuilder.append("Static");
} else {
@@ -657,7 +706,12 @@
}
if (needsCast) nameBuilder.append("Cast");
if (needsInit) nameBuilder.append("Init");
- return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT);
+ if (needsCast || needsInit) {
+ // can't use the pre-generated form when casting and/or initializing
+ return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT);
+ } else {
+ return new LambdaForm(nameBuilder.toString(), ARG_LIMIT, names, RESULT, kind);
+ }
}
/**
@@ -674,7 +728,8 @@
NF_staticOffset,
NF_checkCast,
NF_allocateInstance,
- NF_constructorMethod;
+ NF_constructorMethod,
+ NF_UNSAFE;
static {
try {
NamedFunction nfs[] = {
@@ -697,7 +752,9 @@
NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
.getDeclaredMethod("allocateInstance", Object.class)),
NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("constructorMethod", Object.class))
+ .getDeclaredMethod("constructorMethod", Object.class)),
+ NF_UNSAFE = new NamedFunction(new MemberName(MethodHandleStatics.class
+ .getDeclaredField("UNSAFE")))
};
// Each nf must be statically invocable or we get tied up in our bootstraps.
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
--- a/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Aug 24 13:54:17 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Aug 24 16:09:34 2016 +0200
@@ -28,9 +28,11 @@
import java.util.Map;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
-
import java.util.ArrayList;
import java.util.HashSet;
+import sun.invoke.util.Wrapper;
+
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
/**
* Helper class to assist the GenerateJLIClassesPlugin to get access to
@@ -66,14 +68,38 @@
static byte[] generateDirectMethodHandleHolderClassBytes(String className,
MethodType[] methodTypes, int[] types) {
- LambdaForm[] forms = new LambdaForm[methodTypes.length];
- String[] names = new String[methodTypes.length];
- for (int i = 0; i < forms.length; i++) {
- forms[i] = DirectMethodHandle.makePreparedLambdaForm(methodTypes[i],
- types[i]);
- names[i] = forms[i].kind.defaultLambdaName;
+ ArrayList<LambdaForm> forms = new ArrayList<>();
+ ArrayList<String> names = new ArrayList<>();
+ for (int i = 0; i < methodTypes.length; i++) {
+ LambdaForm form = DirectMethodHandle
+ .makePreparedLambdaForm(methodTypes[i], types[i]);
+ forms.add(form);
+ names.add(form.kind.defaultLambdaName);
}
- return generateCodeBytesForLFs(className, names, forms);
+ for (Wrapper wrapper : Wrapper.values()) {
+ if (wrapper == Wrapper.VOID) {
+ continue;
+ }
+ for (byte b = DirectMethodHandle.AF_GETFIELD; b < DirectMethodHandle.AF_LIMIT; b++) {
+ int ftype = DirectMethodHandle.ftypeKind(wrapper.primitiveType());
+ LambdaForm form = DirectMethodHandle
+ .makePreparedFieldLambdaForm(b, /*isVolatile*/false, ftype);
+ if (form.kind != LambdaForm.Kind.GENERIC) {
+ forms.add(form);
+ names.add(form.kind.defaultLambdaName);
+ }
+ // volatile
+ form = DirectMethodHandle
+ .makePreparedFieldLambdaForm(b, /*isVolatile*/true, ftype);
+ if (form.kind != LambdaForm.Kind.GENERIC) {
+ forms.add(form);
+ names.add(form.kind.defaultLambdaName);
+ }
+ }
+ }
+ return generateCodeBytesForLFs(className,
+ names.toArray(new String[0]),
+ forms.toArray(new LambdaForm[0]));
}
static byte[] generateDelegatingMethodHandleHolderClassBytes(String className,
@@ -166,4 +192,5 @@
BoundMethodHandle.Factory.generateConcreteBMHClassBytes(
shortTypes, types, className));
}
+
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Aug 24 13:54:17 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Aug 24 16:09:34 2016 +0200
@@ -629,6 +629,24 @@
name = name + "_" + form.returnType().basicTypeChar();
return resolveFrom(name, invokerType, LambdaForm.Holder.class);
}
+ case GET_OBJECT: // fall-through
+ case GET_BOOLEAN: // fall-through
+ case GET_BYTE: // fall-through
+ case GET_CHAR: // fall-through
+ case GET_SHORT: // fall-through
+ case GET_INT: // fall-through
+ case GET_LONG: // fall-through
+ case GET_FLOAT: // fall-through
+ case GET_DOUBLE: // fall-through
+ case PUT_OBJECT: // fall-through
+ case PUT_BOOLEAN: // fall-through
+ case PUT_BYTE: // fall-through
+ case PUT_CHAR: // fall-through
+ case PUT_SHORT: // fall-through
+ case PUT_INT: // fall-through
+ case PUT_LONG: // fall-through
+ case PUT_FLOAT: // fall-through
+ case PUT_DOUBLE: // fall-through
case DIRECT_INVOKE_INTERFACE: // fall-through
case DIRECT_INVOKE_SPECIAL: // fall-through
case DIRECT_INVOKE_STATIC: // fall-through
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug 24 13:54:17 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Wed Aug 24 16:09:34 2016 +0200
@@ -280,7 +280,43 @@
DIRECT_INVOKE_STATIC("DMH.invokeStatic"),
DIRECT_NEW_INVOKE_SPECIAL("DMH.newInvokeSpecial"),
DIRECT_INVOKE_INTERFACE("DMH.invokeInterface"),
- DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit");
+ DIRECT_INVOKE_STATIC_INIT("DMH.invokeStaticInit"),
+ GET_OBJECT("getObject"),
+ PUT_OBJECT("putObject"),
+ GET_OBJECT_VOLATILE("getObjectVolatile"),
+ PUT_OBJECT_VOLATILE("putObjectVolatile"),
+ GET_INT("getInt"),
+ PUT_INT("putInt"),
+ GET_INT_VOLATILE("getIntVolatile"),
+ PUT_INT_VOLATILE("putIntVolatile"),
+ GET_BOOLEAN("getBoolean"),
+ PUT_BOOLEAN("putBoolean"),
+ GET_BOOLEAN_VOLATILE("getBooleanVolatile"),
+ PUT_BOOLEAN_VOLATILE("putBooleanVolatile"),
+ GET_BYTE("getByte"),
+ PUT_BYTE("putByte"),
+ GET_BYTE_VOLATILE("getByteVolatile"),
+ PUT_BYTE_VOLATILE("putByteVolatile"),
+ GET_CHAR("getChar"),
+ PUT_CHAR("putChar"),
+ GET_CHAR_VOLATILE("getCharVolatile"),
+ PUT_CHAR_VOLATILE("putCharVolatile"),
+ GET_SHORT("getShort"),
+ PUT_SHORT("putShort"),
+ GET_SHORT_VOLATILE("getShortVolatile"),
+ PUT_SHORT_VOLATILE("putShortVolatile"),
+ GET_LONG("getLong"),
+ PUT_LONG("putLong"),
+ GET_LONG_VOLATILE("getLongVolatile"),
+ PUT_LONG_VOLATILE("putLongVolatile"),
+ GET_FLOAT("getFloat"),
+ PUT_FLOAT("putFloat"),
+ GET_FLOAT_VOLATILE("getFloatVolatile"),
+ PUT_FLOAT_VOLATILE("putFloatVolatile"),
+ GET_DOUBLE("getDouble"),
+ PUT_DOUBLE("putDouble"),
+ GET_DOUBLE_VOLATILE("getDoubleVolatile"),
+ PUT_DOUBLE_VOLATILE("putDoubleVolatile");
final String defaultLambdaName;
final String methodName;