提交 7e35994f 编写于 作者: V vlivanov

8038261: JSR292: cache and reuse typed array accessors

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 5cdd5a30
...@@ -35,6 +35,7 @@ import static java.lang.invoke.LambdaForm.*; ...@@ -35,6 +35,7 @@ import static java.lang.invoke.LambdaForm.*;
import static 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.lang.invoke.MethodHandleImpl.ArrayAccessor;
import sun.invoke.util.ValueConversions; import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyAccess; import sun.invoke.util.VerifyAccess;
import sun.invoke.util.VerifyType; import sun.invoke.util.VerifyType;
...@@ -427,6 +428,40 @@ class InvokerBytecodeGenerator { ...@@ -427,6 +428,40 @@ class InvokerBytecodeGenerator {
emitStoreInsn(L_TYPE, index); emitStoreInsn(L_TYPE, index);
} }
private byte arrayTypeCode(Wrapper elementType) {
switch (elementType) {
case BOOLEAN: return Opcodes.T_BOOLEAN;
case BYTE: return Opcodes.T_BYTE;
case CHAR: return Opcodes.T_CHAR;
case SHORT: return Opcodes.T_SHORT;
case INT: return Opcodes.T_INT;
case LONG: return Opcodes.T_LONG;
case FLOAT: return Opcodes.T_FLOAT;
case DOUBLE: return Opcodes.T_DOUBLE;
case OBJECT: return 0; // in place of Opcodes.T_OBJECT
default: throw new InternalError();
}
}
private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
int xas;
switch (tcode) {
case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
case Opcodes.T_BYTE: xas = Opcodes.BASTORE; break;
case Opcodes.T_CHAR: xas = Opcodes.CASTORE; break;
case Opcodes.T_SHORT: xas = Opcodes.SASTORE; break;
case Opcodes.T_INT: xas = Opcodes.IASTORE; break;
case Opcodes.T_LONG: xas = Opcodes.LASTORE; break;
case Opcodes.T_FLOAT: xas = Opcodes.FASTORE; break;
case Opcodes.T_DOUBLE: xas = Opcodes.DASTORE; break;
case 0: xas = Opcodes.AASTORE; break;
default: throw new InternalError();
}
return xas - Opcodes.AASTORE + aaop;
}
private void freeFrameLocal(int oldFrameLocal) { private void freeFrameLocal(int oldFrameLocal) {
int i = indexForFrameLocal(oldFrameLocal); int i = indexForFrameLocal(oldFrameLocal);
if (i < 0) return; if (i < 0) return;
...@@ -616,6 +651,10 @@ class InvokerBytecodeGenerator { ...@@ -616,6 +651,10 @@ class InvokerBytecodeGenerator {
i = i+2; // Jump to the end of GWC idiom i = i+2; // Jump to the end of GWC idiom
} else if (isNewArray(rtype, name)) { } else if (isNewArray(rtype, name)) {
emitNewArray(rtype, name); emitNewArray(rtype, name);
} else if (isArrayLoad(member)) {
emitArrayLoad(name);
} else if (isArrayStore(member)) {
emitArrayStore(name);
} else if (isStaticallyInvocable(member)) { } else if (isStaticallyInvocable(member)) {
emitStaticInvoke(name); emitStaticInvoke(name);
} else { } else {
...@@ -634,6 +673,35 @@ class InvokerBytecodeGenerator { ...@@ -634,6 +673,35 @@ class InvokerBytecodeGenerator {
return classFile; return classFile;
} }
boolean isArrayLoad(MemberName member) {
return member != null &&
member.getDeclaringClass() == ArrayAccessor.class &&
member.getName() != null &&
member.getName().startsWith("getElement");
}
boolean isArrayStore(MemberName member) {
return member != null &&
member.getDeclaringClass() == ArrayAccessor.class &&
member.getName() != null &&
member.getName().startsWith("setElement");
}
void emitArrayLoad(Name name) { emitArrayOp(name, Opcodes.AALOAD); }
void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
void emitArrayOp(Name name, int arrayOpcode) {
assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
assert elementType != null;
emitPushArguments(name);
if (elementType.isPrimitive()) {
Wrapper w = Wrapper.forPrimitiveType(elementType);
arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
}
mv.visitInsn(arrayOpcode);
}
/** /**
* Emit an invoke for the given name. * Emit an invoke for the given name.
*/ */
......
...@@ -52,27 +52,54 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -52,27 +52,54 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) { static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
if (arrayClass == Object[].class)
return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER);
if (!arrayClass.isArray()) if (!arrayClass.isArray())
throw newIllegalArgumentException("not an array: "+arrayClass); throw newIllegalArgumentException("not an array: "+arrayClass);
MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter); MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
MethodType srcType = accessor.type().erase(); int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX);
MethodType lambdaType = srcType.invokerType(); MethodHandle mh = cache[cacheIndex];
Name[] names = arguments(1, lambdaType); if (mh != null) return mh;
Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount()); mh = ArrayAccessor.getAccessor(arrayClass, isSetter);
names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args); MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter);
LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names); if (mh.type() != correctType) {
MethodHandle mh = SimpleMethodHandle.make(srcType, form); assert(mh.type().parameterType(0) == Object[].class);
if (ArrayAccessor.needCast(arrayClass)) { assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class);
mh = mh.bindTo(arrayClass); assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType());
} // safe to view non-strictly, because element type follows from array type
mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter)); mh = mh.viewAsType(correctType);
}
// Atomically update accessor cache.
synchronized(cache) {
if (cache[cacheIndex] == null) {
cache[cacheIndex] = mh;
} else {
// Throw away newly constructed accessor and use cached version.
mh = cache[cacheIndex];
}
}
return mh; return mh;
} }
static final class ArrayAccessor { static final class ArrayAccessor {
/// Support for array element access /// Support for array element access
static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2;
static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it static final ClassValue<MethodHandle[]> TYPED_ACCESSORS
= new ClassValue<MethodHandle[]>() {
@Override
protected MethodHandle[] computeValue(Class<?> type) {
return new MethodHandle[INDEX_LIMIT];
}
};
static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
static {
MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = getAccessor(Object[].class, false);
cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = getAccessor(Object[].class, true);
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
}
static int getElementI(int[] a, int i) { return a[i]; } static int getElementI(int[] a, int i) { return a[i]; }
static long getElementJ(long[] a, int i) { return a[i]; } static long getElementJ(long[] a, int i) { return a[i]; }
...@@ -94,45 +121,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -94,45 +121,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static void setElementC(char[] a, int i, char x) { a[i] = x; } static void setElementC(char[] a, int i, char x) { a[i] = x; }
static void setElementL(Object[] a, int i, Object x) { a[i] = x; } static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
static Object getElementL(Class<?> arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; }
static void setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
// Weakly typed wrappers of Object[] accessors:
static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); }
static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); }
static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
static boolean needCast(Class<?> arrayClass) {
Class<?> elemClass = arrayClass.getComponentType();
return !elemClass.isPrimitive() && elemClass != Object.class;
}
static String name(Class<?> arrayClass, boolean isSetter) { static String name(Class<?> arrayClass, boolean isSetter) {
Class<?> elemClass = arrayClass.getComponentType(); Class<?> elemClass = arrayClass.getComponentType();
if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass);
return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
} }
static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
static MethodType type(Class<?> arrayClass, boolean isSetter) { static MethodType type(Class<?> arrayClass, boolean isSetter) {
Class<?> elemClass = arrayClass.getComponentType(); Class<?> elemClass = arrayClass.getComponentType();
Class<?> arrayArgClass = arrayClass; Class<?> arrayArgClass = arrayClass;
if (!elemClass.isPrimitive()) { if (!elemClass.isPrimitive()) {
arrayArgClass = Object[].class; arrayArgClass = Object[].class;
if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS) elemClass = Object.class;
arrayArgClass = Object.class;
} }
if (!needCast(arrayClass)) { return !isSetter ?
return !isSetter ?
MethodType.methodType(elemClass, arrayArgClass, int.class) : MethodType.methodType(elemClass, arrayArgClass, int.class) :
MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
} else {
Class<?> classArgClass = Class.class;
if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
classArgClass = Object.class;
return !isSetter ?
MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class);
}
} }
static MethodType correctType(Class<?> arrayClass, boolean isSetter) { static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
Class<?> elemClass = arrayClass.getComponentType(); Class<?> elemClass = arrayClass.getComponentType();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册