--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Sep 10 19:19:49 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Sep 10 19:19:50 2014 +0400
@@ -35,7 +35,7 @@
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
-import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
+
import sun.invoke.util.VerifyAccess;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
@@ -636,26 +636,44 @@
Name onStack = null;
for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
Name name = lambdaForm.names[i];
- MemberName member = name.function.member();
- Class<?> rtype = name.function.methodType().returnType();
emitStoreResult(onStack);
onStack = name; // unless otherwise modified below
+ MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
+ switch (intr) {
+ case SELECT_ALTERNATIVE:
+ assert isSelectAlternative(i);
+ onStack = emitSelectAlternative(name, lambdaForm.names[i+1]);
+ i++; // skip MH.invokeBasic of the selectAlternative result
+ continue;
+ case GUARD_WITH_CATCH:
+ assert isGuardWithCatch(i);
+ onStack = emitGuardWithCatch(i);
+ i = i+2; // Jump to the end of GWC idiom
+ continue;
+ case NEW_ARRAY:
+ Class<?> rtype = name.function.methodType().returnType();
+ if (isStaticallyNameable(rtype)) {
+ emitNewArray(name);
+ continue;
+ }
+ break;
+ case ARRAY_LOAD:
+ emitArrayLoad(name);
+ continue;
+ case ARRAY_STORE:
+ emitArrayStore(name);
+ continue;
+ case NONE:
+ // no intrinsic associated
+ break;
+ default:
+ throw newInternalError("Unknown intrinsic: "+intr);
+ }
- if (isSelectAlternative(i)) {
- onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
- i++; // skip MH.invokeBasic of the selectAlternative result
- } else if (isGuardWithCatch(i)) {
- onStack = emitGuardWithCatch(i);
- i = i+2; // Jump to the end of GWC idiom
- } else if (isNewArray(rtype, name)) {
- emitNewArray(rtype, name);
- } else if (isArrayLoad(member)) {
- emitArrayLoad(name);
- } else if (isArrayStore(member)) {
- emitArrayStore(name);
- } else if (isStaticallyInvocable(member)) {
- emitStaticInvoke(name);
+ MemberName member = name.function.member();
+ if (isStaticallyInvocable(member)) {
+ emitStaticInvoke(member, name);
} else {
emitInvoke(name);
}
@@ -672,20 +690,6 @@
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); }
@@ -837,33 +841,31 @@
}
}
- boolean isNewArray(Class<?> rtype, Name name) {
- return rtype.isArray() &&
- isStaticallyNameable(rtype) &&
- isArrayBuilder(name.function.resolvedHandle) &&
- name.arguments.length > 0;
- }
-
- void emitNewArray(Class<?> rtype, Name name) throws InternalError {
+ void emitNewArray(Name name) throws InternalError {
+ Class<?> rtype = name.function.methodType().returnType();
+ if (name.arguments.length == 0) {
+ // The array will be a constant.
+ Object emptyArray;
+ try {
+ emptyArray = name.function.resolvedHandle.invoke();
+ } catch (Throwable ex) {
+ throw newInternalError(ex);
+ }
+ assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
+ assert(emptyArray.getClass() == rtype); // exact typing
+ mv.visitLdcInsn(constantPlaceholder(emptyArray));
+ emitReferenceCast(rtype, emptyArray);
+ return;
+ }
Class<?> arrayElementType = rtype.getComponentType();
+ assert(arrayElementType != null);
emitIconstInsn(name.arguments.length);
- int xas;
+ int xas = Opcodes.AASTORE;
if (!arrayElementType.isPrimitive()) {
mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
- xas = Opcodes.AASTORE;
} else {
- int tc;
- switch (Wrapper.forPrimitiveType(arrayElementType)) {
- case BOOLEAN: tc = Opcodes.T_BOOLEAN; xas = Opcodes.BASTORE; break;
- case BYTE: tc = Opcodes.T_BYTE; xas = Opcodes.BASTORE; break;
- case CHAR: tc = Opcodes.T_CHAR; xas = Opcodes.CASTORE; break;
- case SHORT: tc = Opcodes.T_SHORT; xas = Opcodes.SASTORE; break;
- case INT: tc = Opcodes.T_INT; xas = Opcodes.IASTORE; break;
- case LONG: tc = Opcodes.T_LONG; xas = Opcodes.LASTORE; break;
- case FLOAT: tc = Opcodes.T_FLOAT; xas = Opcodes.FASTORE; break;
- case DOUBLE: tc = Opcodes.T_DOUBLE; xas = Opcodes.DASTORE; break;
- default: throw new InternalError(rtype.getName());
- }
+ byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
+ xas = arrayInsnOpcode(tc, xas);
mv.visitIntInsn(Opcodes.NEWARRAY, tc);
}
// store arguments
@@ -890,24 +892,6 @@
throw new InternalError("refKind="+refKind);
}
- static boolean isArrayBuilder(MethodHandle fn) {
- if (fn == null)
- return false;
- MethodType mtype = fn.type();
- Class<?> rtype = mtype.returnType();
- Class<?> arrayElementType = rtype.getComponentType();
- if (arrayElementType == null)
- return false;
- List<Class<?>> ptypes = mtype.parameterList();
- int size = ptypes.size();
- if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
- return false;
- // Assume varargsArray caches pointers.
- if (fn != MethodHandleImpl.varargsArray(rtype, size))
- return false;
- return true;
- }
-
/**
* Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
*/
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:49 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:50 2014 +0400
@@ -30,7 +30,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
@@ -86,6 +85,7 @@
// safe to view non-strictly, because element type follows from array type
mh = mh.viewAsType(correctType, false);
}
+ mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD));
// Atomically update accessor cache.
synchronized(cache) {
if (cache[cacheIndex] == null) {
@@ -111,8 +111,8 @@
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);
+ cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD);
+ cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE);
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
@@ -502,10 +502,10 @@
static final NamedFunction NF_checkSpreadArgument;
static final NamedFunction NF_guardWithCatch;
- static final NamedFunction NF_selectAlternative;
static final NamedFunction NF_throwException;
static final MethodHandle MH_castReference;
+ static final MethodHandle MH_selectAlternative;
static final MethodHandle MH_copyAsPrimitiveArray;
static final MethodHandle MH_fillNewTypedArray;
static final MethodHandle MH_fillNewArray;
@@ -516,13 +516,10 @@
NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
MethodHandle.class, Object[].class));
- NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
- MethodHandle.class));
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
NF_checkSpreadArgument.resolve();
NF_guardWithCatch.resolve();
- NF_selectAlternative.resolve();
NF_throwException.resolve();
MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
@@ -535,6 +532,11 @@
MethodType.methodType(Object[].class, Integer.class, Object[].class));
MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
+
+ MH_selectAlternative = makeIntrinsic(
+ IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
+ MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
+ Intrinsic.SELECT_ALTERNATIVE);
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
@@ -620,7 +622,7 @@
// call selectAlternative
Object[] selectArgs = { names[arity + 1], target, fallback };
- names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs);
+ names[arity + 2] = new Name(Lazy.MH_selectAlternative, selectArgs);
targetArgs[0] = names[arity + 2];
// call target or fallback
@@ -689,7 +691,7 @@
Object[] args = new Object[invokeBasic.type().parameterCount()];
args[0] = names[GET_COLLECT_ARGS];
System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
- names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args);
+ names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args);
// t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
@@ -698,7 +700,7 @@
// t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
- names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs);
+ names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
@@ -1004,6 +1006,63 @@
return new WrappedMember(target, target.type(), member, isInvokeSpecial, null);
}
+ /** Intrinsic IDs */
+ /*non-public*/
+ enum Intrinsic {
+ SELECT_ALTERNATIVE,
+ GUARD_WITH_CATCH,
+ NEW_ARRAY,
+ ARRAY_LOAD,
+ ARRAY_STORE,
+ NONE // no intrinsic associated
+ }
+
+ /** Mark arbitrary method handle as intrinsic.
+ * InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */
+ private static final class IntrinsicMethodHandle extends DelegatingMethodHandle {
+ private final MethodHandle target;
+ private final Intrinsic intrinsicName;
+
+ IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) {
+ super(target.type(), target);
+ this.target = target;
+ this.intrinsicName = intrinsicName;
+ }
+
+ @Override
+ protected MethodHandle getTarget() {
+ return target;
+ }
+
+ @Override
+ Intrinsic intrinsicName() {
+ return intrinsicName;
+ }
+
+ @Override
+ public MethodHandle asTypeUncached(MethodType newType) {
+ // This MH is an alias for target, except for the intrinsic name
+ // Drop the name if there is any conversion.
+ return asTypeCache = target.asType(newType);
+ }
+
+ @Override
+ String internalProperties() {
+ return super.internalProperties() +
+ "\n& Intrinsic="+intrinsicName;
+ }
+ }
+
+ static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) {
+ if (intrinsicName == target.intrinsicName())
+ return target;
+ return new IntrinsicMethodHandle(target, intrinsicName);
+ }
+
+ static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) {
+ return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName);
+ }
+
/// Collection of multiple arguments.
private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
@@ -1053,6 +1112,7 @@
for (;;) {
MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
if (mh == null) break;
+ mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
mhs.add(mh);
}
assert(mhs.size() == 11); // current number of methods
@@ -1131,9 +1191,11 @@
MethodHandle mh = ARRAYS[nargs];
if (mh != null) return mh;
mh = findCollector("array", nargs, Object[].class);
+ if (mh != null) mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
if (mh != null) return ARRAYS[nargs] = mh;
mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
assert(assertCorrectArity(mh, nargs));
+ mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
return ARRAYS[nargs] = mh;
}
@@ -1263,6 +1325,7 @@
mh = buildVarargsArray(builder, producer, nargs);
}
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
+ mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
assert(assertCorrectArity(mh, nargs));
if (nargs < cache.length)
cache[nargs] = mh;