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 }