1 /*
   2 * Copyright (c) 2018, 2019, 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 
  26 /**
  27 * @test
  28 * @summary Basic tests for java.lang.Continuation
  29 *
  30 * @run testng/othervm -Xint -XX:-UseContinuationLazyCopy Basic
  31 * @run testng/othervm -Xint -XX:+UseContinuationLazyCopy Basic
  32 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:-UseContinuationLazyCopy Basic
  33 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=exclude,Basic.manyArgsDriver -XX:-UseContinuationLazyCopy Basic
  34 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=exclude,java/lang/Continuation.enter -XX:-UseContinuationLazyCopy Basic
  35 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=inline,java/lang/Continuation.run -XX:-UseContinuationLazyCopy Basic
  36 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy Basic
  37 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy -XX:CompileCommand=exclude,Basic.manyArgsDriver Basic
  38 * @run testng/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy -XX:CompileCommand=exclude,java/lang/Continuation.enter Basic
  39 * @run testng/othervm -Xcomp -XX:TieredStopAtLevel=3 -XX:CompileOnly=java/lang/Continuation,Basic -XX:-UseContinuationLazyCopy Basic
  40 * @run testng/othervm -Xcomp -XX:TieredStopAtLevel=3 -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy Basic
  41 */
  42 
  43 /*
  44 Graal tests currently disabled until we can find the problem with monitor pinned tests.
  45 
  46 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:CompileOnly=java/lang/Continuation,Basic -XX:-UseContinuationLazyCopy Basic
  47 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=exclude,Basic.manyArgsDriver -XX:-UseContinuationLazyCopy Basic
  48 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=exclude,java/lang/Continuation.enter -XX:-UseContinuationLazyCopy Basic
  49 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:CompileCommand=inline,java/lang/Continuation.run -XX:-UseContinuationLazyCopy Basic
  50 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy Basic
  51 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy -XX:CompileCommand=exclude,Basic.manyArgsDriver Basic
  52 * @run testng/othervm -Xcomp -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -XX:-TieredCompilation -XX:CompileOnly=java/lang/Continuation,Basic -XX:+UseContinuationLazyCopy -XX:CompileCommand=exclude,java/lang/Continuation.enter Basic
  53 */
  54 
  55 // Anything excluded or not compileonly is not compiled; see CompilerOracle::should_exclude
  56 
  57 // * @library /test/lib /
  58 // *
  59 // * @build sun.hotspot.WhiteBox
  60 // * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
  61 // *
  62 // -XX:+WhiteBoxAPI
  63 
  64 // @run driver jdk.test.lib.FileInstaller compilerDirectives.json compilerDirectives.json
  65 // -XX:CompilerDirectivesFile=compilerDirectives.json
  66 
  67 // import sun.hotspot.WhiteBox;
  68 
  69 import java.util.ArrayList;
  70 import java.util.Arrays;
  71 import java.util.List;
  72 import java.util.stream.Collectors;
  73 import java.util.stream.IntStream;
  74 
  75 import org.testng.annotations.Test;
  76 import org.testng.annotations.DataProvider;
  77 import static org.testng.Assert.*;
  78 
  79 import java.util.concurrent.atomic.AtomicInteger;
  80 import java.util.concurrent.atomic.AtomicReference;
  81 
  82 @Test
  83 public class Basic {
  84     // private static final WhiteBox WB = WhiteBox.getWhiteBox();
  85 
  86     static final ContinuationScope FOO = new ContinuationScope() {};
  87     
  88     // @Test
  89     // public void test0() {
  90     //     fooooooo();
  91     // }
  92 
  93     // private static void fooooooo() {
  94     //     new Basic().test1();
  95     // }
  96 
  97     public void test1() {
  98         System.out.println("test1");
  99         final AtomicInteger res = new AtomicInteger(0);
 100         Continuation cont = new Continuation(FOO, ()-> {
 101             double r = 0;
 102             for (int k = 1; k < 20; k++) {
 103                 int x = 3;
 104                 String s = "abc";
 105                 r += foo(k);
 106             }
 107             res.set((int)r);
 108         });
 109         
 110         int i = 0;
 111         while (!cont.isDone()) {
 112             cont.run();
 113             System.gc();
 114 
 115             assertEquals(cont.isPreempted(), false);
 116 
 117             List<String> frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
 118             assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "bar", "foo", "lambda$test1$0", "enter"));
 119         }
 120         assertEquals(res.get(), 247);
 121         assertEquals(cont.isPreempted(), false);
 122     }
 123     
 124     static double foo(int a) {
 125         long x = 8;
 126         String s = "yyy";
 127         String r = bar(a + 1);
 128         return Integer.parseInt(r)+1;
 129     }
 130     
 131     static final int DEPTH = 40;
 132     static String bar(long b) {
 133         double x = 9.99;
 134         String s = "zzz";
 135         boolean res = Continuation.yield(FOO);
 136 
 137         assertEquals(res, true);
 138 
 139         // StackWalker walker = StackWalker.getInstance();
 140         // List<String> frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
 141 
 142         // assertEquals(frames.subList(0, 7), List.of("bar", "foo", "lambda$test1$0", "enter", "run", "test1"));
 143 
 144         // walker = StackWalker.getInstance(FOO);
 145         // frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
 146 
 147         // assertEquals(frames, List.of("bar", "foo", "lambda$test1$0", "enter"));
 148 
 149         deep(DEPTH);
 150 
 151         long r = b+1;
 152         return "" + r;
 153     }
 154 
 155     static String bar2(long b) {
 156         double x = 9.99;
 157         String s = "zzz";
 158         Continuation.yield(FOO);
 159 
 160         long r = b+1;
 161         return "" + r;
 162     }
 163 
 164     static void deep(int depth) {
 165         if (depth > 1) {
 166             deep(depth-1);
 167             return;
 168         }
 169 
 170         StackWalker walker = StackWalker.getInstance();
 171         List<String> frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
 172 
 173         List<String> expected0 = new ArrayList<>();
 174         IntStream.range(0, DEPTH).forEach(i -> { expected0.add("deep"); });
 175         expected0.addAll(List.of("bar", "foo", "lambda$test1$0", "enter", "run", "test1"));
 176 
 177         assertEquals(frames.subList(0, DEPTH + 6), expected0);
 178 
 179         walker = StackWalker.getInstance(FOO);
 180         frames = walker.walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList()));
 181 
 182 
 183         List<String> expected1 = new ArrayList<>();
 184         IntStream.range(0, DEPTH).forEach(i -> { expected1.add("deep"); });
 185         expected1.addAll(List.of("bar", "foo", "lambda$test1$0", "enter"));
 186         assertEquals(frames, expected1);
 187     }
 188 
 189     static class LoomException extends RuntimeException {
 190         public LoomException(String message) {
 191             super(message);
 192         }
 193 
 194         @Override
 195         public Throwable fillInStackTrace() {
 196             return fillInStackTrace(FOO);
 197         }
 198     }
 199 
 200     static double fooThrow(int a) {
 201         long x = 8;
 202         String s = "yyy";
 203         String r = barThrow(a + 1);
 204         return Integer.parseInt(r)+1;
 205     }
 206 
 207     static String barThrow(long b) {
 208         double x = 9.99;
 209         String s = "zzz";
 210         Continuation.yield(FOO);
 211 
 212         long r = b+1;
 213 
 214         if (true)
 215             throw new LoomException("Loom exception!");
 216         return "" + r;
 217     }
 218     
 219     public void testException1() {
 220         System.out.println("testException1");
 221         Continuation cont = new Continuation(FOO, ()-> {
 222             double r = 0;
 223             for (int k = 1; k < 20; k++) {
 224                 int x = 3;
 225                 String s = "abc";
 226                 r += fooThrow(k);
 227             }
 228         });
 229         
 230         cont.run();
 231         try {
 232             cont.run();
 233             fail("Exception not thrown.");
 234         } catch (LoomException e) {
 235             assertEquals(e.getMessage(), "Loom exception!");
 236 
 237             StackTraceElement[] stes = e.getStackTrace();
 238             // System.out.println(Arrays.toString(stes));
 239             assertEquals(stes[0].getMethodName(), "barThrow");
 240             StackTraceElement last = stes[stes.length-1];
 241             assertEquals(last.getClassName(), "java.lang.Continuation");
 242             assertEquals(last.getMethodName(), "enter");
 243             assertTrue(last.toString().endsWith(" " + FOO.toString()), last.toString());
 244         }
 245     }
 246 
 247     public void testManyArgs() {
 248         System.out.println("testManyArgs");
 249         final AtomicInteger res = new AtomicInteger(0);
 250         Continuation cont = new Continuation(FOO, ()-> {
 251             res.set((int)manyArgsDriver());
 252         });
 253         
 254         int i = 0;
 255         while (!cont.isDone()) {
 256             cont.run();
 257             System.gc();
 258         }
 259         assertEquals(res.get(), 247);
 260     }
 261     
 262     static double manyArgsDriver() {
 263         double r = 0;
 264         for (int k = 1; k < 20; k++) {
 265             int x = 3;
 266             String s = "abc"; 
 267 
 268             // TODO: test when this method is interpreted but callee is compiled.
 269             r += fooMany(k,
 270             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
 271             1.0, 2.0, 3.0, 4.0, 5.0, 6.0f, 7.0f, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0f, 15.0f, 16.0f, 17.0, 18.0, 19.0, 20.0,
 272             1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020);
 273         }
 274         return r;
 275     }
 276 
 277     static double fooMany(int a,
 278     int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12,
 279     int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20,
 280     double f1, double f2, double f3, double f4, double f5, float f6, float f7, double f8, double f9, double f10,
 281     double f11, double f12, double f13, float f14, float f15, float f16, double f17, double f18, double f19, double f20,
 282     Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8, Object o9, Object o10,
 283     Object o11, Object o12, Object o13, Object o14, Object o15, Object o16, Object o17, Object o18, Object o19, Object o20) {
 284         long x = 8;
 285         String s = "yyy";
 286         String r = barMany(a + 1,
 287         x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20,
 288         f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20,
 289         o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15, o16, o17, o18, o19, o20);
 290         return Integer.parseInt(r)+1;
 291     }
 292     
 293     static String barMany(long b,
 294     int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x10, int x11, int x12,
 295     int x13, int x14, int x15, int x16, int x17, int x18, int x19, int x20,
 296     double f1, double f2, double f3, double f4, double f5, float f6, float f7, double f8, double f9, double f10,
 297     double f11, double f12, double f13, float f14, float f15, float f16, double f17, double f18, double f19, double f20,
 298     Object o1, Object o2, Object o3, Object o4, Object o5, Object o6, Object o7, Object o8, Object o9, Object o10,
 299     Object o11, Object o12, Object o13, Object o14, Object o15, Object o16, Object o17, Object o18, Object o19, Object o20) {
 300         double x = 9.99;
 301         String s = "zzz";
 302         Continuation.yield(FOO);
 303         long r = b+1;
 304         return "" + r;
 305     }
 306     
 307     public void testPinnedMonitor() {
 308         System.out.println("testPinnedMonitor");
 309         final AtomicReference<Continuation.Pinned> res = new AtomicReference<>();
 310         
 311         Continuation cont = new Continuation(FOO, ()-> {
 312             syncFoo(1);
 313         }) {
 314             @Override
 315             protected void onPinned(Continuation.Pinned reason) {
 316                 assert Continuation.isPinned(FOO);
 317                 res.set(reason);
 318             }
 319         };
 320         
 321         cont.run();
 322         assertEquals(res.get(), Continuation.Pinned.MONITOR);
 323         boolean isDone = cont.isDone();
 324         assertEquals(isDone, true);
 325     }
 326     
 327     static double syncFoo(int a) {
 328         long x = 8;
 329         String s = "yyy";
 330         String r;
 331         synchronized(FOO) {
 332             r = bar2(a + 1);
 333         }
 334         return Integer.parseInt(r)+1;
 335     }
 336     
 337     public void testNotPinnedMonitor() {
 338         System.out.println("testNotPinnedMonitor");
 339         final AtomicReference<Continuation.Pinned> res = new AtomicReference<>();
 340         
 341         Continuation cont = new Continuation(FOO, ()-> {
 342             noSyncFoo(1);
 343         }) {
 344             @Override
 345             protected void onPinned(Continuation.Pinned reason) {
 346                 assert Continuation.isPinned(FOO);
 347                 res.set(reason);
 348             }
 349         };
 350         
 351         cont.run();
 352         boolean isDone = cont.isDone();
 353         assertEquals(res.get(), null);
 354         assertEquals(isDone, false);
 355     }
 356 
 357     static double noSyncFoo(int a) {
 358         long x = 7;
 359         synchronized(FOO) {
 360             x += FOO.getClass().getName().contains("FOO") ? 1 : 0;
 361         }
 362         String s = "yyy";
 363         String r = bar2(a + 1);
 364         return Integer.parseInt(r)+1;
 365     }
 366 
 367     public void testPinnedNative() {
 368         System.out.println("testPinnedNative");
 369         final AtomicReference<Continuation.Pinned> res = new AtomicReference<>();
 370         
 371         Continuation cont = new Continuation(FOO, ()-> {
 372             nativeFoo(1);
 373         }) {
 374             @Override
 375             protected void onPinned(Continuation.Pinned reason) {
 376                 res.set(reason);
 377             }
 378         };
 379         
 380         cont.run();
 381         assertEquals(res.get(), Continuation.Pinned.NATIVE);
 382     }
 383     
 384     static double nativeFoo(int a) {
 385         try {
 386             long x = 8;
 387             String s = "yyy";
 388             String r = (String)Basic.class.getDeclaredMethod("nativeBar", long.class).invoke(null, 1L);
 389             return Integer.parseInt(r)+1;
 390         } catch (Exception e) {
 391             throw new AssertionError(e);
 392         }
 393     }
 394 
 395     static String nativeBar(long b) {
 396         double x = 9.99;
 397         String s = "zzz";
 398         assert Continuation.isPinned(FOO);
 399         boolean res = Continuation.yield(FOO);
 400         assert res == false;
 401 
 402         long r = b+1;
 403         return "" + r;
 404     }
 405 
 406     public void testPinnedCriticalSection() {
 407         System.out.println("testPinnedCriticalSection");
 408         final AtomicReference<Continuation.Pinned> res = new AtomicReference<>();
 409         
 410         Continuation cont = new Continuation(FOO, ()-> {
 411             csFoo(1);
 412         }) {
 413             @Override
 414             protected void onPinned(Continuation.Pinned reason) {
 415                 res.set(reason);
 416             }
 417         };
 418         
 419         cont.run();
 420         assertEquals(res.get(), Continuation.Pinned.CRITICAL_SECTION);
 421     }
 422 
 423     static double csFoo(int a) {
 424         long x = 8;
 425         String s = "yyy";
 426         String r;
 427         Continuation.pin();
 428         try {
 429             assert Continuation.isPinned(FOO);
 430             r = bar2(a + 1);
 431         } finally {
 432             Continuation.unpin();
 433         }
 434         return Integer.parseInt(r)+1;
 435     }
 436 }