1 /*
2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 
25 package org.graalvm.compiler.hotspot.test;
26 
27 import java.lang.management.ManagementFactory;
28 import java.lang.management.MonitorInfo;
29 import java.lang.management.ThreadInfo;
30 import java.lang.management.ThreadMXBean;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 
36 import jdk.internal.vm.compiler.collections.EconomicMap;
37 import org.graalvm.compiler.api.directives.GraalDirectives;
38 import org.graalvm.compiler.core.phases.HighTier;
39 import org.graalvm.compiler.debug.DebugContext;
40 import org.graalvm.compiler.debug.GraalError;
41 import org.graalvm.compiler.debug.TTY;
42 import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase;
43 import org.graalvm.compiler.options.OptionKey;
44 import org.graalvm.compiler.options.OptionValues;
45 import org.graalvm.compiler.serviceprovider.GraalServices;
46 import org.junit.Assert;
47 import org.junit.Assume;
48 import org.junit.BeforeClass;
49 import org.junit.Test;
50 
51 import jdk.vm.ci.meta.ResolvedJavaMethod;
52 
53 /**
54  * Test on-stack-replacement with locks.
55  */
56 public class GraalOSRLockTest extends GraalOSRTestBase {
57 
58     private static boolean TestInSeparateThread = false;
59     private static final String COMPILE_ONLY_FLAG = "-Xcomp";
60 
61     @BeforeClass
checkVMArguments()62     public static void checkVMArguments() {
63         assumeManagementLibraryIsLoadable();
64         /*
65          * Note: The -Xcomp execution mode of the VM will stop most of the OSR test cases from
66          * working as every method is compiled at level3 (followed by level4 on the second
67          * invocation). The tests in this class are written in a way that they expect a method to be
68          * executed at the invocation BCI with the interpreter and then perform an OSR to an
69          * installed nmethod at a given BCI.
70          *
71          */
72         List<String> arguments = GraalServices.getInputArguments();
73         Assume.assumeTrue("cannot check for monitors without", arguments != null);
74         for (String arg : arguments) {
75             Assume.assumeFalse(arg.equals(COMPILE_ONLY_FLAG));
76         }
77     }
78 
79     // testing only
isMonitorLockHeld(Object o)80     public static boolean isMonitorLockHeld(Object o) {
81         return isMonitorLockHeldByThread(o, null);
82     }
83 
isMonitorLockHeldByThread(Object o, Thread t)84     public static boolean isMonitorLockHeldByThread(Object o, Thread t) {
85         int oihc = System.identityHashCode(o);
86         ThreadMXBean tmxbean = ManagementFactory.getThreadMXBean();
87         ThreadInfo[] tinfos = tmxbean.dumpAllThreads(true, false);
88 
89         for (ThreadInfo ti : tinfos) {
90             if (!(t != null && t.getId() != ti.getThreadId())) {
91                 for (MonitorInfo mi : ti.getLockedMonitors()) {
92                     if (mi.getIdentityHashCode() == oihc) {
93                         return true;
94                     }
95                 }
96             }
97         }
98         return false;
99     }
100 
run(Runnable r)101     protected static void run(Runnable r) {
102         if (TestInSeparateThread) {
103             Thread t = new Thread(new Runnable() {
104                 @Override
105                 public void run() {
106                     beforeOSRLockTest();
107                     r.run();
108                     afterOSRLockTest();
109                 }
110             });
111             t.start();
112             try {
113                 t.join();
114             } catch (Throwable t1) {
115                 throw new GraalError(t1);
116             }
117         } else {
118             beforeOSRLockTest();
119             r.run();
120             afterOSRLockTest();
121         }
122     }
123 
wasLocked()124     private static boolean wasLocked() {
125         return isMonitorLockHeld(lock) || isMonitorLockHeld(lock1);
126     }
127 
osrLockNoDeopt()128     protected static EconomicMap<OptionKey<?>, Object> osrLockNoDeopt() {
129         EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
130         overrides.put(OnStackReplacementPhase.Options.DeoptAfterOSR, false);
131         overrides.put(OnStackReplacementPhase.Options.SupportOSRWithLocks, true);
132         return overrides;
133     }
134 
osrLockDeopt()135     protected static EconomicMap<OptionKey<?>, Object> osrLockDeopt() {
136         EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
137         overrides.put(OnStackReplacementPhase.Options.SupportOSRWithLocks, true);
138         return overrides;
139     }
140 
141     public static int SideEffectI;
142 
lockOnObject(Object o, String msg)143     private static void lockOnObject(Object o, String msg) {
144         Thread t = new Thread(new Runnable() {
145             @Override
146             public void run() {
147                 synchronized (o) {
148                     SideEffectI = 1;
149                 }
150             }
151         });
152         t.start();
153         try {
154             t.join(1000);
155         } catch (InterruptedException e) {
156             Assert.fail("Object " + msg + " was locked");
157         }
158     }
159 
beforeOSRLockTest()160     private static void beforeOSRLockTest() {
161         // try lock both objects
162         lockOnObject(lock, "lock");
163         lockOnObject(lock1, "lock1");
164         Assert.assertFalse(wasLocked());
165     }
166 
afterOSRLockTest()167     private static void afterOSRLockTest() {
168         // try lock both objects
169         lockOnObject(lock, "lock");
170         lockOnObject(lock1, "lock1");
171         Assert.assertFalse(wasLocked());
172         // force a safepoint and hope the inflated locks are deflated
173         System.gc();
174     }
175 
176     // @Test
177     @SuppressWarnings("try")
testLockOSROuterImmediateDeoptAfter()178     public void testLockOSROuterImmediateDeoptAfter() {
179         run(() -> {
180             OptionValues options = new OptionValues(getInitialOptions(), osrLockDeopt());
181             testOSR(options, "testOuterLockImmediateDeoptAfter");
182         });
183     }
184 
185     static class A {
186 
187     }
188 
189     static class B {
190         @SuppressWarnings("unused")
B(A a)191         B(A a) {
192 
193         }
194     }
195 
196     HashMap<String, HashSet<A>> listeners = new HashMap<>();
197 
synchronizedSnippet()198     public synchronized ReturnValue synchronizedSnippet() {
199         /*
200          * Test method for which liveness would conclude the original object is no longer alive
201          * although it is.
202          */
203         Collection<HashSet<A>> allListeners = listeners.values();
204         for (HashSet<A> group : allListeners) {
205             GraalDirectives.blackhole(group);
206         }
207         return ReturnValue.SUCCESS;
208     }
209 
210     @Test
211     @SuppressWarnings("try")
testSynchronizedSnippet()212     public void testSynchronizedSnippet() {
213         GraalOSRLockTest instance = new GraalOSRLockTest();
214         // enough entries to trigger OSR
215         for (int i = 0; i < 100000; i++) {
216             instance.listeners.put("hello" + i, null);
217         }
218         testOSR(getInitialOptions(), "synchronizedSnippet", instance);
219         Assert.assertFalse(isMonitorLockHeld(instance));
220     }
221 
222     @Test
223     @SuppressWarnings("try")
testOSRTrivialLoop()224     public void testOSRTrivialLoop() {
225         run(() -> {
226             OptionValues options = new OptionValues(getInitialOptions(), osrLockDeopt());
227             try {
228                 testOSR(options, "testReduceOSRTrivialLoop");
229             } catch (Throwable t) {
230                 Assert.assertEquals("OSR compilation without OSR entry loop.", t.getMessage());
231             }
232         });
233     }
234 
235     @Test
236     @SuppressWarnings("try")
testLockOSROuterInnerImmediateDeoptAfter()237     public void testLockOSROuterInnerImmediateDeoptAfter() {
238         run(() -> {
239             OptionValues options = new OptionValues(getInitialOptions(), osrLockDeopt());
240             testOSR(options, "testOuterInnerLockImmediateDeoptAfter");
241         });
242     }
243 
244     @Test
245     @SuppressWarnings("try")
testLockOSROuterCompileRestOfMethod()246     public void testLockOSROuterCompileRestOfMethod() {
247         run(() -> {
248             EconomicMap<OptionKey<?>, Object> overrides = osrLockNoDeopt();
249             overrides.put(HighTier.Options.Inline, false);
250             OptionValues options = new OptionValues(getInitialOptions(), overrides);
251             testOSR(options, "testOuterLockCompileRestOfMethod");
252         });
253     }
254 
255     @Test
256     @SuppressWarnings("try")
testLockOSROuterInnerCompileRestOfMethod()257     public void testLockOSROuterInnerCompileRestOfMethod() {
258         run(() -> {
259             OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt());
260             testOSR(options, "testOuterInnerLockCompileRestOfMethod");
261         });
262     }
263 
264     @Test
265     @SuppressWarnings("try")
testLockOSROuterInnerLockDepthCompileRestOfMethod()266     public void testLockOSROuterInnerLockDepthCompileRestOfMethod() {
267         run(() -> {
268             EconomicMap<OptionKey<?>, Object> overrides = osrLockNoDeopt();
269             overrides.put(HighTier.Options.Inline, false);
270             OptionValues options = new OptionValues(getInitialOptions(), overrides);
271             testOSR(options, "testOuterInnerLockDepth1CompileRestOfMethod");
272         });
273     }
274 
275     @Test
276     @SuppressWarnings("try")
testLockOSROuterInnerLockDepthDeopt()277     public void testLockOSROuterInnerLockDepthDeopt() {
278         run(() -> {
279             EconomicMap<OptionKey<?>, Object> overrides = osrLockNoDeopt();
280             overrides.put(HighTier.Options.Inline, false);
281             OptionValues options = new OptionValues(getInitialOptions(), overrides);
282             testOSR(options, "testOuterInnerLockDepth1DeoptAfter");
283         });
284     }
285 
286     @Test
287     @SuppressWarnings("try")
testLockOSROuterInnerLockDepthRecursiveCompileRestOfMethod0()288     public void testLockOSROuterInnerLockDepthRecursiveCompileRestOfMethod0() {
289         run(() -> {
290             OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt());
291             testOSR(options, "testOuterInnerLockDepth1RecursiveCompileRestOfMethod1");
292         });
293     }
294 
295     @Test
296     @SuppressWarnings("try")
testLockOSROuterInnerLockDepthRecursiveCompileRestOfMethod1()297     public void testLockOSROuterInnerLockDepthRecursiveCompileRestOfMethod1() {
298         run(() -> {
299             OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt());
300             testOSR(options, "testOuterInnerLockDepth1RecursiveCompileRestOfMethod2");
301         });
302     }
303 
304     @Test
305     @SuppressWarnings("try")
testLockOSROuterCompileRestOfMethodSubsequentLock()306     public void testLockOSROuterCompileRestOfMethodSubsequentLock() {
307         run(() -> {
308             OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt());
309             testOSR(options, "testOuterLockCompileRestOfMethodSubsequentLock");
310         });
311     }
312 
313     @Test
314     @SuppressWarnings("try")
testLockOSROuterInnerSameLockCompileRestOfMethod()315     public void testLockOSROuterInnerSameLockCompileRestOfMethod() {
316         run(() -> {
317             OptionValues options = new OptionValues(getInitialOptions(), osrLockNoDeopt());
318             testOSR(options, "testOuterInnerSameLockCompileRestOfMethod");
319         });
320     }
321 
322     @Test
323     @SuppressWarnings("try")
testLockOSRRecursive()324     public void testLockOSRRecursive() {
325         run(() -> {
326             // call it
327             testRecursiveLockingLeaf();
328             ResolvedJavaMethod leaf = getResolvedJavaMethod("testRecursiveLockingLeaf");
329             // profile it
330             leaf.reprofile();
331             testRecursiveLockingLeaf();
332             EconomicMap<OptionKey<?>, Object> overrides = osrLockNoDeopt();
333             overrides.put(HighTier.Options.Inline, false);
334             OptionValues options = new OptionValues(getInitialOptions(), overrides);
335             DebugContext debug = getDebugContext(options);
336             compile(debug, leaf, -1);
337             testOSR(options, "testRecursiveLockingRoot");
338         });
339     }
340 
341     @Test
342     @SuppressWarnings("try")
testLockOSRRecursiveLeafOSR()343     public void testLockOSRRecursiveLeafOSR() {
344         run(() -> {
345             testRecursiveRootNoOSR();
346             ResolvedJavaMethod root = getResolvedJavaMethod("testRecursiveRootNoOSR");
347             EconomicMap<OptionKey<?>, Object> overrides = osrLockNoDeopt();
348             overrides.put(HighTier.Options.Inline, false);
349             OptionValues options = new OptionValues(getInitialOptions(), overrides);
350             DebugContext debug = getDebugContext(options);
351             compile(debug, root, -1);
352             testOSR(options, "testRecursiveLeafOSR");
353             // force a safepoint and hope the inflated locks are deflated
354             System.gc();
355             // call the root to call into the leaf and enter the osr-ed code
356             testRecursiveRootNoOSR();
357 
358         });
359     }
360 
361     protected static int limit = 10000;
362     protected static Object lock = new Object();
363     protected static Object lock1 = new Object();
364     private static final boolean LOG = false;
365 
366     static {
367         // force identity hash code for easy displaced mark identification
368         int h1 = System.identityHashCode(lock);
369         int h2 = System.identityHashCode(lock1);
370         if (LOG) {
371             TTY.println("Forcing a system identity hashcode on lock object " + h1);
372             TTY.println("Forcing a system identity hashcode on lock1 object " + h2);
373         }
374     }
375 
testReduceOSRTrivialLoop()376     public static ReturnValue testReduceOSRTrivialLoop() {
377         for (int i = 0; i < limit * limit; i++) {
378             GraalDirectives.blackhole(i);
379             if (GraalDirectives.inCompiledCode()) {
380                 return ReturnValue.SUCCESS;
381             }
382         }
383         return ReturnValue.FAILURE;
384     }
385 
testOuterLockImmediateDeoptAfter()386     public static ReturnValue testOuterLockImmediateDeoptAfter() {
387         ReturnValue ret = ReturnValue.FAILURE;
388         synchronized (lock) {
389             for (int i = 1; i < 10 * limit; i++) {
390                 GraalDirectives.blackhole(i);
391                 if (i % 33 == 0) {
392                     ret = ReturnValue.SUCCESS;
393                     if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
394                         GraalDirectives.blackhole(ret);
395                     }
396                 }
397             }
398             GraalDirectives.controlFlowAnchor();
399             if (GraalDirectives.inCompiledCode()) {
400                 throw new Error("Must not be part of compiled code");
401             }
402             return ret;
403         }
404     }
405 
testOuterInnerLockImmediateDeoptAfter()406     public static ReturnValue testOuterInnerLockImmediateDeoptAfter() {
407         ReturnValue ret = ReturnValue.FAILURE;
408         synchronized (lock) {
409             for (int i = 1; i < 10 * limit; i++) {
410                 synchronized (lock1) {
411                     GraalDirectives.blackhole(i);
412                     if (i % 33 == 0) {
413                         ret = ReturnValue.SUCCESS;
414                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
415                             GraalDirectives.blackhole(ret);
416                         }
417                     }
418                 }
419             }
420             GraalDirectives.controlFlowAnchor();
421             GraalDirectives.deoptimize();
422             return ret;
423         }
424     }
425 
testOuterLockCompileRestOfMethod()426     public static ReturnValue testOuterLockCompileRestOfMethod() {
427         ReturnValue ret = ReturnValue.FAILURE;
428         synchronized (lock) {
429             for (int i = 1; i < limit; i++) {
430                 GraalDirectives.blackhole(i);
431                 if (i % 1001 == 0) {
432                     ret = ReturnValue.SUCCESS;
433                     System.gc();
434                 }
435             }
436             return ret;
437         }
438     }
439 
testOuterInnerLockCompileRestOfMethod()440     public static ReturnValue testOuterInnerLockCompileRestOfMethod() {
441         ReturnValue ret = ReturnValue.FAILURE;
442         synchronized (lock) {
443             for (int i = 1; i < 10 * limit; i++) {
444                 synchronized (lock1) {
445                     GraalDirectives.blackhole(i);
446                     if (i % 33 == 0) {
447                         ret = ReturnValue.SUCCESS;
448                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
449                             GraalDirectives.blackhole(ret);
450                             System.gc();
451                         }
452                     }
453                 }
454             }
455             GraalDirectives.controlFlowAnchor();
456             if (!GraalDirectives.inCompiledCode()) {
457                 throw new Error("Must be part of compiled code");
458             }
459             return ret;
460         }
461     }
462 
testOuterInnerLockDepth1CompileRestOfMethod()463     public static ReturnValue testOuterInnerLockDepth1CompileRestOfMethod() {
464         // testing the order of the lock releasing
465         ReturnValue ret = ReturnValue.FAILURE;
466         synchronized (lock) {
467             synchronized (lock1) {
468                 for (int i = 1; i < 10 * limit; i++) {
469                     GraalDirectives.blackhole(i);
470                     if (i % 33 == 0) {
471                         ret = ReturnValue.SUCCESS;
472                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
473                             GraalDirectives.blackhole(ret);
474                             System.gc();
475                         }
476                     }
477                 }
478             }
479             GraalDirectives.controlFlowAnchor();
480             if (!GraalDirectives.inCompiledCode()) {
481                 throw new Error("Must be part of compiled code already hereeeeee");
482             } else {
483                 // lock 1 must be free
484                 if (isMonitorLockHeld(lock1)) {
485                     throw new Error("Lock 1 must have been released already");
486                 }
487 
488                 // lock 2 must still be locked and cannot be acquired by another thread
489                 if (!isMonitorLockHeldByThread(lock, Thread.currentThread())) {
490                     throw new Error("Lock must not have been released already");
491                 }
492             }
493             return ret;
494         }
495     }
496 
testOuterInnerLockDepth1DeoptAfter()497     public static ReturnValue testOuterInnerLockDepth1DeoptAfter() {
498         // testing the order of the lock releasing
499         ReturnValue ret = ReturnValue.FAILURE;
500         synchronized (lock) {
501             synchronized (lock1) {
502                 for (int i = 1; i < 10 * limit; i++) {
503                     GraalDirectives.blackhole(i);
504                     if (i % 33 == 0) {
505                         ret = ReturnValue.SUCCESS;
506                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
507                             GraalDirectives.blackhole(ret);
508                         }
509                     }
510                 }
511                 GraalDirectives.controlFlowAnchor();
512                 GraalDirectives.deoptimize();
513                 if (GraalDirectives.inCompiledCode()) {
514                     throw new Error("Must not part of compiled code");
515                 }
516             }
517         }
518         return ret;
519     }
520 
testOuterInnerLockDepth1RecursiveCompileRestOfMethod1()521     public static ReturnValue testOuterInnerLockDepth1RecursiveCompileRestOfMethod1() {
522         // testing the order of the lock releasing
523         ReturnValue ret = ReturnValue.FAILURE;
524         synchronized (lock) {
525             synchronized (lock) {
526                 for (int i = 1; i < 10 * limit; i++) {
527                     GraalDirectives.blackhole(i);
528                     if (i % 33 == 0) {
529                         ret = ReturnValue.SUCCESS;
530                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
531                             GraalDirectives.blackhole(ret);
532                         }
533                     }
534                 }
535             }
536             GraalDirectives.controlFlowAnchor();
537             if (!GraalDirectives.inCompiledCode()) {
538                 throw new Error("Must be part of compiled code");
539             }
540             return ret;
541         }
542     }
543 
testOuterInnerLockDepth1RecursiveCompileRestOfMethod2()544     public static ReturnValue testOuterInnerLockDepth1RecursiveCompileRestOfMethod2() {
545         // testing the order of the lock releasing
546         final Object l = lock;
547         ReturnValue ret = ReturnValue.FAILURE;
548         synchronized (l) {
549             synchronized (l) {
550                 for (int i = 1; i < 10 * limit; i++) {
551                     GraalDirectives.blackhole(i);
552                     if (i % 33 == 0) {
553                         ret = ReturnValue.SUCCESS;
554                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
555                             GraalDirectives.blackhole(ret);
556                         }
557                     }
558                 }
559             }
560             GraalDirectives.controlFlowAnchor();
561             if (!GraalDirectives.inCompiledCode()) {
562                 throw new Error("Must be part of compiled code");
563             }
564             return ret;
565         }
566     }
567 
testRecursiveLockingRoot()568     public static ReturnValue testRecursiveLockingRoot() {
569         // testing the order of the lock releasing
570         final Object l = lock;
571         ReturnValue ret = ReturnValue.FAILURE;
572         synchronized (l) {
573             synchronized (l) {
574                 for (int i = 1; i < limit; i++) {
575                     GraalDirectives.blackhole(i);
576                     testRecursiveLockingLeaf();
577                     if (i % 33 == 0) {
578                         ret = ReturnValue.SUCCESS;
579                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
580                             GraalDirectives.blackhole(ret);
581                         }
582                     }
583                 }
584             }
585             GraalDirectives.controlFlowAnchor();
586             if (!GraalDirectives.inCompiledCode()) {
587                 throw new Error("Must be part of compiled code");
588             }
589             return ret;
590         }
591     }
592 
testRecursiveLockingLeaf()593     public static ReturnValue testRecursiveLockingLeaf() {
594         // testing the order of the lock releasing
595         final Object l = lock;
596         ReturnValue ret = ReturnValue.FAILURE;
597         synchronized (l) {
598             synchronized (l) {
599                 for (int i = 1; i < limit; i++) {
600                     GraalDirectives.blackhole(i);
601                     if (i % 33 == 0) {
602                         ret = ReturnValue.SUCCESS;
603                     }
604                 }
605             }
606             return ret;
607         }
608     }
609 
testRecursiveRootNoOSR()610     public static ReturnValue testRecursiveRootNoOSR() {
611         // testing the order of the lock releasing
612         final Object l = lock;
613         synchronized (l) {
614             ReturnValue ret = ReturnValue.FAILURE;
615             for (int i = 0; i < 5; i++) {
616                 if (GraalDirectives.inCompiledCode()) {
617                     ret = testRecursiveLeafOSR();
618                 }
619                 GraalDirectives.controlFlowAnchor();
620                 if (ret == ReturnValue.FAILURE) {
621                     return ret;
622                 }
623             }
624             GraalDirectives.controlFlowAnchor();
625             return ret;
626         }
627     }
628 
testRecursiveLeafOSR()629     public static ReturnValue testRecursiveLeafOSR() {
630         ReturnValue ret = ReturnValue.FAILURE;
631         // lock is already locked by the caller
632         synchronized (lock) {
633             for (int i = 1; i < 10 * limit; i++) {
634                 GraalDirectives.blackhole(i);
635                 if (i % 33 == 0) {
636                     ret = ReturnValue.SUCCESS;
637                     if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
638                         GraalDirectives.blackhole(ret);
639                     }
640                 }
641             }
642             GraalDirectives.controlFlowAnchor();
643             return ret;
644         }
645     }
646 
647     // test cases for optimizations
testOuterLockCompileRestOfMethodSubsequentLock()648     public static ReturnValue testOuterLockCompileRestOfMethodSubsequentLock() {
649         final Object monitor = lock;
650         ReturnValue ret = ReturnValue.FAILURE;
651         synchronized (monitor) {
652             for (int i = 1; i < 10 * limit; i++) {
653                 GraalDirectives.blackhole(i);
654                 if (i % 33 == 0) {
655                     ret = ReturnValue.SUCCESS;
656                     if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
657                         GraalDirectives.blackhole(ret);
658                     }
659                 }
660             }
661         }
662         synchronized (monitor) {
663             GraalDirectives.controlFlowAnchor();
664             if (!GraalDirectives.inCompiledCode()) {
665                 throw new Error("Must be part of compiled code");
666             }
667         }
668         return ret;
669 
670     }
671 
testOuterInnerSameLockCompileRestOfMethod()672     public static ReturnValue testOuterInnerSameLockCompileRestOfMethod() {
673         final Object monitor = lock;
674         ReturnValue ret = ReturnValue.FAILURE;
675         synchronized (monitor) {
676             for (int i = 1; i < 10 * limit; i++) {
677                 synchronized (monitor) {
678                     GraalDirectives.blackhole(i);
679                     if (i % 33 == 0) {
680                         ret = ReturnValue.SUCCESS;
681                         if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
682                             GraalDirectives.blackhole(ret);
683                         }
684                     }
685                 }
686             }
687             GraalDirectives.controlFlowAnchor();
688             if (!GraalDirectives.inCompiledCode()) {
689                 throw new Error("Must be part of compiled code");
690             }
691             return ret;
692         }
693     }
694 
695 }
696