1 /*
   2  * Copyright (c) 2016, 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
  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
  80     public static boolean isMonitorLockHeld(Object o) {
  81         return isMonitorLockHeldByThread(o, null);
  82     }
  83 
  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 
 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 
 124     private static boolean wasLocked() {
 125         return isMonitorLockHeld(lock) || isMonitorLockHeld(lock1);
 126     }
 127 
 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 
 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 
 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 
 160     private static void beforeOSRLockTest() {
 161         // try lock both objects
 162         lockOnObject(lock, "lock");
 163         lockOnObject(lock1, "lock1");
 164         Assert.assertFalse(wasLocked());
 165     }
 166 
 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")
 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")
 191         B(A a) {
 192 
 193         }
 194     }
 195 
 196     HashMap<String, HashSet<A>> listeners = new HashMap<>();
 197 
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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")
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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
 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 
 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 }