An Implementation of effect handlers using bytecode manipulation.
- The world famous Drunkflip example.
An example of some instrumented bytecode can be found in this gist. The source-file is Simple.java.
The project currently consists of the following subprojects:
- core The runtime system of jvm-effekt -- contains necessary runtime classes (like Stack).
- instrumentation The implementation of byte code instrumentation, depends on core.
- sbtplugin An sbtplugin for offline instrumentation of classfiles.
- tests A separate project illustrating the use of Java Effekt.
The project currently depends on version 2.0.1
of the static analysis and bytecode generation framework OPAL.
To run the tests, execute the following steps:
# If you haven't already, clone the repo
git clone git@github.com:b-studios/java-effekt.git
cd java-effekt
# clean all previous builds, if any to avoid sbt conflicts (only necessary once in a while ;) )
rm -r **/target
# Start sbt and publish the effekt instrumentation locally
sbt publishLocal
# now switch to the effekt core library and publish this locally
cd core
sbt publishLocal
# switch to tests subproject and run tests
cd ..
git clone git@github.com:b-studios/java-effekt-tests.git
cd java-effekt-tests
sbt
> test -- -oDF
Running the tests will instrument the class files and dump them for inspection under target/instrumented
.
To inspect bytecode, I highly recommend the
OPAL - Bytecode Disassembler Plugin for Atom.
Scala-Effekt is a library based implementation of effect handlers and uses a monad to implement multiprompt delimited continuations (which are necessary for effect handlers). Similarly, some experiments in Java show that this is in fact a viable approach. However, the monadic style might impose usability as well as performance issues.
This project implements stack manipulation (a la DelimCC) on the JVM by
only using the JVM stack for pure (non effectful) operations. For effectful operations, instead a
user-level Stack
is used. Before each effectful operation, the continuation is pushed as a first-class frame to this stack.
These first-class frames are instances of Frame
and exactly represent the continuation after the effectful call. The method state is stored in the closure of the frame and restored before the original body is executed.
This is very similar to the bytecode instrumentation performed by Quasar. In particular, we also use Java checked exceptions to mark "effectful" functions. However, Quasar does not have a notion of first-class frames and still uses the JVM-stack for effectful functions. Thus resuming a continuation takes O(n) in the depth of the JVM stack.