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