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