1 /*
   2  * Copyright (c) 2020 SAP SE. 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  * @test
  26  * @bug 8230956
  27  * @summary JVMTI agents can obtain references to not escaping objects using JVMTI Heap functions.
  28  *          Therefore optimizations based on escape analysis have to be reverted,
  29  *          i.e. scalar replaced objects need to be reallocated on the heap and objects with eliminated locking
  30  *          need to be relocked.
  31  * @requires ((vm.compMode == "Xmixed") & vm.compiler2.enabled)
  32  * @library /test/lib /test/hotspot/jtreg
  33  * @build sun.hotspot.WhiteBox
  34  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  35  * @compile IterateHeapWithEscapeAnalysisEnabled.java
  36  *
  37  * @comment BLOCK BEGIN EXCLUSIVE TESTCASES {
  38  *
  39  *          The following test cases are executed in fresh VMs, because they require that the
  40  *          capability can_tag_objects is not taken until dontinline_testMethod is jit compiled and
  41  *          an activation of the compiled version is on stack of the target thread.
  42  *
  43  *          Without JDK-8227745 these test cases require that escape analysis is disabled at
  44  *          start-up, because can_tag_objects can be taken lazily, potentially after loading an
  45  *          agent dynamically by means of the attach API. Disabling escape analysis and invalidating
  46  *          compiled methods does not help then, because there may be compiled frames with ea-based
  47  *          optimizations on stack. Just like in this collection of test cases.
  48  *
  49  * @run main/othervm/native
  50  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
  51  *                  -XX:+UnlockDiagnosticVMOptions
  52  *                  -Xms256m -Xmx256m
  53  *                  -XX:+PrintCompilation -XX:+PrintInlining
  54  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  55  *                  -Xbatch
  56  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  57  *                  -XX:+DoEscapeAnalysis
  58  *                  IterateHeapWithEscapeAnalysisEnabled IterateOverReachableObjects
  59  * @run main/othervm/native
  60  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
  61  *                  -XX:+UnlockDiagnosticVMOptions
  62  *                  -Xms256m -Xmx256m
  63  *                  -XX:+PrintCompilation -XX:+PrintInlining
  64  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  65  *                  -Xbatch
  66  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  67  *                  -XX:+DoEscapeAnalysis
  68  *                  IterateHeapWithEscapeAnalysisEnabled IterateOverHeap
  69  * @run main/othervm/native
  70  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
  71  *                  -XX:+UnlockDiagnosticVMOptions
  72  *                  -Xms256m -Xmx256m
  73  *                  -XX:+PrintCompilation -XX:+PrintInlining
  74  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  75  *                  -Xbatch
  76  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  77  *                  -XX:+DoEscapeAnalysis
  78  *                  IterateHeapWithEscapeAnalysisEnabled IterateOverInstancesOfClass
  79  * @run main/othervm/native
  80  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
  81  *                  -XX:+UnlockDiagnosticVMOptions
  82  *                  -Xms256m -Xmx256m
  83  *                  -XX:+PrintCompilation -XX:+PrintInlining
  84  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  85  *                  -Xbatch
  86  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  87  *                  -XX:+DoEscapeAnalysis
  88  *                  IterateHeapWithEscapeAnalysisEnabled FollowReferences
  89  * @run main/othervm/native
  90  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
  91  *                  -XX:+UnlockDiagnosticVMOptions
  92  *                  -Xms256m -Xmx256m
  93  *                  -XX:+PrintCompilation -XX:+PrintInlining
  94  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
  95  *                  -Xbatch
  96  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  97  *                  -XX:+DoEscapeAnalysis
  98  *                  IterateHeapWithEscapeAnalysisEnabled IterateThroughHeap
  99  *
 100  * @comment } BLOCK END EXCLUSIVE TESTCASES
 101  *
 102  * @comment BLOCK BEGIN NON EXCLUSIVE TESTCASES {
 103  *
 104  * @run main/othervm/native
 105  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
 106  *                  -XX:+UnlockDiagnosticVMOptions
 107  *                  -Xms256m -Xmx256m
 108  *                  -XX:CompileCommand=dontinline,*::dontinline_*
 109  *                  -XX:+PrintCompilation
 110  *                  -XX:+PrintInlining
 111  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
 112  *                  -Xbatch
 113  *                  -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
 114  *                  IterateHeapWithEscapeAnalysisEnabled
 115  * @run main/othervm/native
 116  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
 117  *                  -XX:+UnlockDiagnosticVMOptions
 118  *                  -Xms256m -Xmx256m
 119  *                  -XX:CompileCommand=dontinline,*::dontinline_*
 120  *                  -XX:+PrintCompilation
 121  *                  -XX:+PrintInlining
 122  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
 123  *                  -Xbatch
 124  *                  -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
 125  *                  IterateHeapWithEscapeAnalysisEnabled
 126  * @run main/othervm/native
 127  *                  -agentlib:IterateHeapWithEscapeAnalysisEnabled
 128  *                  -XX:+UnlockDiagnosticVMOptions
 129  *                  -Xms256m -Xmx256m
 130  *                  -XX:CompileCommand=dontinline,*::dontinline_*
 131  *                  -XX:+PrintCompilation
 132  *                  -XX:+PrintInlining
 133  *                  -XX:+WhiteBoxAPI -Xbootclasspath/a:.
 134  *                  -Xbatch
 135  *                  -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
 136  *                  IterateHeapWithEscapeAnalysisEnabled
 137  *
 138  * @comment } BLOCK END NON EXCLUSIVE TESTCASES
 139  */
 140 
 141 import compiler.whitebox.CompilerWhiteBoxTest;
 142 import jdk.test.lib.Asserts;
 143 import sun.hotspot.WhiteBox;
 144 
 145 public class IterateHeapWithEscapeAnalysisEnabled {
 146 
 147     public static final WhiteBox WB = WhiteBox.getWhiteBox();
 148 
 149     public static final int COMPILE_THRESHOLD = CompilerWhiteBoxTest.THRESHOLD;
 150 
 151     public static native int jvmtiTagClass(Class<?> cls, long tag);
 152 
 153     // Methods to tag or count instances of a given class available in JVMTI
 154     public static enum TaggingAndCountingMethods {
 155         IterateOverReachableObjects,
 156         IterateOverHeap,
 157         IterateOverInstancesOfClass,
 158         FollowReferences,
 159         IterateThroughHeap
 160     }
 161 
 162     public static native int acquireCanTagObjectsCapability();
 163     public static native int registerMethod(TaggingAndCountingMethods m, String name);
 164     public static native void agentTearDown();
 165 
 166     /**
 167      * Count and tag instances of a given class.
 168      * @param cls Used by the method {@link TaggingAndCountingMethods#IterateOverInstancesOfClass} as class to count and tag instances of.
 169      *        Ignored by other counting methods.
 170      * @param clsTag Tag of the class to count and tag instances of. Used by all methods except
 171      *        {@link TaggingAndCountingMethods#IterateOverInstancesOfClass}
 172      * @param instanceTag The tag to be set for selected instances.
 173      * @param method JVMTI counting and tagging method to be used.
 174      * @return The number of instances or -1 if the call fails.
 175      */
 176     public static native int countAndTagInstancesOfClass(Class<?> cls, long clsTag, long instanceTag, TaggingAndCountingMethods method);
 177 
 178     /**
 179      * Get all objects tagged with the given tag.
 180      * @param tag The tag used to select objects.
 181      * @param result Selected objects are copied into this array.
 182      * @return -1 to indicated failure and 0 for success.
 183      */
 184     public static native int getObjectsWithTag(long tag, Object[] result);
 185 
 186     public static void main(String[] args) throws Exception {
 187         try {
 188             new IterateHeapWithEscapeAnalysisEnabled().runTestCases(args);
 189         } finally {
 190             agentTearDown();
 191         }
 192     }
 193 
 194     public void runTestCases(String[] args) throws Exception {
 195         // register various instance tagging and counting methods with agent
 196         for (TaggingAndCountingMethods m : TaggingAndCountingMethods.values()) {
 197             msg("register instance count method " + m.name());
 198             int rc = registerMethod(m, m.name());
 199             Asserts.assertGreaterThanOrEqual(rc, 0, "method " + m.name() + " is unknown to agent");
 200         }
 201 
 202         if (args.length > 0) {
 203             // EXCLUSIVE TEST CASES
 204             // cant_tag_objects is acquired after warmup. Use given tagging/counting method.
 205             new TestCase01(true, 100, TaggingAndCountingMethods.valueOf(args[0])).run();
 206         } else {
 207             // NON-EXCLUSIVE TEST CASES
 208             // cant_tag_objects is acquired before test cases are run, but still during live phase.
 209             msgHL("Acquire capability can_tag_objects before first test case.");
 210             int err = acquireCanTagObjectsCapability();
 211             Asserts.assertEQ(0, err, "acquireCanTagObjectsCapability FAILED");
 212 
 213             // run test cases
 214             for (TaggingAndCountingMethods m : TaggingAndCountingMethods.values()) {
 215                 new TestCase01(false, 200, m).run();
 216             }
 217             new TestCase02a(200).run();
 218             new TestCase02b(300).run();
 219         }
 220     }
 221 
 222     static class ABBox {
 223         public int aVal;
 224         public int bVal;
 225         public TestCaseBase testCase;
 226 
 227         public ABBox() { /* empty */ }
 228 
 229         public ABBox(TestCaseBase testCase) {
 230             this.testCase = testCase;
 231         }
 232 
 233         /**
 234          * Increment {@link #aVal} and {@link #bVal} under lock. The method is supposed to
 235          * be inlined into the test method and locking is supposed to be eliminated. After
 236          * this object escaped to the JVMTI agent, the code with eliminated locking must
 237          * not be used anymore.
 238          */
 239         public synchronized void synchronizedSlowInc() {
 240             aVal++;
 241             testCase.waitingForCheck = true;
 242             dontinline_waitForCheck(testCase);
 243             testCase.waitingForCheck = false;
 244             bVal++;
 245         }
 246 
 247         public static void dontinline_waitForCheck(TestCaseBase testCase) {
 248             if (testCase.warmUpDone) {
 249                 while(!testCase.checkingNow) {
 250                     try {
 251                         Thread.sleep(50);
 252                     } catch (InterruptedException e) { /*ign*/ }
 253                 }
 254             }
 255         }
 256 
 257         /**
 258          * This method and incrementing {@link #aVal} and {@link #bVal} are synchronized.
 259          * So {@link #aVal} and {@link #bVal} should always be equal. Unless the optimized version
 260          * of {@link #synchronizedSlowInc()} without locking is still used after this object
 261          * escaped to the JVMTI agent.
 262          * @return
 263          */
 264         public synchronized boolean check() {
 265             return aVal == bVal;
 266         }
 267     }
 268 
 269     public static abstract class TestCaseBase implements Runnable {
 270         public final long classTag;
 271         public long instanceTag;
 272 
 273         public final Class<?> taggedClass;
 274 
 275         public long checkSum;
 276         public long loopCount;
 277         public volatile boolean doLoop;
 278         public volatile boolean targetIsInLoop;
 279 
 280         public volatile boolean waitingForCheck;
 281         public volatile boolean checkingNow;
 282 
 283         public boolean warmUpDone;
 284 
 285         public TestCaseBase(long classTag, Class<?> taggedClass) {
 286             this.classTag = classTag;
 287             this.taggedClass = taggedClass;
 288         }
 289 
 290         public void setUp() {
 291             // Tag the class of instances to be scalar replaced
 292             msg("tagging " + taggedClass.getName() + " with tag " +  classTag);
 293             int err = jvmtiTagClass(taggedClass, classTag);
 294             Asserts.assertEQ(0, err, "jvmtiTagClass FAILED");
 295         }
 296 
 297         // to be overridden by test cases
 298         abstract public void dontinline_testMethod();
 299 
 300         public void warmUp() {
 301             msg("WarmUp: START");
 302             int callCount = COMPILE_THRESHOLD + 1000;
 303             doLoop = true;
 304             while (callCount-- > 0) {
 305                 dontinline_testMethod();
 306             }
 307             warmUpDone = true;
 308             msg("WarmUp: DONE");
 309         }
 310 
 311         public Object dontinline_endlessLoop(Object argEscape) {
 312             long cs = checkSum;
 313             while (loopCount-- > 0 && doLoop) {
 314                 targetIsInLoop = true;
 315                 checkSum += checkSum % ++cs;
 316             }
 317             loopCount = 3;
 318             targetIsInLoop = false;
 319             return argEscape;
 320         }
 321 
 322         public void waitUntilTargetThreadHasEnteredEndlessLoop() {
 323             while(!targetIsInLoop) {
 324                 msg("Target has not yet entered the loop. Sleep 100ms.");
 325                 try { Thread.sleep(100); } catch (InterruptedException e) { /*ignore */ }
 326             }
 327             msg("Target has entered the loop.");
 328         }
 329 
 330         public void terminateEndlessLoop() throws Exception {
 331             msg("Terminate endless loop");
 332             doLoop = false;
 333         }
 334     }
 335 
 336     /**
 337      * Use JVMTI heap functions associated with the elements of {@link TaggingAndCountingMethods} to
 338      * get a reference to an object allocated in {@link TestCase01#dontinline_testMethod()}. The
 339      * allocation can be eliminated / scalar replaced.  The test case can be run in two modes: (1)
 340      * the capability can_tag_objects which is required to use the JVMTI heap functions is taken
 341      * before the test case (2) the capability is taken after {@link TestCase01#dontinline_testMethod()}
 342      * is compiled and the target thread has an activation of it on stack.
 343      */
 344     public static class TestCase01 extends TestCaseBase {
 345 
 346         public volatile int testMethod_result;
 347         public boolean acquireCanTagObjectsCapabilityAfterWarmup;
 348         public TaggingAndCountingMethods taggingMethod;
 349 
 350         public TestCase01(boolean acquireCanTagObjectsCapabilityAfterWarmup, long classTag, TaggingAndCountingMethods taggingMethod) {
 351             super(classTag, ABBox.class);
 352             instanceTag = classTag + 1;
 353             this.acquireCanTagObjectsCapabilityAfterWarmup = acquireCanTagObjectsCapabilityAfterWarmup;
 354             this.taggingMethod = taggingMethod;
 355         }
 356 
 357         @Override
 358         public void setUp() {
 359             if (!acquireCanTagObjectsCapabilityAfterWarmup) {
 360                 super.setUp();
 361             }
 362         }
 363 
 364         public void setUpAfterWarmUp() {
 365             if (acquireCanTagObjectsCapabilityAfterWarmup) {
 366                 msg("Acquire capability can_tag_objects " + (warmUpDone ? "after" : "before") + " warmup.");
 367                 int err = acquireCanTagObjectsCapability();
 368                 Asserts.assertEQ(0, err, "acquireCanTagObjectsCapability FAILED");
 369                 super.setUp();
 370             }
 371         }
 372 
 373         public void run() {
 374             try {
 375                 msgHL(getClass().getName() + ": test if object that may be scalar replaced is found using " + taggingMethod);
 376                 msg("The capability can_tag_object is acquired " + (acquireCanTagObjectsCapabilityAfterWarmup ? "AFTER" : "BEFORE")
 377                         + " warmup.");
 378                 setUp();
 379                 warmUp();
 380                 WB.deflateIdleMonitors();
 381                 WB.fullGC(); // get rid of dead instances from previous test cases
 382                 runTest(taggingMethod);
 383             } catch (Exception e) {
 384                 Asserts.fail("Unexpected Exception", e);
 385             }
 386         }
 387 
 388         public void runTest(TaggingAndCountingMethods m) throws Exception {
 389             loopCount = 1L << 62; // endless loop
 390             doLoop = true;
 391             testMethod_result = 0;
 392             Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread (" + getClass().getName() + ")");
 393             try {
 394                 t1.start();
 395                 try {
 396                     waitUntilTargetThreadHasEnteredEndlessLoop();
 397                     setUpAfterWarmUp();
 398                     msg("count and tag instances of " + taggedClass.getName() + " with tag " + instanceTag + " using JVMTI " + m.name());
 399                     int count = countAndTagInstancesOfClass(taggedClass, classTag, instanceTag, m);
 400                     msg("Done. Count is " + count);
 401                     Asserts.assertGreaterThanOrEqual(count, 0, "countAndTagInstancesOfClass FAILED");
 402                     Asserts.assertEQ(count, 1, "unexpected number of instances");
 403 
 404                     ABBox[] result = new ABBox[1];
 405                     msg("get instances tagged with " + instanceTag + ". The instances escape thereby.");
 406                     int err = getObjectsWithTag(instanceTag, result);
 407                     msg("Done.");
 408                     Asserts.assertEQ(0, err, "getObjectsWithTag FAILED");
 409 
 410                     msg("change the now escaped instance' bVal");
 411                     ABBox abBox = result[0];
 412                     abBox.bVal = 3;
 413                     terminateEndlessLoop();
 414 
 415                     msg("wait until target thread has set testMethod_result");
 416                     while (testMethod_result == 0) {
 417                         Thread.sleep(50);
 418                     }
 419                     msg("check if the modification of bVal is reflected in testMethod_result.");
 420                     Asserts.assertEQ(7, testMethod_result, " testMethod_result has wrong value");
 421                     msg("ok.");
 422                 } finally {
 423                     terminateEndlessLoop();
 424                 }
 425             } finally {
 426                 t1.join();
 427             }
 428         }
 429 
 430         @Override
 431         public void dontinline_testMethod() {
 432             ABBox ab = new ABBox();     // can be scalar replaced
 433             ab.aVal = 4;
 434             ab.bVal = 2;
 435             dontinline_endlessLoop(null);   // JVMTI agent acquires reference to ab and changes bVal
 436             testMethod_result = ab.aVal + ab.bVal;
 437         }
 438     }
 439 
 440     /**
 441      * {@link #dontinline_testMethod()} creates an ArgEscape instance of {@link TestCaseBase#taggedClass} on stack.
 442      * The jvmti agent tags all instances of this class using one of the {@link TaggingAndCountingMethods}. Then it gets the tagged
 443      * instances using <code>GetObjectsWithTags()</code>. This is where the ArgEscape globally escapes.
 444      * It happens at a location without eliminated locking, but there is
 445      * eliminated locking following, so the compiled frame must be deoptimized. This is checked by letting the agent call the
 446      * synchronized method {@link ABBox#check()} on the escaped instance.
 447      */
 448     public static class TestCase02a extends TestCaseBase {
 449 
 450         public long instanceTag;
 451 
 452         public TestCase02a(long classTag) {
 453             super(classTag, ABBox.class);
 454             instanceTag = classTag + 1;
 455         }
 456 
 457         public void run() {
 458             try {
 459                 msgHL(getClass().getName() + ": test if owning frame is deoptimized if ArgEscape escapes globally");
 460                 setUp();
 461                 warmUp();
 462                 for (TaggingAndCountingMethods m : TaggingAndCountingMethods.values()) {
 463                     msgHL(getClass().getName() + ": Tag and Get of ArgEscapes using " + m.name());
 464                     waitingForCheck = false;
 465                     checkingNow = false;
 466                     WB.deflateIdleMonitors();
 467                     WB.fullGC(); // get rid of dead instances from previous test cases
 468                     runTest(m);
 469                 }
 470             } catch (Exception e) {
 471                 Asserts.fail("Unexpected Exception", e);
 472             }
 473         }
 474 
 475         public void runTest(TaggingAndCountingMethods m) throws Exception {
 476             loopCount = 1L << 62; // endless loop
 477             doLoop = true;
 478             Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread (" + getClass().getName() + ")");
 479             try {
 480                 t1.start();
 481                 try {
 482                     waitUntilTargetThreadHasEnteredEndlessLoop();
 483                     msg("count and tag instances of " + taggedClass.getName() + " with tag " + instanceTag + " using JVMTI " + m.name());
 484                     int count = countAndTagInstancesOfClass(taggedClass, classTag, instanceTag, m);
 485                     msg("Done. Count is " + count);
 486                     Asserts.assertGreaterThanOrEqual(count, 0, "countAndTagInstancesOfClass FAILED");
 487                     Asserts.assertEQ(count, 1, "unexpected number of instances");
 488                 } finally {
 489                     terminateEndlessLoop();
 490                 }
 491 
 492                 ABBox[] result = new ABBox[1];
 493                 msg("get instances tagged with " + instanceTag);
 494                 int err = getObjectsWithTag(instanceTag, result);
 495                 msg("Done.");
 496                 Asserts.assertEQ(0, err, "getObjectsWithTag FAILED");
 497 
 498                 ABBox abBoxArgEscape = result[0];
 499                 while (!waitingForCheck) {
 500                     Thread.yield();
 501                 }
 502                 msg("Check abBoxArgEscape's state is consistent");
 503                 checkingNow = true;
 504                 Asserts.assertTrue(abBoxArgEscape.check(), "Detected inconsistent state. abBoxArgEscape.aVal != abBoxArgEscape.bVal");
 505                 msg("Ok.");
 506             } finally {
 507                 checkingNow = true;
 508                 t1.join();
 509             }
 510         }
 511 
 512         @Override
 513         public void dontinline_testMethod() {
 514             ABBox ab = new ABBox(this);
 515             dontinline_endlessLoop(ab);
 516             ab.synchronizedSlowInc();
 517         }
 518     }
 519 
 520     /**
 521      * Like {@link TestCase02a}, with the exception that at the location in {@link #dontinline_testMethod()} where the
 522      * ArgEscape escapes it is not referenced by a local variable.
 523      */
 524     public static class TestCase02b extends TestCaseBase {
 525 
 526         public long instanceTag;
 527 
 528         public TestCase02b(long classTag) {
 529             super(classTag, ABBox.class);
 530             instanceTag = classTag + 1;
 531         }
 532 
 533         public void run() {
 534             try {
 535                 msgHL(getClass().getName() + ": test if owning frame is deoptimized if ArgEscape escapes globally");
 536                 setUp();
 537                 warmUp();
 538                 for (TaggingAndCountingMethods m : TaggingAndCountingMethods.values()) {
 539                     msgHL(getClass().getName() + ": Tag and Get of ArgEscapes using " + m.name());
 540                     waitingForCheck = false;
 541                     checkingNow = false;
 542                     WB.deflateIdleMonitors();
 543                     WB.fullGC(); // get rid of dead instances from previous test cases
 544                     runTest(m);
 545                 }
 546             } catch (Exception e) {
 547                 Asserts.fail("Unexpected Exception", e);
 548             }
 549         }
 550 
 551         public void runTest(TaggingAndCountingMethods m) throws Exception {
 552             loopCount = 1L << 62; // endless loop
 553             doLoop = true;
 554             Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread (" + getClass().getName() + ")");
 555             try {
 556                 t1.start();
 557                 try {
 558                     waitUntilTargetThreadHasEnteredEndlessLoop();
 559                     msg("count and tag instances of " + taggedClass.getName() + " with tag " + instanceTag + " using JVMTI " + m.name());
 560                     int count = countAndTagInstancesOfClass(taggedClass, classTag, instanceTag, m);
 561                     msg("Done. Count is " + count);
 562                     Asserts.assertGreaterThanOrEqual(count, 0, "countAndTagInstancesOfClass FAILED");
 563                     Asserts.assertEQ(count, 1, "unexpected number of instances");
 564                 } finally {
 565                     terminateEndlessLoop();
 566                 }
 567 
 568                 ABBox[] result = new ABBox[1];
 569                 msg("get instances tagged with " + instanceTag);
 570                 int err = getObjectsWithTag(instanceTag, result);
 571                 msg("Done.");
 572                 Asserts.assertEQ(0, err, "getObjectsWithTag FAILED");
 573 
 574                 ABBox abBoxArgEscape = result[0];
 575                 while (!waitingForCheck) {
 576                     Thread.yield();
 577                 }
 578                 msg("Check abBoxArgEscape's state is consistent");
 579                 checkingNow = true;
 580                 Asserts.assertTrue(abBoxArgEscape.check(), "Detected inconsistent state. abBoxArgEscape.aVal != abBoxArgEscape.bVal");
 581                 msg("Ok.");
 582             } finally {
 583                 checkingNow = true;
 584                 t1.join();
 585             }
 586         }
 587 
 588         @Override
 589         public void dontinline_testMethod() {
 590             // The new instance is an ArgEscape instance and escapes to the JVMTI agent
 591             // while the target thread is in the call to dontinline_endlessLoop(). At this
 592             // location there is no local variable that references the ArgEscape.
 593             ((ABBox) dontinline_endlessLoop(new ABBox(this))).synchronizedSlowInc();;
 594         }
 595     }
 596 
 597     public static void msg(String m) {
 598         System.out.println();
 599         System.out.println("### " + m);
 600         System.out.println();
 601     }
 602 
 603     public static void msgHL(String m) {
 604         System.out.println(); System.out.println(); System.out.println();
 605         System.out.println("#####################################################");
 606         System.out.println("### " + m);
 607         System.out.println("###");
 608         System.out.println();
 609     }
 610 }