35 */
36
37 /*
38 * @test id=TieredStopAtLevel1
39 * @enablePreview
40 * @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
41 */
42
43 /*
44 * @test id=no-vmcontinuations
45 * @requires vm.continuations
46 * @enablePreview
47 * @run main/othervm/timeout=300 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StressStackOverflow
48 */
49
50 import java.lang.ScopedValue.CallableOp;
51 import java.time.Duration;
52 import java.util.concurrent.ThreadLocalRandom;
53 import java.util.concurrent.StructureViolationException;
54 import java.util.concurrent.StructuredTaskScope;
55 import java.util.function.Supplier;
56
57 public class StressStackOverflow {
58 public static final ScopedValue<Integer> el = ScopedValue.newInstance();
59
60 public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
61
62 static final TestFailureException testFailureException = new TestFailureException("Unexpected value for ScopedValue");
63 int ITERS = 1_000_000;
64
65 static class TestFailureException extends RuntimeException {
66 TestFailureException(String s) { super(s); }
67 }
68
69 static final long DURATION_IN_NANOS = Duration.ofMinutes(1).toNanos();
70
71 // Test the ScopedValue recovery mechanism for stack overflows. We implement both CallableOp
72 // and Runnable interfaces. Which one gets tested depends on the constructor argument.
73 class DeepRecursion implements CallableOp<Object, RuntimeException>, Supplier<Object>, Runnable {
74
152
153 long fibonacci_pad(int n, Runnable op) {
154 final var last = el.get();
155 try {
156 return fibonacci_pad1(ThreadLocalRandom.current().nextInt(n), op);
157 } catch (StackOverflowError err) {
158 if (!inheritedValue.get().equals(I_42)) {
159 throw testFailureException;
160 }
161 if (!last.equals(el.get())) {
162 throw testFailureException;
163 }
164 throw err;
165 }
166 }
167
168 // Run op in a new thread. Platform or virtual threads are chosen at random.
169 void runInNewThread(Runnable op) {
170 var threadFactory
171 = (ThreadLocalRandom.current().nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
172 try (var scope = new StructuredTaskScope<>("", threadFactory)) {
173 var handle = scope.fork(() -> {
174 op.run();
175 return null;
176 });
177 scope.join();
178 handle.get();
179 } catch (TestFailureException e) {
180 throw e;
181 } catch (Exception e) {
182 throw new RuntimeException(e);
183 }
184 }
185
186 public void run() {
187 try {
188 ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
189 try (var scope = new StructuredTaskScope<>()) {
190 try {
191 if (ThreadLocalRandom.current().nextBoolean()) {
192 // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
193 final var deepRecursion
194 = new DeepRecursion(DeepRecursion.Behaviour.choose(ThreadLocalRandom.current()));
195 deepRecursion.run();
196 } else {
197 // Recursively run ourself until we get a stack overflow
198 // Catch the overflow and make sure the recovery path works
199 // for values inherited from a StructuredTaskScope.
200 Runnable op = new Runnable() {
201 public void run() {
202 try {
203 fibonacci_pad(20, this);
204 } catch (StackOverflowError e) {
205 } catch (TestFailureException e) {
206 throw e;
207 } catch (Throwable throwable) {
208 // StackOverflowErrors cause many different failures. These include
209 // StructureViolationExceptions and InvocationTargetExceptions. This test
|
35 */
36
37 /*
38 * @test id=TieredStopAtLevel1
39 * @enablePreview
40 * @run main/othervm/timeout=300 -XX:TieredStopAtLevel=1 StressStackOverflow
41 */
42
43 /*
44 * @test id=no-vmcontinuations
45 * @requires vm.continuations
46 * @enablePreview
47 * @run main/othervm/timeout=300 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StressStackOverflow
48 */
49
50 import java.lang.ScopedValue.CallableOp;
51 import java.time.Duration;
52 import java.util.concurrent.ThreadLocalRandom;
53 import java.util.concurrent.StructureViolationException;
54 import java.util.concurrent.StructuredTaskScope;
55 import java.util.concurrent.StructuredTaskScope.Joiner;
56 import java.util.function.Supplier;
57
58 public class StressStackOverflow {
59 public static final ScopedValue<Integer> el = ScopedValue.newInstance();
60
61 public static final ScopedValue<Integer> inheritedValue = ScopedValue.newInstance();
62
63 static final TestFailureException testFailureException = new TestFailureException("Unexpected value for ScopedValue");
64 int ITERS = 1_000_000;
65
66 static class TestFailureException extends RuntimeException {
67 TestFailureException(String s) { super(s); }
68 }
69
70 static final long DURATION_IN_NANOS = Duration.ofMinutes(1).toNanos();
71
72 // Test the ScopedValue recovery mechanism for stack overflows. We implement both CallableOp
73 // and Runnable interfaces. Which one gets tested depends on the constructor argument.
74 class DeepRecursion implements CallableOp<Object, RuntimeException>, Supplier<Object>, Runnable {
75
153
154 long fibonacci_pad(int n, Runnable op) {
155 final var last = el.get();
156 try {
157 return fibonacci_pad1(ThreadLocalRandom.current().nextInt(n), op);
158 } catch (StackOverflowError err) {
159 if (!inheritedValue.get().equals(I_42)) {
160 throw testFailureException;
161 }
162 if (!last.equals(el.get())) {
163 throw testFailureException;
164 }
165 throw err;
166 }
167 }
168
169 // Run op in a new thread. Platform or virtual threads are chosen at random.
170 void runInNewThread(Runnable op) {
171 var threadFactory
172 = (ThreadLocalRandom.current().nextBoolean() ? Thread.ofPlatform() : Thread.ofVirtual()).factory();
173 try (var scope = StructuredTaskScope.open(Joiner.awaitAll(), cf -> cf.withThreadFactory(threadFactory))) {
174 var handle = scope.fork(() -> {
175 op.run();
176 return null;
177 });
178 scope.join();
179 handle.get();
180 } catch (TestFailureException e) {
181 throw e;
182 } catch (Exception e) {
183 throw new RuntimeException(e);
184 }
185 }
186
187 public void run() {
188 try {
189 ScopedValue.where(inheritedValue, 42).where(el, 0).run(() -> {
190 try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) {
191 try {
192 if (ThreadLocalRandom.current().nextBoolean()) {
193 // Repeatedly test Scoped Values set by ScopedValue::call(), get(), and run()
194 final var deepRecursion
195 = new DeepRecursion(DeepRecursion.Behaviour.choose(ThreadLocalRandom.current()));
196 deepRecursion.run();
197 } else {
198 // Recursively run ourself until we get a stack overflow
199 // Catch the overflow and make sure the recovery path works
200 // for values inherited from a StructuredTaskScope.
201 Runnable op = new Runnable() {
202 public void run() {
203 try {
204 fibonacci_pad(20, this);
205 } catch (StackOverflowError e) {
206 } catch (TestFailureException e) {
207 throw e;
208 } catch (Throwable throwable) {
209 // StackOverflowErrors cause many different failures. These include
210 // StructureViolationExceptions and InvocationTargetExceptions. This test
|