jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java
changeset 28405 53e900131e21
parent 27958 51c87937ff0c
child 31058 fbe6df60e104
equal deleted inserted replaced
28404:ca8570ff2a87 28405:53e900131e21
    28  * @author kshefov
    28  * @author kshefov
    29  * @library /lib/testlibrary/jsr292 /lib/testlibrary
    29  * @library /lib/testlibrary/jsr292 /lib/testlibrary
    30  * @build TestMethods
    30  * @build TestMethods
    31  * @build LambdaFormTestCase
    31  * @build LambdaFormTestCase
    32  * @build LFGarbageCollectedTest
    32  * @build LFGarbageCollectedTest
    33  * @run main/othervm LFGarbageCollectedTest
    33  * @run main/othervm -Xmx64m -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+HeapDumpOnOutOfMemoryError -DHEAP_DUMP=false LFGarbageCollectedTest
    34  */
    34  */
    35 
    35 
    36 import java.lang.invoke.MethodHandle;
    36 import java.lang.invoke.MethodHandle;
       
    37 import java.lang.invoke.MethodType;
    37 import java.lang.ref.PhantomReference;
    38 import java.lang.ref.PhantomReference;
       
    39 import java.lang.ref.Reference;
    38 import java.lang.ref.ReferenceQueue;
    40 import java.lang.ref.ReferenceQueue;
    39 import java.lang.reflect.InvocationTargetException;
    41 import java.lang.reflect.InvocationTargetException;
    40 import java.util.EnumSet;
    42 import java.util.EnumSet;
    41 import java.util.Map;
    43 import java.util.Map;
    42 
    44 
    43 /**
    45 /**
    44  * Lambda forms garbage collection test class.
    46  * Lambda forms garbage collection test class.
    45  */
    47  */
    46 public final class LFGarbageCollectedTest extends LambdaFormTestCase {
    48 public final class LFGarbageCollectedTest extends LambdaFormTestCase {
       
    49     private static boolean HEAP_DUMP = Boolean.getBoolean("HEAP_DUMP");
    47 
    50 
    48     /**
    51     /**
    49      * Constructor for a lambda forms garbage collection test case.
    52      * Constructor for a lambda forms garbage collection test case.
    50      *
    53      *
    51      * @param testMethod A method from {@code j.l.i.MethodHandles} class that
    54      * @param testMethod A method from {@code j.l.i.MethodHandles} class that
    53      */
    56      */
    54     public LFGarbageCollectedTest(TestMethods testMethod) {
    57     public LFGarbageCollectedTest(TestMethods testMethod) {
    55         super(testMethod);
    58         super(testMethod);
    56     }
    59     }
    57 
    60 
       
    61     PhantomReference ph;
       
    62     ReferenceQueue rq = new ReferenceQueue();
       
    63     MethodType mtype;
       
    64     Map<String, Object> data;
       
    65 
    58     @Override
    66     @Override
    59     public void doTest() {
    67     public void doTest() {
    60         try {
    68         try {
    61             Map<String, Object> data = getTestMethod().getTestCaseData();
    69             TestMethods testCase = getTestMethod();
       
    70             data = testCase.getTestCaseData();
    62             MethodHandle adapter;
    71             MethodHandle adapter;
    63             try {
    72             try {
    64                 adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE);
    73                 adapter = testCase.getTestCaseMH(data, TestMethods.Kind.ONE);
    65             } catch (NoSuchMethodException ex) {
    74             } catch (NoSuchMethodException ex) {
    66                 throw new Error("Unexpected exception: ", ex);
    75                 throw new Error("Unexpected exception: ", ex);
    67             }
    76             }
    68             Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter);
    77             mtype = adapter.type();
       
    78             Object lambdaForm = INTERNAL_FORM.invoke(adapter);
    69             if (lambdaForm == null) {
    79             if (lambdaForm == null) {
    70                 throw new Error("Unexpected error: Lambda form of the method handle is null");
    80                 throw new Error("Unexpected error: Lambda form of the method handle is null");
    71             }
    81             }
    72             ReferenceQueue rq = new ReferenceQueue();
    82 
    73             PhantomReference ph = new PhantomReference(lambdaForm, rq);
    83             String debugName = (String)DEBUG_NAME.get(lambdaForm);
       
    84             if (debugName != null && debugName.startsWith("identity_")) {
       
    85                 // Ignore identity_* LambdaForms.
       
    86                 return;
       
    87             }
       
    88 
       
    89             ph = new PhantomReference(lambdaForm, rq);
    74             lambdaForm = null;
    90             lambdaForm = null;
    75             data = null;
       
    76             adapter = null;
    91             adapter = null;
    77             for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) {
    92 
    78                 System.gc();
    93             collectLambdaForm();
    79             }
       
    80             if (!ph.isEnqueued()) {
       
    81                 throw new AssertionError("Error: Lambda form is not garbage collected");
       
    82             }
       
    83         } catch (IllegalAccessException | IllegalArgumentException |
    94         } catch (IllegalAccessException | IllegalArgumentException |
    84                 InvocationTargetException ex) {
    95                 InvocationTargetException ex) {
    85             throw new Error("Unexpected exception: ", ex);
    96             throw new Error("Unexpected exception: ", ex);
    86         }
    97         }
    87     }
    98     }
       
    99 
       
   100 
       
   101     private void collectLambdaForm() throws IllegalAccessException {
       
   102         // Usually, 2 System.GCs are necessary to enqueue a SoftReference.
       
   103         System.gc();
       
   104         System.gc();
       
   105 
       
   106         Reference ref = null;
       
   107         for (int i = 0; i < 10; i++) {
       
   108             try {
       
   109                 ref = rq.remove(1000);
       
   110             } catch (InterruptedException e) {
       
   111                 /* ignore */
       
   112             }
       
   113             if (ref != null) {
       
   114                 break;
       
   115             }
       
   116             System.gc(); // If the reference hasn't been queued yet, trigger one more GC.
       
   117         }
       
   118 
       
   119         if (ref == null) {
       
   120             dumpTestData();
       
   121             System.err.println("Method type: " + mtype);
       
   122             System.err.println("LambdaForm:  " + REF_FIELD.get(ph));
       
   123 
       
   124             if (HEAP_DUMP) {
       
   125                 // Trigger OOM to force heap dump for post-mortem analysis.
       
   126                 val = new long[1_000_000_000];
       
   127             }
       
   128             throw new AssertionError("Error: LambdaForm is not garbage collected");
       
   129         };
       
   130     }
       
   131 
       
   132     private void dumpTestData() {
       
   133         System.err.println("Test case: " + getTestMethod());
       
   134         for (String s : data.keySet()) {
       
   135             System.err.printf("\t%20s => %s\n", s, data.get(s));
       
   136         }
       
   137     }
       
   138 
       
   139     private static long[] val;
    88 
   140 
    89     /**
   141     /**
    90      * Main routine for lambda forms garbage collection test.
   142      * Main routine for lambda forms garbage collection test.
    91      *
   143      *
    92      * @param args Accepts no arguments.
   144      * @param args Accepts no arguments.
    99         // so no memory leak happens.
   151         // so no memory leak happens.
   100         EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(
   152         EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(
   101                 TestMethods.IDENTITY,
   153                 TestMethods.IDENTITY,
   102                 TestMethods.CONSTANT,
   154                 TestMethods.CONSTANT,
   103                 TestMethods.ARRAY_ELEMENT_GETTER,
   155                 TestMethods.ARRAY_ELEMENT_GETTER,
   104                 TestMethods.ARRAY_ELEMENT_SETTER));
   156                 TestMethods.ARRAY_ELEMENT_SETTER,
       
   157                 TestMethods.EXACT_INVOKER,
       
   158                 TestMethods.INVOKER));
   105         LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods);
   159         LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods);
   106     }
   160     }
   107 }
   161 }