From 32880edc3de5559bd187a6504b6f02904d604c10 Mon Sep 17 00:00:00 2001 From: Parker TenBroeck <51721964+ParkerTenBroeck@users.noreply.github.com> Date: Wed, 7 May 2025 13:11:43 -0400 Subject: [PATCH 1/2] Update README.md --- README.md | 57 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index b5008a9..483ffed 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,35 @@ public static Future regular_function() { } ``` +### Why not annotations? +Unfortunately annotations cannot be put on lambdas. + +## Use this library + +```kotlin +// settings.gradle.kts +sourceControl { + gitRepository(URI.create("https://github.com/ParkerTenBroeck/generators.git")) { + producesModule("com.parkertenbroeck.generators:lib") + } +} + +// build.gradle.kts +implementation("com.parkertenbroeck.generators:lib:0.1.0") +``` + +This library requires the application be ran with a custom class loader, there is a utility provided to make this easier. +```java +public static void main(String[] args) { + // loads the current class with a custom class loader and calls *this* method with the provided arguments. + // *this* method - the one used to call `runWithStateMachines` + RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args); + + // past this point generators will be created on methods which match the criteria +} +``` + + ## Oddities ```java @@ -130,7 +159,7 @@ public static Future add_reorder() { ### synchronized -when a generator/future method is declared as `synchronized` the `next`/`poll`/`cancel` functions will all be synchronized over the instance or class which the method was declared in. +when a generator/future method is declared as `synchronized` the `next`/`poll`/`cancel` functions will all be synchronized over the instance or class the method was declared in. it is important to note that the monitor is **NOT** held across suspend points where the function returns. @@ -146,22 +175,7 @@ static Future unsync(Object value) { ## How this works -This library requires the application be ran with a custom class loader as follows (this can be done manually if needed) -```java -public static void main(String[] args) { - // loads the current class with a custom class loader and calls *this* method with the provided arguments. - // *this* method - the one used to call `runWithStateMachines` - RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args); - - // past this point generators will be created on methods which match the criteria -} -``` - -Once finished any class loaded will be scanned for methods which match a particular signature. - -When matched a shim is introduced into the source method and a class is constructed which stores all state for the future/generator - -A basic example here where we have some parameters +Say we have some async function like this. ```java public static Future example(@Cancellation("close") Socket socket, String message) throws IOException { try(socket){ @@ -170,6 +184,8 @@ public static Future example(@Cancellation("close") Socket so return Future.ret(); } ``` +The loader will see the methods which it needs to transform, then modify the bytecode, transforming the function into a class where state across suspend points is saved/restored (local variables & the current state of the stack). + This is a (modified) decompiled version of the generated method. ```java public static Future example(Socket socket, String message) { @@ -273,10 +289,3 @@ public static Future example(Socket socket, String message) { }; } ``` -### Steps -- A functions signature and code is determined to be "of interest" -- When a function is found we wish to modify it first builds a frame(locals, stack, annotations) for every area of interest in the function -- The number of unique locations which can be suspended from are kept track of -- A switch is built which handles each state the function can resume from setting up any locals/stack that needs to be resumed as well as setting up the code for saving locals/stack state -- the locations which special methods are found are modified to perform their particular function and potentially save state and return -- (Futures) generate cancellation code for locals which have specified so, and cancellation for a pending future. From 6ca8ac2d25aa1275aaf71abab8874d80512cc324 Mon Sep 17 00:00:00 2001 From: Parker TenBroeck <51721964+ParkerTenBroeck@users.noreply.github.com> Date: Wed, 7 May 2025 13:34:14 -0400 Subject: [PATCH 2/2] Update README.md --- README.md | 90 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 483ffed..3d8eb9e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,31 @@ public static Gen primes() { } ``` +## Use this library + +```kotlin +// settings.gradle.kts +sourceControl { + gitRepository(URI.create("https://github.com/ParkerTenBroeck/generators.git")) { + producesModule("com.parkertenbroeck.generators:lib") + } +} + +// build.gradle.kts +implementation("com.parkertenbroeck.generators:lib:0.1.0") +``` + +This library requires the application be ran with a custom class loader, there is a utility provided to make this easier. +```java +public static void main(String[] args) { + // loads the current class with a custom class loader and calls *this* method with the provided arguments. + // *this* method - the one used to call `runWithStateMachines` + RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args); + + // past this point generators will be created on methods which match the criteria +} +``` + ## How does it know what functions to transform? Detection is done by @@ -64,31 +89,6 @@ public static Future regular_function() { ### Why not annotations? Unfortunately annotations cannot be put on lambdas. -## Use this library - -```kotlin -// settings.gradle.kts -sourceControl { - gitRepository(URI.create("https://github.com/ParkerTenBroeck/generators.git")) { - producesModule("com.parkertenbroeck.generators:lib") - } -} - -// build.gradle.kts -implementation("com.parkertenbroeck.generators:lib:0.1.0") -``` - -This library requires the application be ran with a custom class loader, there is a utility provided to make this easier. -```java -public static void main(String[] args) { - // loads the current class with a custom class loader and calls *this* method with the provided arguments. - // *this* method - the one used to call `runWithStateMachines` - RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args); - - // past this point generators will be created on methods which match the criteria -} -``` - ## Oddities @@ -110,7 +110,38 @@ public static Future echo(🔷@Cancellation("close") Socket s ## Things to watch out for -### Future errors are not type checked +### Await function works specifically for the Future type + +```java +class MyFuture implements Future{ + public Object poll(Waker waker){ /* code */ } +} + +void Future wrong() { + new MyFuture().await();//⚡ + return Future.ret(); +} +``` +Internally the await call will become a `invokevirtual` call to `await` on `MyFuture`. Which will not currently be recognized as a "special" method to transform. + +To avoid this use static methods to return a future and make manually implemented futures have private/protected constructors +```java +class MyFuture implements Future{ + private MyFuture(){} + public static Future make(){ + return new MyFuture(); + } + public Object poll(Waker waker){ /* code */ } +} + +void Future wrong() { + MyFuture.make().await(); + return Future.ret(); +} +``` + + +### Future exceptions are not type checked ```java public static Future wrong() throws Exception { Waker.waker().wake(); @@ -289,3 +320,10 @@ public static Future example(Socket socket, String message) { }; } ``` + +## Potential additions + +- Type checking during transformations +- Better debugger support (Currently line stepping is generally supported but most breakpoint sets are not working) +- Annotations (possibly integration during build time) +- More library features (async)