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