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