1 /*
  2  * Copyright (c) 2018, 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 package java.lang;
 25 
 26 import jdk.internal.vm.Continuation;
 27 import jdk.internal.vm.ContinuationScope;
 28 
 29 import java.util.concurrent.atomic.AtomicInteger;
 30 import java.util.concurrent.CountDownLatch;
 31 import java.util.Arrays;
 32 import java.util.Objects;
 33 
 34 public class PreemptLiveFrames {
 35     public static void main(String[] args) {
 36         try {
 37             PreemptLiveFrames obj = new PreemptLiveFrames();
 38             obj.test1();
 39         } catch (Exception e) {
 40             throw new RuntimeException(e);
 41         }
 42     }
 43 
 44     static final ContinuationScope FOO = new ContinuationScope() {};
 45     CountDownLatch startLatch = new CountDownLatch(1);
 46     volatile boolean run;
 47     volatile int x;
 48 
 49     public void test1() throws Exception {
 50         System.out.println("test1");
 51 
 52         final AtomicInteger result = new AtomicInteger(0);
 53         final Continuation cont = new Continuation(FOO, ()-> {
 54                 double r = 0;
 55                 int k = 1;
 56                 int x = 3;
 57                 String s = "abc";
 58                 r += foo(k);
 59                 result.set((int)r);
 60             });
 61 
 62         final Thread t0 = Thread.currentThread();
 63         Thread t = new Thread(() -> {
 64             try {
 65                 startLatch.await();
 66 
 67                 Continuation.PreemptStatus res;
 68                 int i = 0;
 69                 do {
 70                     res = cont.tryPreempt(t0);
 71                     i++;
 72                 } while (i < 100 && res == Continuation.PreemptStatus.TRANSIENT_FAIL_PINNED_NATIVE);
 73                 assertEquals(res, Continuation.PreemptStatus.SUCCESS);
 74                 // assertEquals(res, Continuation.PreemptStatus.SUCCESS);
 75             } catch (InterruptedException e) {
 76                 throw new RuntimeException(e);
 77             }
 78         });
 79         t.start();
 80 
 81         run = true;
 82 
 83         cont.run();
 84         assertEquals(cont.isDone(), false);
 85         assertEquals(cont.isPreempted(), true);
 86 
 87         testStackWalk(LiveStackFrame.getStackWalker(cont));
 88 
 89         t.join();
 90     }
 91 
 92     double foo(int a) {
 93         long x = 8;
 94         String s = "yyy";
 95         String r = bar(a + 1);
 96         return Integer.parseInt(r)+1;
 97     }
 98 
 99     String bar(long b) {
100         double x = 9.99;
101         String s = "zzz";
102         String r = baz(b + 1);
103         return "" + r;
104     }
105 
106     String baz(long b) {
107         double x = 9.99;
108         String s = "zzz";
109 
110         loop();
111 
112         long r = b+1;
113         return "" + r;
114     }
115 
116     void loop() {
117         while (run) {
118             x++;
119             if (startLatch.getCount() > 0) {
120                 startLatch.countDown();
121             }
122         }
123     }
124 
125     static void testStackWalk(StackWalker walker) {
126         // StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
127         System.out.println("^&^ start");
128         walker.forEach(f -> {
129             try {
130                 System.out.println("^&^ --==--");
131                 // System.out.println("^&^ " + f);
132                 LiveStackFrame lf = (LiveStackFrame)f;
133                 System.out.println("^&^ locals: " + Arrays.toString(lf.getLocals()));
134                 System.out.println("^&^ stack: " + Arrays.toString(lf.getStack()));
135             } catch (Throwable t) {
136                 t.printStackTrace();
137                 throw t;
138             }
139         });
140         System.out.println("^&^ end");
141     }
142 
143     static void assertEquals(Object actual, Object expected) {
144         if (!Objects.equals(actual, expected)) {
145             throw new AssertionError("Expected: " + expected + ", actual: " + actual);
146         }
147     }
148 }