aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/java/lang/invoke
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/java/lang/invoke')
-rw-r--r--src/share/classes/java/lang/invoke/DelegatingMethodHandle.java37
-rw-r--r--src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java9
-rw-r--r--src/share/classes/java/lang/invoke/LambdaForm.java27
-rw-r--r--src/share/classes/java/lang/invoke/MethodHandle.java43
-rw-r--r--src/share/classes/java/lang/invoke/MethodHandleImpl.java133
-rw-r--r--src/share/classes/java/lang/invoke/MethodHandleStatics.java12
-rw-r--r--src/share/classes/java/lang/invoke/MethodHandles.java252
-rw-r--r--src/share/classes/java/lang/invoke/MethodTypeForm.java37
8 files changed, 315 insertions, 235 deletions
diff --git a/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
index 63ba8fea5..5c874f497 100644
--- a/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
+++ b/src/share/classes/java/lang/invoke/DelegatingMethodHandle.java
@@ -44,6 +44,10 @@ abstract class DelegatingMethodHandle extends MethodHandle {
super(type, chooseDelegatingForm(target));
}
+ protected DelegatingMethodHandle(MethodType type, LambdaForm form) {
+ super(type, form);
+ }
+
/** Define this to extract the delegated target which supplies the invocation behavior. */
abstract protected MethodHandle getTarget();
@@ -88,14 +92,31 @@ abstract class DelegatingMethodHandle extends MethodHandle {
return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
}
- /** Create a LF which simply reinvokes a target of the given basic type. */
static LambdaForm makeReinvokerForm(MethodHandle target,
int whichCache,
Object constraint,
NamedFunction getTargetFn) {
+ String debugString;
+ switch(whichCache) {
+ case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
+ case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
+ default: debugString = "MH.reinvoke"; break;
+ }
+ // No pre-action needed.
+ return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
+ }
+ /** Create a LF which simply reinvokes a target of the given basic type. */
+ static LambdaForm makeReinvokerForm(MethodHandle target,
+ int whichCache,
+ Object constraint,
+ String debugString,
+ boolean forceInline,
+ NamedFunction getTargetFn,
+ NamedFunction preActionFn) {
MethodType mtype = target.type().basicType();
boolean customized = (whichCache < 0 ||
mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
+ boolean hasPreAction = (preActionFn != null);
LambdaForm form;
if (!customized) {
form = mtype.form().cachedLambdaForm(whichCache);
@@ -105,12 +126,16 @@ abstract class DelegatingMethodHandle extends MethodHandle {
final int ARG_BASE = 1;
final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
int nameCursor = ARG_LIMIT;
+ final int PRE_ACTION = hasPreAction ? nameCursor++ : -1;
final int NEXT_MH = customized ? -1 : nameCursor++;
final int REINVOKE = nameCursor++;
LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
assert(names.length == nameCursor);
names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
Object[] targetArgs;
+ if (hasPreAction) {
+ names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
+ }
if (customized) {
targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself
@@ -120,20 +145,14 @@ abstract class DelegatingMethodHandle extends MethodHandle {
targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH
names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
}
- String debugString;
- switch(whichCache) {
- case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break;
- case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break;
- default: debugString = "MH.reinvoke"; break;
- }
- form = new LambdaForm(debugString, ARG_LIMIT, names);
+ form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
if (!customized) {
form = mtype.form().setCachedLambdaForm(whichCache, form);
}
return form;
}
- private static final NamedFunction NF_getTarget;
+ static final NamedFunction NF_getTarget;
static {
try {
NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
index cdbbebcbe..6e8d091a6 100644
--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
@@ -628,8 +628,13 @@ class InvokerBytecodeGenerator {
// Mark this method as a compiled LambdaForm
mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
- // Force inlining of this invoker method.
- mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
+ if (lambdaForm.forceInline) {
+ // Force inlining of this invoker method.
+ mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
+ } else {
+ mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
+ }
+
// iterate over the form's names, generating bytecode instructions for each
// start iterating at the first name following the arguments
diff --git a/src/share/classes/java/lang/invoke/LambdaForm.java b/src/share/classes/java/lang/invoke/LambdaForm.java
index b83040647..e1791719c 100644
--- a/src/share/classes/java/lang/invoke/LambdaForm.java
+++ b/src/share/classes/java/lang/invoke/LambdaForm.java
@@ -119,6 +119,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*;
class LambdaForm {
final int arity;
final int result;
+ final boolean forceInline;
@Stable final Name[] names;
final String debugName;
MemberName vmentry; // low-level behavior, or null if not yet prepared
@@ -243,11 +244,16 @@ class LambdaForm {
LambdaForm(String debugName,
int arity, Name[] names, int result) {
+ this(debugName, arity, names, result, true);
+ }
+ LambdaForm(String debugName,
+ int arity, Name[] names, int result, boolean forceInline) {
assert(namesOK(arity, names));
this.arity = arity;
this.result = fixResult(result, names);
this.names = names.clone();
this.debugName = fixDebugName(debugName);
+ this.forceInline = forceInline;
int maxOutArity = normalize();
if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
// Cannot use LF interpreter on very high arity expressions.
@@ -255,17 +261,23 @@ class LambdaForm {
compileToBytecode();
}
}
-
LambdaForm(String debugName,
int arity, Name[] names) {
- this(debugName,
- arity, names, LAST_RESULT);
+ this(debugName, arity, names, LAST_RESULT, true);
+ }
+ LambdaForm(String debugName,
+ int arity, Name[] names, boolean forceInline) {
+ this(debugName, arity, names, LAST_RESULT, forceInline);
}
-
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result) {
this(debugName,
- formals.length, buildNames(formals, temps, result), LAST_RESULT);
+ formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
+ }
+ LambdaForm(String debugName,
+ Name[] formals, Name[] temps, Name result, boolean forceInline) {
+ this(debugName,
+ formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline);
}
private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
@@ -279,6 +291,10 @@ class LambdaForm {
}
private LambdaForm(String sig) {
+ this(sig, true);
+ }
+
+ private LambdaForm(String sig, boolean forceInline) {
// Make a blank lambda form, which returns a constant zero or null.
// It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm.
@@ -287,6 +303,7 @@ class LambdaForm {
this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
this.names = buildEmptyNames(arity, sig);
this.debugName = "LF.zero";
+ this.forceInline = forceInline;
assert(nameRefsAreLegal());
assert(isEmpty());
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
diff --git a/src/share/classes/java/lang/invoke/MethodHandle.java b/src/share/classes/java/lang/invoke/MethodHandle.java
index f0169e73d..9b586a317 100644
--- a/src/share/classes/java/lang/invoke/MethodHandle.java
+++ b/src/share/classes/java/lang/invoke/MethodHandle.java
@@ -867,15 +867,11 @@ assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray
MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
int arity = type().parameterCount();
int spreadArgPos = arity - arrayLength;
- if (USE_LAMBDA_FORM_EDITOR) {
- MethodHandle afterSpread = this.asType(postSpreadType);
- BoundMethodHandle mh = afterSpread.rebind();
- LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
- MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
- return mh.copyWith(preSpreadType, lform);
- } else {
- return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
- }
+ MethodHandle afterSpread = this.asType(postSpreadType);
+ BoundMethodHandle mh = afterSpread.rebind();
+ LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
+ MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
+ return mh.copyWith(preSpreadType, lform);
}
/**
@@ -996,23 +992,15 @@ assertEquals("[123]", (String) longsToString.invokeExact((long)123));
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
asCollectorChecks(arrayType, arrayLength);
int collectArgPos = type().parameterCount() - 1;
- if (USE_LAMBDA_FORM_EDITOR) {
- BoundMethodHandle mh = rebind();
- MethodType resultType = type().asCollectorType(arrayType, arrayLength);
- MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
- LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
- if (lform != null) {
- 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);
+ BoundMethodHandle mh = rebind();
+ MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+ MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+ LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
+ if (lform != null) {
+ return mh.copyWith(resultType, lform);
}
+ lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
+ return mh.copyWithExtendL(resultType, lform, newArray);
}
/**
@@ -1438,10 +1426,9 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
/*non-public*/
void updateForm(LambdaForm newForm) {
if (form == newForm) return;
- assert(this instanceof DirectMethodHandle && this.internalMemberName().isStatic());
- // ISSUE: Should we have a memory fence here?
+ newForm.prepare(); // as in MethodHandle.<init>
UNSAFE.putObject(this, FORM_OFFSET, newForm);
- this.form.prepare(); // as in MethodHandle.<init>
+ UNSAFE.fullFence();
}
private static final long FORM_OFFSET;
diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
index 3cab70696..8812b6d2a 100644
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.function.Function;
import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
@@ -190,11 +191,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodType dstType = target.type();
if (srcType == dstType)
return target;
- if (USE_LAMBDA_FORM_EDITOR) {
- return makePairwiseConvertByEditor(target, srcType, strict, monobox);
- } else {
- return makePairwiseConvertIndirect(target, srcType, strict, monobox);
- }
+ return makePairwiseConvertByEditor(target, srcType, strict, monobox);
}
private static int countNonNull(Object[] array) {
@@ -713,10 +710,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
LambdaForm form = makeGuardWithTestForm(basicType);
BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
BoundMethodHandle mh;
+
try {
mh = (BoundMethodHandle)
data.constructor().invokeBasic(type, form,
- (Object) test, (Object) target, (Object) fallback);
+ (Object) test, (Object) profile(target), (Object) profile(fallback));
} catch (Throwable ex) {
throw uncaughtException(ex);
}
@@ -724,6 +722,129 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return mh;
}
+
+ static
+ MethodHandle profile(MethodHandle target) {
+ if (DONT_INLINE_THRESHOLD >= 0) {
+ return makeBlockInlningWrapper(target);
+ } else {
+ return target;
+ }
+ }
+
+ /**
+ * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
+ * Corresponding LambdaForm has @DontInline when compiled into bytecode.
+ */
+ static
+ MethodHandle makeBlockInlningWrapper(MethodHandle target) {
+ LambdaForm lform = PRODUCE_BLOCK_INLINING_FORM.apply(target);
+ return new CountingWrapper(target, lform,
+ PRODUCE_BLOCK_INLINING_FORM, PRODUCE_REINVOKER_FORM,
+ DONT_INLINE_THRESHOLD);
+ }
+
+ /** Constructs reinvoker lambda form which block inlining during JIT-compilation for a particular method handle */
+ private static final Function<MethodHandle, LambdaForm> PRODUCE_BLOCK_INLINING_FORM = new Function<MethodHandle, LambdaForm>() {
+ @Override
+ public LambdaForm apply(MethodHandle target) {
+ return DelegatingMethodHandle.makeReinvokerForm(target,
+ MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, CountingWrapper.class, "reinvoker.dontInline", false,
+ DelegatingMethodHandle.NF_getTarget, CountingWrapper.NF_maybeStopCounting);
+ }
+ };
+
+ /** Constructs simple reinvoker lambda form for a particular method handle */
+ private static final Function<MethodHandle, LambdaForm> PRODUCE_REINVOKER_FORM = new Function<MethodHandle, LambdaForm>() {
+ @Override
+ public LambdaForm apply(MethodHandle target) {
+ return DelegatingMethodHandle.makeReinvokerForm(target,
+ MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, DelegatingMethodHandle.NF_getTarget);
+ }
+ };
+
+ /**
+ * Counting method handle. It has 2 states: counting and non-counting.
+ * It is in counting state for the first n invocations and then transitions to non-counting state.
+ * Behavior in counting and non-counting states is determined by lambda forms produced by
+ * countingFormProducer & nonCountingFormProducer respectively.
+ */
+ static class CountingWrapper extends DelegatingMethodHandle {
+ private final MethodHandle target;
+ private int count;
+ private Function<MethodHandle, LambdaForm> countingFormProducer;
+ private Function<MethodHandle, LambdaForm> nonCountingFormProducer;
+ private volatile boolean isCounting;
+
+ private CountingWrapper(MethodHandle target, LambdaForm lform,
+ Function<MethodHandle, LambdaForm> countingFromProducer,
+ Function<MethodHandle, LambdaForm> nonCountingFormProducer,
+ int count) {
+ super(target.type(), lform);
+ this.target = target;
+ this.count = count;
+ this.countingFormProducer = countingFromProducer;
+ this.nonCountingFormProducer = nonCountingFormProducer;
+ this.isCounting = (count > 0);
+ }
+
+ @Hidden
+ @Override
+ protected MethodHandle getTarget() {
+ return target;
+ }
+
+ @Override
+ public MethodHandle asTypeUncached(MethodType newType) {
+ MethodHandle newTarget = target.asType(newType);
+ MethodHandle wrapper;
+ if (isCounting) {
+ LambdaForm lform;
+ lform = countingFormProducer.apply(target);
+ wrapper = new CountingWrapper(newTarget, lform, countingFormProducer, nonCountingFormProducer, DONT_INLINE_THRESHOLD);
+ } else {
+ wrapper = newTarget; // no need for a counting wrapper anymore
+ }
+ return (asTypeCache = wrapper);
+ }
+
+ boolean countDown() {
+ if (count <= 0) {
+ // Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
+ if (isCounting) {
+ isCounting = false;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ --count;
+ return false;
+ }
+ }
+
+ @Hidden
+ static void maybeStopCounting(Object o1) {
+ CountingWrapper wrapper = (CountingWrapper) o1;
+ if (wrapper.countDown()) {
+ // Reached invocation threshold. Replace counting behavior with a non-counting one.
+ LambdaForm lform = wrapper.nonCountingFormProducer.apply(wrapper.target);
+ lform.compileToBytecode(); // speed up warmup by avoiding LF interpretation again after transition
+ wrapper.updateForm(lform);
+ }
+ }
+
+ static final NamedFunction NF_maybeStopCounting;
+ static {
+ Class<?> THIS_CLASS = CountingWrapper.class;
+ try {
+ NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
+ } catch (ReflectiveOperationException ex) {
+ throw newInternalError(ex);
+ }
+ }
+ }
+
static
LambdaForm makeGuardWithTestForm(MethodType basicType) {
LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
index c3d9ac12c..335a32289 100644
--- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java
+++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java
@@ -45,20 +45,20 @@ import sun.misc.Unsafe;
static final boolean DUMP_CLASS_FILES;
static final boolean TRACE_INTERPRETER;
static final boolean TRACE_METHOD_LINKAGE;
- static final boolean USE_LAMBDA_FORM_EDITOR;
static final int COMPILE_THRESHOLD;
+ static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL;
static {
- final Object[] values = { false, false, false, false, false, null, null };
+ final Object[] values = new Object[7];
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
- values[4] = Boolean.getBoolean("java.lang.invoke.MethodHandle.USE_LF_EDITOR");
- values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 30);
+ values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
+ values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
return null;
}
@@ -67,8 +67,8 @@ import sun.misc.Unsafe;
DUMP_CLASS_FILES = (Boolean) values[1];
TRACE_INTERPRETER = (Boolean) values[2];
TRACE_METHOD_LINKAGE = (Boolean) values[3];
- USE_LAMBDA_FORM_EDITOR = (Boolean) values[4];
- COMPILE_THRESHOLD = (Integer) values[5];
+ COMPILE_THRESHOLD = (Integer) values[4];
+ DONT_INLINE_THRESHOLD = (Integer) values[5];
PROFILE_LEVEL = (Integer) values[6];
}
diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
index 91855fb86..3c60a8c3c 100644
--- a/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -2104,115 +2104,65 @@ assert((int)twice.invokeExact(21) == 42);
reorder = reorder.clone(); // get a private copy
MethodType oldType = target.type();
permuteArgumentChecks(reorder, newType, oldType);
- if (USE_LAMBDA_FORM_EDITOR) {
- // first detect dropped arguments and handle them separately
- int[] originalReorder = reorder;
- BoundMethodHandle result = target.rebind();
- LambdaForm form = result.form;
- int newArity = newType.parameterCount();
- // Normalize the reordering into a real permutation,
- // by removing duplicates and adding dropped elements.
- // This somewhat improves lambda form caching, as well
- // as simplifying the transform by breaking it up into steps.
- for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
- if (ddIdx > 0) {
- // We found a duplicated entry at reorder[ddIdx].
- // Example: (x,y,z)->asList(x,y,z)
- // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
- // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
- // The starred element corresponds to the argument
- // deleted by the dupArgumentForm transform.
- int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
- boolean killFirst = false;
- for (int val; (val = reorder[--dstPos]) != dupVal; ) {
- // Set killFirst if the dup is larger than an intervening position.
- // This will remove at least one inversion from the permutation.
- 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;
+ // first detect dropped arguments and handle them separately
+ int[] originalReorder = reorder;
+ BoundMethodHandle result = target.rebind();
+ LambdaForm form = result.form;
+ int newArity = newType.parameterCount();
+ // Normalize the reordering into a real permutation,
+ // by removing duplicates and adding dropped elements.
+ // This somewhat improves lambda form caching, as well
+ // as simplifying the transform by breaking it up into steps.
+ for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
+ if (ddIdx > 0) {
+ // We found a duplicated entry at reorder[ddIdx].
+ // Example: (x,y,z)->asList(x,y,z)
+ // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
+ // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
+ // The starred element corresponds to the argument
+ // deleted by the dupArgumentForm transform.
+ int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
+ boolean killFirst = false;
+ for (int val; (val = reorder[--dstPos]) != dupVal; ) {
+ // Set killFirst if the dup is larger than an intervening position.
+ // This will remove at least one inversion from the permutation.
+ if (dupVal > val) killFirst = true;
}
- assert (permuteArgumentChecks(reorder, newType, oldType));
- }
- 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);
- } 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;
+ 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(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 (permuteArgumentChecks(reorder, newType, oldType));
}
+ 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);
}
/**
@@ -2503,13 +2453,9 @@ assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
if (dropped == 0) return target;
BoundMethodHandle result = target.rebind();
LambdaForm lform = result.form;
- if (USE_LAMBDA_FORM_EDITOR) {
- int insertFormArg = 1 + pos;
- for (Class<?> ptype : valueTypes) {
- lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
- }
- } else {
- lform = lform.addArguments(pos, valueTypes);
+ int insertFormArg = 1 + pos;
+ for (Class<?> ptype : valueTypes) {
+ lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
}
result = result.copyWith(newType, lform);
return result;
@@ -2660,18 +2606,14 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
/*non-public*/ static
MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
filterArgumentChecks(target, pos, filter);
- if (USE_LAMBDA_FORM_EDITOR) {
- MethodType targetType = target.type();
- MethodType filterType = filter.type();
- BoundMethodHandle result = target.rebind();
- Class<?> newParamType = filterType.parameterType(0);
- LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
- MethodType newType = targetType.changeParameterType(pos, newParamType);
- result = result.copyWithExtendL(newType, lform, filter);
- return result;
- } else {
- return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
- }
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ BoundMethodHandle result = target.rebind();
+ Class<?> newParamType = filterType.parameterType(0);
+ LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
+ MethodType newType = targetType.changeParameterType(pos, newParamType);
+ result = result.copyWithExtendL(newType, lform, filter);
+ return result;
}
private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
@@ -2798,21 +2740,17 @@ assertEquals("[top, [[up, down, strange], charm], bottom]",
public static
MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
MethodType newType = collectArgumentsChecks(target, pos, filter);
- if (USE_LAMBDA_FORM_EDITOR) {
- MethodType collectorType = filter.type();
- BoundMethodHandle result = target.rebind();
- LambdaForm lform;
- if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
- lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
- if (lform != null) {
- return result.copyWith(newType, lform);
- }
+ MethodType collectorType = filter.type();
+ BoundMethodHandle result = target.rebind();
+ LambdaForm lform;
+ if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
+ lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
+ if (lform != null) {
+ 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 {
@@ -2891,16 +2829,12 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
MethodType targetType = target.type();
MethodType filterType = filter.type();
filterReturnValueChecks(targetType, filterType);
- if (USE_LAMBDA_FORM_EDITOR) {
- BoundMethodHandle result = target.rebind();
- BasicType rtype = BasicType.basicType(filterType.returnType());
- LambdaForm lform = result.editor().filterReturnForm(rtype, false);
- MethodType newType = targetType.changeReturnType(filterType.returnType());
- result = result.copyWithExtendL(newType, lform, filter);
- return result;
- } else {
- return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
- }
+ BoundMethodHandle result = target.rebind();
+ BasicType rtype = BasicType.basicType(filterType.returnType());
+ LambdaForm lform = result.editor().filterReturnForm(rtype, false);
+ MethodType newType = targetType.changeReturnType(filterType.returnType());
+ result = result.copyWithExtendL(newType, lform, filter);
+ return result;
}
private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
@@ -2994,19 +2928,15 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
MethodType targetType = target.type();
MethodType combinerType = combiner.type();
Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
- if (USE_LAMBDA_FORM_EDITOR) {
- BoundMethodHandle result = target.rebind();
- boolean dropResult = (rtype == void.class);
- // Note: This may cache too many distinct LFs. Consider backing off to varargs code.
- LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
- MethodType newType = targetType;
- if (!dropResult)
- newType = newType.dropParameterTypes(foldPos, foldPos + 1);
- result = result.copyWithExtendL(newType, lform, combiner);
- return result;
- } else {
- return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
- }
+ BoundMethodHandle result = target.rebind();
+ boolean dropResult = (rtype == void.class);
+ // Note: This may cache too many distinct LFs. Consider backing off to varargs code.
+ LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
+ MethodType newType = targetType;
+ if (!dropResult)
+ newType = newType.dropParameterTypes(foldPos, foldPos + 1);
+ result = result.copyWithExtendL(newType, lform, combiner);
+ return result;
}
private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
diff --git a/src/share/classes/java/lang/invoke/MethodTypeForm.java b/src/share/classes/java/lang/invoke/MethodTypeForm.java
index 43e855894..6733e29ef 100644
--- a/src/share/classes/java/lang/invoke/MethodTypeForm.java
+++ b/src/share/classes/java/lang/invoke/MethodTypeForm.java
@@ -63,24 +63,25 @@ final class MethodTypeForm {
final @Stable LambdaForm[] lambdaForms;
// Indexes into lambdaForms:
static final int
- LF_INVVIRTUAL = 0, // DMH invokeVirtual
- LF_INVSTATIC = 1,
- LF_INVSPECIAL = 2,
- LF_NEWINVSPECIAL = 3,
- LF_INVINTERFACE = 4,
- LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
- LF_INTERPRET = 6, // LF interpreter
- LF_REBIND = 7, // BoundMethodHandle
- LF_DELEGATE = 8, // DelegatingMethodHandle
- LF_EX_LINKER = 9, // invokeExact_MT (for invokehandle)
- LF_EX_INVOKER = 10, // MHs.invokeExact
- LF_GEN_LINKER = 11, // generic invoke_MT (for invokehandle)
- LF_GEN_INVOKER = 12, // generic MHs.invoke
- LF_CS_LINKER = 13, // linkToCallSite_CS
- LF_MH_LINKER = 14, // linkToCallSite_MH
- LF_GWC = 15, // guardWithCatch (catchException)
- LF_GWT = 16, // guardWithTest
- LF_LIMIT = 17;
+ LF_INVVIRTUAL = 0, // DMH invokeVirtual
+ LF_INVSTATIC = 1,
+ LF_INVSPECIAL = 2,
+ LF_NEWINVSPECIAL = 3,
+ LF_INVINTERFACE = 4,
+ LF_INVSTATIC_INIT = 5, // DMH invokeStatic with <clinit> barrier
+ LF_INTERPRET = 6, // LF interpreter
+ LF_REBIND = 7, // BoundMethodHandle
+ LF_DELEGATE = 8, // DelegatingMethodHandle
+ LF_DELEGATE_BLOCK_INLINING = 9, // Counting DelegatingMethodHandle w/ @DontInline
+ LF_EX_LINKER = 10, // invokeExact_MT (for invokehandle)
+ LF_EX_INVOKER = 11, // MHs.invokeExact
+ LF_GEN_LINKER = 12, // generic invoke_MT (for invokehandle)
+ LF_GEN_INVOKER = 13, // generic MHs.invoke
+ LF_CS_LINKER = 14, // linkToCallSite_CS
+ LF_MH_LINKER = 15, // linkToCallSite_MH
+ LF_GWC = 16, // guardWithCatch (catchException)
+ LF_GWT = 17, // guardWithTest
+ LF_LIMIT = 18;
/** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object.