Skip to content

Continuation-based yield return in Java - Building a "missing" language feature using internal APIs

License

Notifications You must be signed in to change notification settings

danthe1st/ContinuationYieldReturn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Continuation-based yield return

This project contains a generator feature for Java applications using Project Loom's internal Continuation class.

A Javadoc is available on GitHub Pages

Demo

For a demo, see io.github.danthe1st.jvmyieldreturn.example.GeneratorExamples:

private void example() {
	System.out.println("main thread: " + Thread.currentThread());

	for(String s : Generator.iterable(this::someMethod)){
		System.out.println("Text: " + s);
	}

	System.out.println();
	System.out.println("Now using streams:");

	Generator.stream(this::someMethod).limit(2).forEach(System.out::println);
}

private void someMethod(Generator<String> y) {
	y.yield("Hello - " + Thread.currentThread());
	System.out.println("between yields");
	y.yield("World - " + Thread.currentThread());

	for(String s : Generator.iterable(this::otherMethod)){
		y.yield("nested: " + s);
	}

	y.yield("bye - " + Thread.currentThread());
}

private void otherMethod(Generator<String> y) {
	y.yield("it can");
	y.yield("also be");
	y.yield("nested");
}

This demo should print

main thread: Thread[#1,main,5,main]
Text: Hello - Thread[#1,main,5,main]
between yields
Text: World - Thread[#1,main,5,main]
Text: nested: it can
Text: nested: also be
Text: nested: nested
Text: bye - Thread[#1,main,5,main]

Now using streams:
Hello - Thread[#1,main,5,main]
between yields
World - Thread[#1,main,5,main]

It can be seen that the main thread switches between the enhanced for loop and the method with the yield return code.

It is necessary to supply the JVM arguments --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn both for compiling and running the application.

How it works

Continuations

Continuation is an internal JDK class which is used for virtual threads. It allows running some code using Continuation#run until that code calls Continuation.yield. At this point, execution of that code stops ("Freeze") and the Continuation#run returns. If Continuation#run is then called again, the said code continues ("Thaw") at the Continuation.yield method call.

How this project uses Continuations

This project allows to create an Iterable which runs some (user-provided) Function<Yielder<T>,T> when hasNext() or next() is called and no value that hasn't been consumed by next() was computed already. When the code inside that Function calls the Yielder#yield method, the method is suspended and Iterator#next returns the value passed to Yielder#yield. The method is resumed when Iterator#hasNext/Iterator#next is called again after the previous value was consumed by Iterator#next. The yielding parts of the method will always run in the same thread that also calls Iterator#hasNext/Iterator#next.

Setup and Requirements

Requirements

This project requires a Hotspot JDK version 20 (other Java versions may not work).

JVM configuration

It is necessary to supply the arguments --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn both for compiling and running the application.

Since Continuation is an internal JDK class, it is normally not available. It can be made available to this project using the command-line argument --add-exports java.base/jdk.internal.vm=YieldReturn which allows this project (module YieldReturn) to access classes of the package jdk.internal.vm of the java.base module.

The argument --enable-preview is necessary since Continuations are only available as a preview feature (as of Java 20).

Eclipse

In Eclipse, the export can be added from the Libraries tab of the Build path (Right click on the project > Build Path > Configure Build Path > Libraries). After expanding the JRE System Library (this should point to a Java 20 JDK), there should be a Is modular option. This option needs to be edited via double-clicking or the Edit-button on the right. image

In the Details tab, a new export needs to be added via the Add button on the right. image

Enter java.base for the Source Module and jdk.internal.vm for the Package entry. image

--enable-preview can be added to the VM arguments of the run configuration. image

CLI

The content of the src directory can be compiled and run using the javac/java command as follows:

First, create a directory called build in the project root in order to store .class files and ensure that you are running Java 20 with Hotspot.

Then, the code can be compiled using

javac --source 20 --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn -d build src/module-info.java src/io/github/danthe1st/jvmyieldreturn/*.java src/io/github/danthe1st/jvmyieldreturn/test/*.java

After the code is compiled to the build directory, it can be run with the following command:

java --enable-preview --add-exports java.base/jdk.internal.vm=YieldReturn --module-path build -m YieldReturn/io.github.danthe1st.jvmyieldreturn.test.YieldReturnTest

Tests

Some tests are present in the test directory.

Running the tests requires JUnit 5.

Disclaimers

See This JVM Language Summit talk for details on how Continuations work in Java. This talk heavily inspired the creation of this project.

Continuation is not public API. This project uses classes which may not be present in different JVMs or may be removed/changed even within minor Java updates. This project is just for educational purposes! If you are using Continuation in your code, do so at your own risk.

About

Continuation-based yield return in Java - Building a "missing" language feature using internal APIs

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages