1 /*
2 * Copyright (c) 2018, 2022, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.vm;
27
28 import jdk.internal.misc.PreviewFeatures;
29 import jdk.internal.misc.Unsafe;
30 import jdk.internal.vm.annotation.DontInline;
31 import jdk.internal.vm.annotation.IntrinsicCandidate;
32 import sun.security.action.GetPropertyAction;
33
34 import java.lang.invoke.MethodHandles;
35 import java.lang.invoke.VarHandle;
36 import java.util.EnumSet;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.function.Supplier;
41 import jdk.internal.access.JavaLangAccess;
42 import jdk.internal.access.SharedSecrets;
43
44 /**
45 * A one-shot delimited continuation.
46 */
47 public class Continuation {
48 private static final Unsafe U = Unsafe.getUnsafe();
49 private static final boolean PRESERVE_SCOPED_VALUE_CACHE;
50 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
51 static {
52 ContinuationSupport.ensureSupported();
53 PreviewFeatures.ensureEnabled();
54
55 StackChunk.init(); // ensure StackChunk class is initialized
56
57 String value = GetPropertyAction.privilegedGetProperty("jdk.preserveScopedValueCache");
58 PRESERVE_SCOPED_VALUE_CACHE = (value == null) || Boolean.parseBoolean(value);
59 }
60
61 private static final VarHandle MOUNTED;
62
63 /** Reason for pinning */
64 public enum Pinned {
65 /** Native frame on stack */ NATIVE,
66 /** Monitor held */ MONITOR,
67 /** In critical section */ CRITICAL_SECTION }
68
69 /** Preemption attempt result */
70 public enum PreemptStatus {
71 /** Success */ SUCCESS(null),
72 /** Permanent failure */ PERM_FAIL_UNSUPPORTED(null),
73 /** Permanent failure: continuation already yielding */ PERM_FAIL_YIELDING(null),
294 }
295
296 private void postYieldCleanup() {
297 if (done) {
298 this.tail = null;
299 }
300 }
301
302 private void finish() {
303 done = true;
304 assert isEmpty();
305 }
306
307 @IntrinsicCandidate
308 private native static int doYield();
309
310 @IntrinsicCandidate
311 private native static void enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread);
312
313
314 @DontInline
315 @IntrinsicCandidate
316 private static void enter(Continuation c, boolean isContinue) {
317 // This method runs in the "entry frame".
318 // A yield jumps to this method's caller as if returning from this method.
319 try {
320 c.enter0();
321 } finally {
322 c.finish();
323 }
324 }
325
326 private void enter0() {
327 target.run();
328 }
329
330 private boolean isStarted() {
331 return tail != null;
332 }
333
334 private boolean isEmpty() {
335 for (StackChunk c = tail; c != null; c = c.parent()) {
336 if (!c.isEmpty())
337 return false;
338 }
339 return true;
340 }
341
342 /**
343 * Suspends the current continuations up to the given scope
344 *
345 * @param scope The {@link ContinuationScope} to suspend
346 * @return {@code true} for success; {@code false} for failure
347 * @throws IllegalStateException if not currently in the given {@code scope},
348 */
349 public static boolean yield(ContinuationScope scope) {
350 Continuation cont = JLA.getContinuation(currentCarrierThread());
351 Continuation c;
352 for (c = cont; c != null && c.scope != scope; c = c.parent)
353 ;
354 if (c == null)
355 throw new IllegalStateException("Not in scope " + scope);
356
357 return cont.yield0(scope, null);
358 }
359
360 private boolean yield0(ContinuationScope scope, Continuation child) {
361 preempted = false;
362
363 if (scope != this.scope)
364 this.yieldInfo = scope;
365 int res = doYield();
366 U.storeFence(); // needed to prevent certain transformations by the compiler
367
368 assert scope != this.scope || yieldInfo == null : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
369 assert yieldInfo == null || scope == this.scope || yieldInfo instanceof Integer : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
370
371 if (child != null) { // TODO: ugly
372 if (res != 0) {
373 child.yieldInfo = res;
374 } else if (yieldInfo != null) {
375 assert yieldInfo instanceof Integer;
376 child.yieldInfo = yieldInfo;
377 } else {
378 child.yieldInfo = res;
379 }
|
1 /*
2 * Copyright (c) 2018, 2023, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.vm;
27
28 import jdk.internal.misc.Unsafe;
29 import jdk.internal.vm.annotation.DontInline;
30 import jdk.internal.vm.annotation.IntrinsicCandidate;
31 import sun.security.action.GetPropertyAction;
32
33 import java.lang.invoke.MethodHandles;
34 import java.lang.invoke.VarHandle;
35 import java.util.EnumSet;
36 import java.util.Set;
37 import java.util.function.Supplier;
38 import jdk.internal.access.JavaLangAccess;
39 import jdk.internal.access.SharedSecrets;
40 import jdk.internal.vm.annotation.Hidden;
41
42 /**
43 * A one-shot delimited continuation.
44 */
45 public class Continuation {
46 private static final Unsafe U = Unsafe.getUnsafe();
47 private static final boolean PRESERVE_SCOPED_VALUE_CACHE;
48 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
49 static {
50 ContinuationSupport.ensureSupported();
51
52 StackChunk.init(); // ensure StackChunk class is initialized
53
54 String value = GetPropertyAction.privilegedGetProperty("jdk.preserveScopedValueCache");
55 PRESERVE_SCOPED_VALUE_CACHE = (value == null) || Boolean.parseBoolean(value);
56 }
57
58 private static final VarHandle MOUNTED;
59
60 /** Reason for pinning */
61 public enum Pinned {
62 /** Native frame on stack */ NATIVE,
63 /** Monitor held */ MONITOR,
64 /** In critical section */ CRITICAL_SECTION }
65
66 /** Preemption attempt result */
67 public enum PreemptStatus {
68 /** Success */ SUCCESS(null),
69 /** Permanent failure */ PERM_FAIL_UNSUPPORTED(null),
70 /** Permanent failure: continuation already yielding */ PERM_FAIL_YIELDING(null),
291 }
292
293 private void postYieldCleanup() {
294 if (done) {
295 this.tail = null;
296 }
297 }
298
299 private void finish() {
300 done = true;
301 assert isEmpty();
302 }
303
304 @IntrinsicCandidate
305 private native static int doYield();
306
307 @IntrinsicCandidate
308 private native static void enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread);
309
310
311 @Hidden
312 @DontInline
313 @IntrinsicCandidate
314 private static void enter(Continuation c, boolean isContinue) {
315 // This method runs in the "entry frame".
316 // A yield jumps to this method's caller as if returning from this method.
317 try {
318 c.enter0();
319 } finally {
320 c.finish();
321 }
322 }
323
324 @Hidden
325 private void enter0() {
326 target.run();
327 }
328
329 private boolean isStarted() {
330 return tail != null;
331 }
332
333 private boolean isEmpty() {
334 for (StackChunk c = tail; c != null; c = c.parent()) {
335 if (!c.isEmpty())
336 return false;
337 }
338 return true;
339 }
340
341 /**
342 * Suspends the current continuations up to the given scope
343 *
344 * @param scope The {@link ContinuationScope} to suspend
345 * @return {@code true} for success; {@code false} for failure
346 * @throws IllegalStateException if not currently in the given {@code scope},
347 */
348 @Hidden
349 public static boolean yield(ContinuationScope scope) {
350 Continuation cont = JLA.getContinuation(currentCarrierThread());
351 Continuation c;
352 for (c = cont; c != null && c.scope != scope; c = c.parent)
353 ;
354 if (c == null)
355 throw new IllegalStateException("Not in scope " + scope);
356
357 return cont.yield0(scope, null);
358 }
359
360 @Hidden
361 private boolean yield0(ContinuationScope scope, Continuation child) {
362 preempted = false;
363
364 if (scope != this.scope)
365 this.yieldInfo = scope;
366 int res = doYield();
367 U.storeFence(); // needed to prevent certain transformations by the compiler
368
369 assert scope != this.scope || yieldInfo == null : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
370 assert yieldInfo == null || scope == this.scope || yieldInfo instanceof Integer : "scope: " + scope + " this.scope: " + this.scope + " yieldInfo: " + yieldInfo + " res: " + res;
371
372 if (child != null) { // TODO: ugly
373 if (res != 0) {
374 child.yieldInfo = res;
375 } else if (yieldInfo != null) {
376 assert yieldInfo instanceof Integer;
377 child.yieldInfo = yieldInfo;
378 } else {
379 child.yieldInfo = res;
380 }
|