< 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 >