Mercurial > hg > shenandoah-preopenjdk-archive > openjdk8 > jdk
changeset 9985:c7be76a1dda5
8050166: Get rid of some package-private methods on arguments in j.l.i.MethodHandle
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
author | vlivanov |
---|---|
date | Wed, 10 Sep 2014 18:34:02 +0400 |
parents | f66dc99dac52 |
children | 9cfb4b22a01e |
files | src/share/classes/java/lang/invoke/BoundMethodHandle.java src/share/classes/java/lang/invoke/CallSite.java src/share/classes/java/lang/invoke/DirectMethodHandle.java src/share/classes/java/lang/invoke/MethodHandle.java src/share/classes/java/lang/invoke/MethodHandleImpl.java src/share/classes/java/lang/invoke/MethodHandles.java src/share/classes/java/lang/invoke/MethodType.java src/share/classes/java/lang/invoke/SimpleMethodHandle.java |
diffstat | 8 files changed, 152 insertions(+), 200 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 @@ -60,13 +60,12 @@ // BMH API and internals // - static MethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { + static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) { // for some type signatures, there exist pre-defined concrete BMH classes try { switch (xtype) { case L_TYPE: - if (true) return bindSingle(type, form, x); // Use known fast path. - return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(L_TYPE).constructor().invokeBasic(type, form, x); + return bindSingle(type, form, x); // Use known fast path. case I_TYPE: return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x)); case J_TYPE: @@ -82,49 +81,40 @@ } } - static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) { - return new Species_L(type, form, x); - } - - MethodHandle cloneExtend(MethodType type, LambdaForm form, BasicType xtype, Object x) { - try { - switch (xtype) { - case L_TYPE: return copyWithExtendL(type, form, x); - case I_TYPE: return copyWithExtendI(type, form, ValueConversions.widenSubword(x)); - case J_TYPE: return copyWithExtendJ(type, form, (long) x); - case F_TYPE: return copyWithExtendF(type, form, (float) x); - case D_TYPE: return copyWithExtendD(type, form, (double) x); - } - } catch (Throwable t) { - throw newInternalError(t); - } - throw newInternalError("unexpected type: " + xtype); + static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) { + return Species_L.make(type, form, x); } - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { + @Override // there is a default binder in the super class, for 'L' types only + /*non-public*/ + BoundMethodHandle bindArgumentL(int pos, Object value) { + MethodType type = type().dropParameterTypes(pos, pos+1); + LambdaForm form = internalForm().bind(1+pos, speciesData()); + return copyWithExtendL(type, form, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentI(int pos, int value) { MethodType type = type().dropParameterTypes(pos, pos+1); LambdaForm form = internalForm().bind(1+pos, speciesData()); - return cloneExtend(type, form, basicType, value); + return copyWithExtendI(type, form, value); + } + /*non-public*/ + BoundMethodHandle bindArgumentJ(int pos, long value) { + MethodType type = type().dropParameterTypes(pos, pos+1); + LambdaForm form = internalForm().bind(1+pos, speciesData()); + return copyWithExtendJ(type, form, value); } - - @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos + drops)); - try { - return copyWith(srcType, form); - } catch (Throwable t) { - throw newInternalError(t); - } + /*non-public*/ + BoundMethodHandle bindArgumentF(int pos, float value) { + MethodType type = type().dropParameterTypes(pos, pos+1); + LambdaForm form = internalForm().bind(1+pos, speciesData()); + return copyWithExtendF(type, form, value); } - - @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - try { - return copyWith(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList()))); - } catch (Throwable t) { - throw newInternalError(t); - } + /*non-public*/ + BoundMethodHandle bindArgumentD(int pos, double value) { + MethodType type = type().dropParameterTypes(pos, pos + 1); + LambdaForm form = internalForm().bind(1+pos, speciesData()); + return copyWithExtendD(type, form, value); } /**
--- a/src/share/classes/java/lang/invoke/CallSite.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/CallSite.java Wed Sep 10 18:34:02 2014 +0400 @@ -211,7 +211,7 @@ public abstract MethodHandle dynamicInvoker(); /*non-public*/ MethodHandle makeDynamicInvoker() { - MethodHandle getTarget = GET_TARGET.bindReceiver(this); + MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this); MethodHandle invoker = MethodHandles.exactInvoker(this.type()); return MethodHandles.foldArguments(invoker, getTarget); }
--- a/src/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 @@ -142,45 +142,8 @@ return member; } - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - // If the member needs dispatching, do so. - if (pos == 0 && basicType == L_TYPE) { - DirectMethodHandle concrete = maybeRebind(value); - if (concrete != null) - return concrete.bindReceiver(value); - } - return super.bindArgument(pos, basicType, value); - } - - @Override - MethodHandle bindReceiver(Object receiver) { - // If the member needs dispatching, do so. - DirectMethodHandle concrete = maybeRebind(receiver); - if (concrete != null) - return concrete.bindReceiver(receiver); - return super.bindReceiver(receiver); - } - private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); - private DirectMethodHandle maybeRebind(Object receiver) { - if (receiver != null) { - switch (member.getReferenceKind()) { - case REF_invokeInterface: - case REF_invokeVirtual: - // Pre-dispatch the member. - Class<?> concreteClass = receiver.getClass(); - MemberName concrete = new MemberName(concreteClass, member.getName(), member.getMethodType(), REF_invokeSpecial); - concrete = IMPL_NAMES.resolveOrNull(REF_invokeSpecial, concrete, concreteClass); - if (concrete != null) - return new DirectMethodHandle(type(), preparedLambdaForm(concrete), concrete); - break; - } - } - return null; - } - /** * Create a LF which can invoke the given method. * Cache and share this structure among all methods with
--- a/src/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/MethodHandle.java Wed Sep 10 18:34:02 2014 +0400 @@ -774,7 +774,7 @@ /*non-public*/ MethodHandle asTypeUncached(MethodType newType) { if (!type.isConvertibleTo(newType)) throw new WrongMethodTypeException("cannot convert "+this+" to "+newType); - return asTypeCache = convertArguments(newType); + return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, 1); } /** @@ -987,7 +987,7 @@ int collectArgPos = type().parameterCount()-1; MethodHandle target = this; if (arrayType != type().parameterType(collectArgPos)) - target = convertArguments(type().changeParameterType(collectArgPos, arrayType)); + target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), 1); MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength); return MethodHandles.collectArguments(target, collectArgPos, collector); } @@ -1260,14 +1260,8 @@ * @see MethodHandles#insertArguments */ public MethodHandle bindTo(Object x) { - Class<?> ptype; - @SuppressWarnings("LocalVariableHidesMemberVariable") - MethodType type = type(); - if (type.parameterCount() == 0 || - (ptype = type.parameterType(0)).isPrimitive()) - throw newIllegalArgumentException("no leading reference parameter", x); - x = ptype.cast(x); // throw CCE if needed - return bindReceiver(x); + x = type.leadingReferenceParameter().cast(x); // throw CCE if needed + return bindArgumentL(0, x); } /** @@ -1306,6 +1300,10 @@ // Other transforms to do: convert, explicitCast, permute, drop, filter, fold, GWT, catch + BoundMethodHandle bindArgumentL(int pos, Object value) { + return rebind().bindArgumentL(pos, value); + } + /*non-public*/ MethodHandle setVarargs(MemberName member) throws IllegalAccessException { if (!member.isVarargs()) return this; @@ -1374,37 +1372,8 @@ //// Sub-classes can override these default implementations. //// All these methods assume arguments are already validated. - /*non-public*/ MethodHandle convertArguments(MethodType newType) { - // Override this if it can be improved. - return MethodHandleImpl.makePairwiseConvert(this, newType, 1); - } - /*non-public*/ - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - // Override this if it can be improved. - return rebind().bindArgument(pos, basicType, value); - } - - /*non-public*/ - MethodHandle bindReceiver(Object receiver) { - // Override this if it can be improved. - return bindArgument(0, L_TYPE, receiver); - } - - /*non-public*/ - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - // Override this if it can be improved. - return rebind().dropArguments(srcType, pos, drops); - } - - /*non-public*/ - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - // Override this if it can be improved. - return rebind().permuteArguments(newType, reorder); - } - - /*non-public*/ - MethodHandle rebind() { + BoundMethodHandle rebind() { // Bind 'this' into a new invoker, of the known class BMH. MethodType type2 = type(); LambdaForm form2 = reinvokerForm(this);
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 18:34:02 2014 +0400 @@ -434,27 +434,6 @@ boolean isInvokeSpecial() { return asFixedArity().isInvokeSpecial(); } - - - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - return asFixedArity().bindArgument(pos, basicType, value); - } - - @Override - MethodHandle bindReceiver(Object receiver) { - return asFixedArity().bindReceiver(receiver); - } - - @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - return asFixedArity().dropArguments(srcType, pos, drops); - } - - @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - return asFixedArity().permuteArguments(newType, reorder); - } } /** Factory method: Spread selected argument. */ @@ -794,7 +773,9 @@ assert(Throwable.class.isAssignableFrom(type.parameterType(0))); int arity = type.parameterCount(); if (arity > 1) { - return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); + MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); + mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); + return mh; } return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2); }
--- a/src/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 18:34:02 2014 +0400 @@ -26,6 +26,7 @@ package java.lang.invoke; import java.lang.reflect.*; +import java.util.BitSet; import java.util.List; import java.util.ArrayList; import java.util.Arrays; @@ -1144,7 +1145,7 @@ Class<? extends Object> refc = receiver.getClass(); // may get NPE MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); - return mh.bindReceiver(receiver).setVarargs(method); + return mh.bindArgumentL(0, receiver).setVarargs(method); } /** @@ -2087,11 +2088,55 @@ public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { reorder = reorder.clone(); - checkReorder(reorder, newType, target.type()); - return target.permuteArguments(newType, reorder); + permuteArgumentChecks(reorder, newType, target.type()); + // first detect dropped arguments and handle them separately + MethodHandle originalTarget = target; + int newArity = newType.parameterCount(); + for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) { + // dropIdx is missing from reorder; add it in at the end + int oldArity = reorder.length; + target = dropArguments(target, oldArity, newType.parameterType(dropIdx)); + reorder = Arrays.copyOf(reorder, oldArity+1); + reorder[oldArity] = dropIdx; + } + assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type())); + // Note: This may cache too many distinct LFs. Consider backing off to varargs code. + BoundMethodHandle result = target.rebind(); + LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList())); + return result.copyWith(newType, form); } - private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) { + /** Return the first value in [0..newArity-1] that is not present in reorder. */ + private static int findFirstDrop(int[] reorder, int newArity) { + final int BIT_LIMIT = 63; // max number of bits in bit mask + if (newArity < BIT_LIMIT) { + long mask = 0; + for (int arg : reorder) { + assert(arg < newArity); + mask |= (1 << arg); + } + if (mask == (1 << newArity) - 1) { + assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); + return -1; + } + // find first zero + long zeroBit = Long.lowestOneBit(~mask); + int zeroPos = Long.numberOfTrailingZeros(zeroBit); + assert(zeroPos < newArity); + return zeroPos; + } + BitSet mask = new BitSet(newArity); + for (int arg : reorder) { + assert(arg < newArity); + mask.set(arg); + } + int zeroPos = mask.nextClearBit(0); + if (zeroPos == newArity) + return -1; + return zeroPos; + } + + private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) { if (newType.returnType() != oldType.returnType()) throw newIllegalArgumentException("return types do not match", oldType, newType); @@ -2109,7 +2154,7 @@ throw newIllegalArgumentException("parameter types do not match after reorder", oldType, newType); } - if (!bad) return; + if (!bad) return true; } throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder)); } @@ -2193,6 +2238,37 @@ public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values) { int insCount = values.length; + Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos); + if (insCount == 0) return target; + BoundMethodHandle result = target.rebind(); + for (int i = 0; i < insCount; i++) { + Object value = values[i]; + Class<?> ptype = ptypes[pos+i]; + if (ptype.isPrimitive()) { + result = insertArgumentPrimitive(result, pos, ptype, value); + } else { + value = ptype.cast(value); // throw CCE if needed + result = result.bindArgumentL(pos, value); + } + } + return result; + } + + private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos, + Class<?> ptype, Object value) { + Wrapper w = Wrapper.forPrimitiveType(ptype); + // perform unboxing and/or primitive conversion + value = w.convert(value, ptype); + switch (w) { + case INT: return result.bindArgumentI(pos, (int)value); + case LONG: return result.bindArgumentJ(pos, (long)value); + case FLOAT: return result.bindArgumentF(pos, (float)value); + case DOUBLE: return result.bindArgumentD(pos, (double)value); + default: return result.bindArgumentI(pos, ValueConversions.widenSubword(value)); + } + } + + private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException { MethodType oldType = target.type(); int outargs = oldType.parameterCount(); int inargs = outargs - insCount; @@ -2200,31 +2276,7 @@ throw newIllegalArgumentException("too many values to insert"); if (pos < 0 || pos > inargs) throw newIllegalArgumentException("no argument type to append"); - MethodHandle result = target; - for (int i = 0; i < insCount; i++) { - Object value = values[i]; - Class<?> ptype = oldType.parameterType(pos+i); - if (ptype.isPrimitive()) { - BasicType btype = I_TYPE; - Wrapper w = Wrapper.forPrimitiveType(ptype); - switch (w) { - case LONG: btype = J_TYPE; break; - case FLOAT: btype = F_TYPE; break; - case DOUBLE: btype = D_TYPE; break; - } - // perform unboxing and/or primitive conversion - value = w.convert(value, ptype); - result = result.bindArgument(pos, btype, value); - continue; - } - value = ptype.cast(value); // throw CCE if needed - if (pos == 0) { - result = result.bindReceiver(value); - } else { - result = result.bindArgument(pos, L_TYPE, value); - } - } - return result; + return oldType.ptypes(); } /** @@ -2272,18 +2324,26 @@ public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { MethodType oldType = target.type(); // get NPE + int dropped = dropArgumentChecks(oldType, pos, valueTypes); + if (dropped == 0) return target; + BoundMethodHandle result = target.rebind(); + LambdaForm lform = result.form; + lform = lform.addArguments(pos, valueTypes); + MethodType newType = oldType.insertParameterTypes(pos, valueTypes); + result = result.copyWith(newType, lform); + return result; + } + + private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) { int dropped = valueTypes.size(); MethodType.checkSlotCount(dropped); - if (dropped == 0) return target; int outargs = oldType.parameterCount(); int inargs = outargs + dropped; - if (pos < 0 || pos >= inargs) - throw newIllegalArgumentException("no argument type to remove"); - ArrayList<Class<?>> ptypes = new ArrayList<>(oldType.parameterList()); - ptypes.addAll(pos, valueTypes); - if (ptypes.size() != inargs) throw newIllegalArgumentException("valueTypes"); - MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); - return target.dropArguments(newType, pos, dropped); + if (pos < 0 || pos > outargs) + throw newIllegalArgumentException("no argument type to remove" + + Arrays.asList(oldType, pos, valueTypes, inargs, outargs) + ); + return dropped; } /**
--- a/src/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 18:34:02 2014 +0400 @@ -498,6 +498,17 @@ return this; // arguments check out; no change } + /** Return the leading parameter type, which must exist and be a reference. + * @return the leading parameter type, after error checks + */ + /*non-public*/ Class<?> leadingReferenceParameter() { + Class<?> ptype; + if (ptypes.length == 0 || + (ptype = ptypes[0]).isPrimitive()) + throw newIllegalArgumentException("no leading reference parameter"); + return ptype; + } + /** * Finds or creates a method type with some parameter types omitted. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
--- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 +++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java Wed Sep 10 18:34:02 2014 +0400 @@ -25,9 +25,6 @@ package java.lang.invoke; -import static java.lang.invoke.LambdaForm.*; -import static java.lang.invoke.LambdaForm.BasicType.*; - /** * A method handle whose behavior is determined only by its LambdaForm. * @author jrose @@ -40,23 +37,4 @@ /*non-public*/ static SimpleMethodHandle make(MethodType type, LambdaForm form) { return new SimpleMethodHandle(type, form); } - - @Override - MethodHandle bindArgument(int pos, BasicType basicType, Object value) { - MethodType type2 = type().dropParameterTypes(pos, pos+1); - LambdaForm form2 = internalForm().bind(1+pos, BoundMethodHandle.SpeciesData.EMPTY); - return BoundMethodHandle.bindSingle(type2, form2, basicType, value); - } - - @Override - MethodHandle dropArguments(MethodType srcType, int pos, int drops) { - LambdaForm newForm = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops)); - return new SimpleMethodHandle(srcType, newForm); - } - - @Override - MethodHandle permuteArguments(MethodType newType, int[] reorder) { - LambdaForm form2 = internalForm().permuteArguments(1, reorder, basicTypes(newType.parameterList())); - return new SimpleMethodHandle(newType, form2); - } }