8063135: Enable full LF sharing by default

Reviewed-by: psandoz, shade
This commit is contained in:
Vladimir Ivanov 2014-11-24 07:16:38 -08:00
parent 96da5b9ce3
commit b1ad8012a0
7 changed files with 115 additions and 204 deletions

View file

@ -867,15 +867,11 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength); MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
int arity = type().parameterCount(); int arity = type().parameterCount();
int spreadArgPos = arity - arrayLength; int spreadArgPos = arity - arrayLength;
if (USE_LAMBDA_FORM_EDITOR) { MethodHandle afterSpread = this.asType(postSpreadType);
MethodHandle afterSpread = this.asType(postSpreadType); BoundMethodHandle mh = afterSpread.rebind();
BoundMethodHandle mh = afterSpread.rebind(); LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength); MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType); return mh.copyWith(preSpreadType, lform);
return mh.copyWith(preSpreadType, lform);
} else {
return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
}
} }
/** /**
@ -996,23 +992,15 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) { public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
asCollectorChecks(arrayType, arrayLength); asCollectorChecks(arrayType, arrayLength);
int collectArgPos = type().parameterCount() - 1; int collectArgPos = type().parameterCount() - 1;
if (USE_LAMBDA_FORM_EDITOR) { BoundMethodHandle mh = rebind();
BoundMethodHandle mh = rebind(); MethodType resultType = type().asCollectorType(arrayType, arrayLength);
MethodType resultType = type().asCollectorType(arrayType, arrayLength); MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength); LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray); if (lform != null) {
if (lform != null) { return mh.copyWith(resultType, lform);
return mh.copyWith(resultType, lform);
}
lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
return mh.copyWithExtendL(resultType, lform, newArray);
} else {
MethodHandle target = this;
if (arrayType != type().parameterType(collectArgPos))
target = MethodHandleImpl.makePairwiseConvert(this, type().changeParameterType(collectArgPos, arrayType), true);
MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
return MethodHandles.collectArguments(target, collectArgPos, collector);
} }
lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
return mh.copyWithExtendL(resultType, lform, newArray);
} }
/** /**

View file

@ -191,11 +191,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodType dstType = target.type(); MethodType dstType = target.type();
if (srcType == dstType) if (srcType == dstType)
return target; return target;
if (USE_LAMBDA_FORM_EDITOR) { return makePairwiseConvertByEditor(target, srcType, strict, monobox);
return makePairwiseConvertByEditor(target, srcType, strict, monobox);
} else {
return makePairwiseConvertIndirect(target, srcType, strict, monobox);
}
} }
private static int countNonNull(Object[] array) { private static int countNonNull(Object[] array) {

View file

@ -45,23 +45,21 @@ import sun.misc.Unsafe;
static final boolean DUMP_CLASS_FILES; static final boolean DUMP_CLASS_FILES;
static final boolean TRACE_INTERPRETER; static final boolean TRACE_INTERPRETER;
static final boolean TRACE_METHOD_LINKAGE; static final boolean TRACE_METHOD_LINKAGE;
static final boolean USE_LAMBDA_FORM_EDITOR;
static final int COMPILE_THRESHOLD; static final int COMPILE_THRESHOLD;
static final int DONT_INLINE_THRESHOLD; static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL; static final int PROFILE_LEVEL;
static { static {
final Object[] values = new Object[8]; final Object[] values = new Object[7];
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() { public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES"); values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES"); values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER"); values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"); values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR"); values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30); values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30); values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
values[7] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
return null; return null;
} }
}); });
@ -69,10 +67,9 @@ import sun.misc.Unsafe;
DUMP_CLASS_FILES = (Boolean) values[1]; DUMP_CLASS_FILES = (Boolean) values[1];
TRACE_INTERPRETER = (Boolean) values[2]; TRACE_INTERPRETER = (Boolean) values[2];
TRACE_METHOD_LINKAGE = (Boolean) values[3]; TRACE_METHOD_LINKAGE = (Boolean) values[3];
USE_LAMBDA_FORM_EDITOR = (Boolean) values[4]; COMPILE_THRESHOLD = (Integer) values[4];
COMPILE_THRESHOLD = (Integer) values[5]; DONT_INLINE_THRESHOLD = (Integer) values[5];
DONT_INLINE_THRESHOLD = (Integer) values[6]; PROFILE_LEVEL = (Integer) values[6];
PROFILE_LEVEL = (Integer) values[7];
} }
/** Tell if any of the debugging switches are turned on. /** Tell if any of the debugging switches are turned on.

View file

@ -2103,115 +2103,65 @@ assert((int)twice.invokeExact(21) == 42);
reorder = reorder.clone(); // get a private copy reorder = reorder.clone(); // get a private copy
MethodType oldType = target.type(); MethodType oldType = target.type();
permuteArgumentChecks(reorder, newType, oldType); permuteArgumentChecks(reorder, newType, oldType);
if (USE_LAMBDA_FORM_EDITOR) { // first detect dropped arguments and handle them separately
// first detect dropped arguments and handle them separately int[] originalReorder = reorder;
int[] originalReorder = reorder; BoundMethodHandle result = target.rebind();
BoundMethodHandle result = target.rebind(); LambdaForm form = result.form;
LambdaForm form = result.form; int newArity = newType.parameterCount();
int newArity = newType.parameterCount(); // Normalize the reordering into a real permutation,
// Normalize the reordering into a real permutation, // by removing duplicates and adding dropped elements.
// by removing duplicates and adding dropped elements. // This somewhat improves lambda form caching, as well
// This somewhat improves lambda form caching, as well // as simplifying the transform by breaking it up into steps.
// as simplifying the transform by breaking it up into steps. for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) { if (ddIdx > 0) {
if (ddIdx > 0) { // We found a duplicated entry at reorder[ddIdx].
// We found a duplicated entry at reorder[ddIdx]. // Example: (x,y,z)->asList(x,y,z)
// Example: (x,y,z)->asList(x,y,z) // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
// permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1) // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
// permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0) // The starred element corresponds to the argument
// The starred element corresponds to the argument // deleted by the dupArgumentForm transform.
// deleted by the dupArgumentForm transform. int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos]; boolean killFirst = false;
boolean killFirst = false; for (int val; (val = reorder[--dstPos]) != dupVal; ) {
for (int val; (val = reorder[--dstPos]) != dupVal; ) { // Set killFirst if the dup is larger than an intervening position.
// Set killFirst if the dup is larger than an intervening position. // This will remove at least one inversion from the permutation.
// This will remove at least one inversion from the permutation. if (dupVal > val) killFirst = true;
if (dupVal > val) killFirst = true;
}
if (!killFirst) {
srcPos = dstPos;
dstPos = ddIdx;
}
form = form.editor().dupArgumentForm(1 + srcPos, 1 + dstPos);
assert (reorder[srcPos] == reorder[dstPos]);
oldType = oldType.dropParameterTypes(dstPos, dstPos + 1);
// contract the reordering by removing the element at dstPos
int tailPos = dstPos + 1;
System.arraycopy(reorder, tailPos, reorder, dstPos, reorder.length - tailPos);
reorder = Arrays.copyOf(reorder, reorder.length - 1);
} else {
int dropVal = ~ddIdx, insPos = 0;
while (insPos < reorder.length && reorder[insPos] < dropVal) {
// Find first element of reorder larger than dropVal.
// This is where we will insert the dropVal.
insPos += 1;
}
Class<?> ptype = newType.parameterType(dropVal);
form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
oldType = oldType.insertParameterTypes(insPos, ptype);
// expand the reordering by inserting an element at insPos
int tailPos = insPos + 1;
reorder = Arrays.copyOf(reorder, reorder.length + 1);
System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
reorder[insPos] = dropVal;
} }
assert (permuteArgumentChecks(reorder, newType, oldType)); if (!killFirst) {
srcPos = dstPos;
dstPos = ddIdx;
}
form = form.editor().dupArgumentForm(1 + srcPos, 1 + dstPos);
assert (reorder[srcPos] == reorder[dstPos]);
oldType = oldType.dropParameterTypes(dstPos, dstPos + 1);
// contract the reordering by removing the element at dstPos
int tailPos = dstPos + 1;
System.arraycopy(reorder, tailPos, reorder, dstPos, reorder.length - tailPos);
reorder = Arrays.copyOf(reorder, reorder.length - 1);
} else {
int dropVal = ~ddIdx, insPos = 0;
while (insPos < reorder.length && reorder[insPos] < dropVal) {
// Find first element of reorder larger than dropVal.
// This is where we will insert the dropVal.
insPos += 1;
}
Class<?> ptype = newType.parameterType(dropVal);
form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
oldType = oldType.insertParameterTypes(insPos, ptype);
// expand the reordering by inserting an element at insPos
int tailPos = insPos + 1;
reorder = Arrays.copyOf(reorder, reorder.length + 1);
System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
reorder[insPos] = dropVal;
} }
assert (reorder.length == newArity); // a perfect permutation assert (permuteArgumentChecks(reorder, newType, oldType));
// Note: This may cache too many distinct LFs. Consider backing off to varargs code.
form = form.editor().permuteArgumentsForm(1, reorder);
if (newType == result.type() && form == result.internalForm())
return result;
return result.copyWith(newType, form);
} else {
// 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);
}
}
/** 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 |= (1L << arg);
}
if (mask == (1L << 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;
} else {
BitSet mask = new BitSet(newArity);
for (int arg : reorder) {
assert (arg < newArity);
mask.set(arg);
}
int zeroPos = mask.nextClearBit(0);
assert(zeroPos <= newArity);
if (zeroPos == newArity)
return -1;
return zeroPos;
} }
assert (reorder.length == newArity); // a perfect permutation
// Note: This may cache too many distinct LFs. Consider backing off to varargs code.
form = form.editor().permuteArgumentsForm(1, reorder);
if (newType == result.type() && form == result.internalForm())
return result;
return result.copyWith(newType, form);
} }
/** /**
@ -2502,13 +2452,9 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
if (dropped == 0) return target; if (dropped == 0) return target;
BoundMethodHandle result = target.rebind(); BoundMethodHandle result = target.rebind();
LambdaForm lform = result.form; LambdaForm lform = result.form;
if (USE_LAMBDA_FORM_EDITOR) { int insertFormArg = 1 + pos;
int insertFormArg = 1 + pos; for (Class<?> ptype : valueTypes) {
for (Class<?> ptype : valueTypes) { lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
}
} else {
lform = lform.addArguments(pos, valueTypes);
} }
result = result.copyWith(newType, lform); result = result.copyWith(newType, lform);
return result; return result;
@ -2659,18 +2605,14 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
/*non-public*/ static /*non-public*/ static
MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
filterArgumentChecks(target, pos, filter); filterArgumentChecks(target, pos, filter);
if (USE_LAMBDA_FORM_EDITOR) { MethodType targetType = target.type();
MethodType targetType = target.type(); MethodType filterType = filter.type();
MethodType filterType = filter.type(); BoundMethodHandle result = target.rebind();
BoundMethodHandle result = target.rebind(); Class<?> newParamType = filterType.parameterType(0);
Class<?> newParamType = filterType.parameterType(0); LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType)); MethodType newType = targetType.changeParameterType(pos, newParamType);
MethodType newType = targetType.changeParameterType(pos, newParamType); result = result.copyWithExtendL(newType, lform, filter);
result = result.copyWithExtendL(newType, lform, filter); return result;
return result;
} else {
return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
}
} }
private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) { private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
@ -2797,21 +2739,17 @@ assertEquals("[top, [[up, down, strange], charm], bottom]",
public static public static
MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) { MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
MethodType newType = collectArgumentsChecks(target, pos, filter); MethodType newType = collectArgumentsChecks(target, pos, filter);
if (USE_LAMBDA_FORM_EDITOR) { MethodType collectorType = filter.type();
MethodType collectorType = filter.type(); BoundMethodHandle result = target.rebind();
BoundMethodHandle result = target.rebind(); LambdaForm lform;
LambdaForm lform; if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) { lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
lform = result.editor().collectArgumentArrayForm(1 + pos, filter); if (lform != null) {
if (lform != null) { return result.copyWith(newType, lform);
return result.copyWith(newType, lform);
}
} }
lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
return result.copyWithExtendL(newType, lform, filter);
} else {
return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
} }
lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
return result.copyWithExtendL(newType, lform, filter);
} }
private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException { private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
@ -2890,16 +2828,12 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodType targetType = target.type(); MethodType targetType = target.type();
MethodType filterType = filter.type(); MethodType filterType = filter.type();
filterReturnValueChecks(targetType, filterType); filterReturnValueChecks(targetType, filterType);
if (USE_LAMBDA_FORM_EDITOR) { BoundMethodHandle result = target.rebind();
BoundMethodHandle result = target.rebind(); BasicType rtype = BasicType.basicType(filterType.returnType());
BasicType rtype = BasicType.basicType(filterType.returnType()); LambdaForm lform = result.editor().filterReturnForm(rtype, false);
LambdaForm lform = result.editor().filterReturnForm(rtype, false); MethodType newType = targetType.changeReturnType(filterType.returnType());
MethodType newType = targetType.changeReturnType(filterType.returnType()); result = result.copyWithExtendL(newType, lform, filter);
result = result.copyWithExtendL(newType, lform, filter); return result;
return result;
} else {
return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
}
} }
private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException { private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
@ -2993,19 +2927,15 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
MethodType targetType = target.type(); MethodType targetType = target.type();
MethodType combinerType = combiner.type(); MethodType combinerType = combiner.type();
Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType); Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
if (USE_LAMBDA_FORM_EDITOR) { BoundMethodHandle result = target.rebind();
BoundMethodHandle result = target.rebind(); boolean dropResult = (rtype == void.class);
boolean dropResult = (rtype == void.class); // Note: This may cache too many distinct LFs. Consider backing off to varargs code.
// Note: This may cache too many distinct LFs. Consider backing off to varargs code. LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType()); MethodType newType = targetType;
MethodType newType = targetType; if (!dropResult)
if (!dropResult) newType = newType.dropParameterTypes(foldPos, foldPos + 1);
newType = newType.dropParameterTypes(foldPos, foldPos + 1); result = result.copyWithExtendL(newType, lform, combiner);
result = result.copyWithExtendL(newType, lform, combiner); return result;
return result;
} else {
return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
}
} }
private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) { private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {

View file

@ -31,7 +31,7 @@
* @build TestMethods * @build TestMethods
* @build LambdaFormTestCase * @build LambdaFormTestCase
* @build LFGarbageCollectedTest * @build LFGarbageCollectedTest
* @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 LFGarbageCollectedTest * @run main/othervm/timeout=600 -DtestLimit=150 LFGarbageCollectedTest
*/ */
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;

View file

@ -31,7 +31,7 @@
* @build LambdaFormTestCase * @build LambdaFormTestCase
* @build LFCachingTestCase * @build LFCachingTestCase
* @build LFMultiThreadCachingTest * @build LFMultiThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest * @run main/othervm/timeout=300 LFMultiThreadCachingTest
*/ */
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;

View file

@ -31,7 +31,7 @@
* @build LambdaFormTestCase * @build LambdaFormTestCase
* @build LFCachingTestCase * @build LFCachingTestCase
* @build LFSingleThreadCachingTest * @build LFSingleThreadCachingTest
* @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest * @run main/othervm/timeout=300 LFSingleThreadCachingTest
*/ */
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;