< prev index next >
src/java.base/share/classes/java/lang/invoke/LambdaForm.java
Print this page
rev 14964 : 8160717: MethodHandles.loop() does not check for excessive signature
@@ -23,10 +23,11 @@
* questions.
*/
package java.lang.invoke;
+import jdk.internal.perf.PerfCounter;
import jdk.internal.vm.annotation.DontInline;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import java.lang.annotation.ElementType;
@@ -37,12 +38,11 @@
import java.util.Arrays;
import java.util.HashMap;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
-import static java.lang.invoke.MethodHandleStatics.debugEnabled;
-import static java.lang.invoke.MethodHandleStatics.newInternalError;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* The symbolic, non-executable form of a method handle's invocation semantics.
* It consists of a series of names.
* The first N (N=arity) names are parameters,
@@ -394,11 +394,11 @@
}
/** Customize LambdaForm for a particular MethodHandle */
LambdaForm customize(MethodHandle mh) {
LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh);
- if (COMPILE_THRESHOLD > 0 && isCompiled) {
+ if (COMPILE_THRESHOLD >= 0 && isCompiled) {
// If shared LambdaForm has been compiled, compile customized version as well.
customForm.compileToBytecode();
}
customForm.transformCache = this; // LambdaFormEditor should always use uncustomized form.
return customForm;
@@ -409,11 +409,11 @@
if (customized == null) {
return this;
}
assert(transformCache != null); // Customized LambdaForm should always has a link to uncustomized version.
LambdaForm uncustomizedForm = (LambdaForm)transformCache;
- if (COMPILE_THRESHOLD > 0 && isCompiled) {
+ if (COMPILE_THRESHOLD >= 0 && isCompiled) {
// If customized LambdaForm has been compiled, compile uncustomized version as well.
uncustomizedForm.compileToBytecode();
}
return uncustomizedForm;
}
@@ -715,11 +715,11 @@
* before invocation.
* (In principle, the JVM could do this very lazily,
* as a sort of pre-invocation linkage step.)
*/
public void prepare() {
- if (COMPILE_THRESHOLD == 0 && !isCompiled) {
+ if (COMPILE_THRESHOLD == 0 && !forceInterpretation() && !isCompiled) {
compileToBytecode();
}
if (this.vmentry != null) {
// already prepared (e.g., a primitive DMH invoker form)
return;
@@ -734,25 +734,38 @@
}
this.vmentry = prep.vmentry;
// TO DO: Maybe add invokeGeneric, invokeWithArguments
}
+ private static final PerfCounter LF_FAILED =
+ PerfCounter.newPerfCounter("java.lang.invoke.failedLambdaFormCompilations");
+
/** Generate optimizable bytecode for this form. */
- MemberName compileToBytecode() {
+ void compileToBytecode() {
+ if (forceInterpretation()) {
+ return; // this should not be compiled
+ }
if (vmentry != null && isCompiled) {
- return vmentry; // already compiled somehow
+ return; // already compiled somehow
}
MethodType invokerType = methodType();
assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
try {
vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
if (TRACE_INTERPRETER)
traceInterpreter("compileToBytecode", this);
isCompiled = true;
- return vmentry;
- } catch (Error | Exception ex) {
- throw newInternalError(this.toString(), ex);
+ } catch (InvokerBytecodeGenerator.BytecodeGenerationException bge) {
+ // bytecode generation failed - mark this LambdaForm as to be run in interpretation mode only
+ invocationCounter = -1;
+ LF_FAILED.increment();
+ if (LOG_LF_COMPILATION_FAILURE) {
+ System.out.println("LambdaForm compilation failed: " + this);
+ bge.printStackTrace(System.out);
+ }
+ } catch (Error | Exception e) {
+ throw newInternalError(this.toString(), e);
}
}
private static void computeInitialPreparedForms() {
// Find all predefined invokers and associate them with canonical empty lambda forms.
@@ -854,11 +867,15 @@
/** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
private static final int COMPILE_THRESHOLD;
static {
COMPILE_THRESHOLD = Math.max(-1, MethodHandleStatics.COMPILE_THRESHOLD);
}
- private int invocationCounter = 0;
+ private int invocationCounter = 0; // a value of -1 indicates LambdaForm interpretation mode forever
+
+ private boolean forceInterpretation() {
+ return invocationCounter == -1;
+ }
@Hidden
@DontInline
/** Interpretively invoke this form on the given arguments. */
Object interpretWithArguments(Object... argumentValues) throws Throwable {
@@ -894,21 +911,21 @@
return name.function.invokeWithArguments(arguments);
}
private void checkInvocationCounter() {
if (COMPILE_THRESHOLD != 0 &&
- invocationCounter < COMPILE_THRESHOLD) {
+ !forceInterpretation() && invocationCounter < COMPILE_THRESHOLD) {
invocationCounter++; // benign race
if (invocationCounter >= COMPILE_THRESHOLD) {
// Replace vmentry with a bytecode version of this LF.
compileToBytecode();
}
}
}
Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
traceInterpreter("[ interpretWithArguments", this, argumentValues);
- if (invocationCounter < COMPILE_THRESHOLD) {
+ if (!forceInterpretation() && invocationCounter < COMPILE_THRESHOLD) {
int ctr = invocationCounter++; // benign race
traceInterpreter("| invocationCounter", ctr);
if (invocationCounter >= COMPILE_THRESHOLD) {
compileToBytecode();
}
< prev index next >