From b0d6737b07d60f04f80c72c0f2e765b67f0ed10f Mon Sep 17 00:00:00 2001 From: Parker TenBroeck <51721964+ParkerTenBroeck@users.noreply.github.com> Date: Mon, 28 Apr 2025 23:36:07 -0400 Subject: [PATCH] so many small issues all at once --- src/Examples.java | 51 +++---------- src/Main.java | 5 +- src/async_example/Delay.java | 52 +++++++++++++ src/async_example/Jokio.java | 73 +++++++++++++++++++ .../runtime/GeneratorClassLoader.java | 9 ++- src/generator/runtime/LocalTracker.java | 3 +- .../runtime/StateMachineBuilder.java | 8 +- .../runtime/future/FutureSMBuilder.java | 23 ++++-- 8 files changed, 167 insertions(+), 57 deletions(-) create mode 100644 src/async_example/Delay.java create mode 100644 src/async_example/Jokio.java diff --git a/src/Examples.java b/src/Examples.java index 1e17944..7a55f82 100644 --- a/src/Examples.java +++ b/src/Examples.java @@ -1,8 +1,6 @@ +import async_example.Delay; +import async_example.Jokio; import generator.future.Future; -import generator.future.Waker; - -import java.util.Timer; -import java.util.TimerTask; public class Examples { // public static Gen parse(String str){ @@ -69,49 +67,24 @@ public class Examples { // return Gen.ret(); // } - public static class Delay implements Future{ - private final static Timer timer; - static{ - timer = new Timer(true); - } - private int delay; - private boolean ready; - public Delay(int ms){ - if(ms<0)throw new IllegalArgumentException("Delay cannot be negative"); - delay = ms; - } - @Override - public synchronized Object poll(Waker waker) { - if(delay==0){ - ready=true; - delay=-1; - return null; - } - if(delay != -1){ - timer.schedule(new TimerTask() { - @Override - public void run() { - ready = true; - waker.wake(); - } - }, delay); - delay = -1; - } - - if(ready)return null; - return Pending.INSTANCE; - } - } - public static Future awaitTest2(int number){ ((Future)new Delay(number)).await(); return Future.ret(number+"ms"); } public Future awaitTest(int number){ + var result = awaitTest2(number).await(); + var rt = Jokio.runtime().await(); + rt.spawn(awaitTest2(5000)); +// closing(100); +// closing(10).await(); + return Future.ret("Result: " + result); + } + + public Future closing(int number){ try(var m = new Meow()){ var result = awaitTest2(number).await(); - return Future.ret("Result: " + result); + return Future.ret(result); } } diff --git a/src/Main.java b/src/Main.java index a955d7c..5efe763 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,10 +1,9 @@ +import async_example.Jokio; import generator.RT; import generator.future.Future; import generator.future.Waker; import generator.gen.Gen; -import java.util.function.Supplier; - public class Main implements Runnable { public static void main(String[] args) { RT.runWithGeneratorSupport(Main.class); @@ -58,7 +57,7 @@ public class Main implements Runnable { } void await(){ - System.out.println(simple_async_rt(new Examples().awaitTest(2000))); + new Jokio().blocking(new Examples().awaitTest(2000)); } diff --git a/src/async_example/Delay.java b/src/async_example/Delay.java new file mode 100644 index 0000000..f10df07 --- /dev/null +++ b/src/async_example/Delay.java @@ -0,0 +1,52 @@ +package async_example; + +import generator.future.Future; +import generator.future.Waker; + +import java.util.Timer; +import java.util.TimerTask; + +public class Delay implements Future { + private final static Timer timer; + private TimerTask task; + + static { + timer = new Timer(true); + } + + private int delay; + private boolean ready; + + public Delay(int ms) { + if (ms < 0) throw new IllegalArgumentException("async_example.Delay cannot be negative"); + delay = ms; + } + + @Override + public void cancel() { + if (task != null) task.cancel(); + } + + @Override + public synchronized Object poll(Waker waker) { + if (delay == 0) { + ready = true; + delay = -1; + return null; + } + if (delay != -1) { + task = new TimerTask() { + @Override + public void run() { + ready = true; + waker.wake(); + } + }; + timer.schedule(task, delay); + delay = -1; + } + + if (ready) return null; + return Pending.INSTANCE; + } +} diff --git a/src/async_example/Jokio.java b/src/async_example/Jokio.java new file mode 100644 index 0000000..4546137 --- /dev/null +++ b/src/async_example/Jokio.java @@ -0,0 +1,73 @@ +package async_example; + +import generator.future.Future; +import generator.future.Waker; + +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.Queue; + +public class Jokio implements Runnable{ + + private class Task implements Waker{ + public final Future future; + + private Task(Future future) { + this.future = future; + } + + @Override + public void wake() { + synchronized (Jokio.this){ + woke.add(this); + Jokio.this.notifyAll(); + } + } + + public Jokio runtime(){ + return Jokio.this; + } + } + + public static Future runtime(){ + return new Future<>() { + @Override + public Jokio poll(Waker waker) { + return ((Task)waker).runtime(); + } + }; + } + + private final HashSet> current = new HashSet<>(); + private final Queue> woke = new ArrayDeque<>(); + + public void blocking(Future fut){ + spawn(fut).run(); + } + + public synchronized Jokio spawn(Future future){ + var task = new Task<>(future); + current.add(task); + woke.add(task); + return this; + } + + @Override + public synchronized void run(){ + while(!current.isEmpty()) { + while(woke.isEmpty()) { + try { + this.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + var task = woke.poll(); + var result = task.future.poll(task); + if(result!=Future.Pending.INSTANCE) { + current.remove(task); + System.out.println(result); + } + } + } +} diff --git a/src/generator/runtime/GeneratorClassLoader.java b/src/generator/runtime/GeneratorClassLoader.java index d8e288c..c9f086c 100644 --- a/src/generator/runtime/GeneratorClassLoader.java +++ b/src/generator/runtime/GeneratorClassLoader.java @@ -60,7 +60,7 @@ public class GeneratorClassLoader extends ClassLoader { clm.findAttributes(Attributes.nestMembers()).forEach(i -> nestMem.addAll(i.nestMembers().stream().map(ClassEntry::asSymbol).toList())); clm.findAttributes(Attributes.innerClasses()).forEach(i -> innerCl.addAll(i.classes())); - return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(clm.thisClass().asSymbol(), cb -> { + return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES, ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED).build(clm.thisClass().asSymbol(), cb -> { for (var ce : clm) { if (ce instanceof MethodModel mem && !isGen && !isFuture) { StateMachineBuilder builder = null; @@ -104,6 +104,10 @@ public class GeneratorClassLoader extends ClassLoader { var smb = new FutureSMBuilder(src_clm, src_mem, com); try{ add(smb.CD_this.displayName(), smb.buildStateMachine()); + + cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> { + mb.withCode(smb::buildSourceMethodShim); + }); }catch (Exception e){ e.printStackTrace(); cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> { @@ -111,9 +115,6 @@ public class GeneratorClassLoader extends ClassLoader { }); return smb; } - cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> { - mb.withCode(smb::buildSourceMethodShim); - }); return smb; } } diff --git a/src/generator/runtime/LocalTracker.java b/src/generator/runtime/LocalTracker.java index cc1ec0f..9b768be 100644 --- a/src/generator/runtime/LocalTracker.java +++ b/src/generator/runtime/LocalTracker.java @@ -146,6 +146,7 @@ public class LocalTracker { case ITEM_FLOAT -> CD_float; case ITEM_DOUBLE -> CD_double; case ITEM_OBJECT -> sym; + case ITEM_NULL -> CD_Object; default -> throw new RuntimeException(); }; } @@ -433,7 +434,7 @@ public class LocalTracker { case TableSwitchInstruction ts -> popStack(); case ThrowInstruction t -> popStack(); - case TypeCheckInstruction tc -> {} + case TypeCheckInstruction tc -> decStack(1).pushStack(tc.type().asSymbol()); case DiscontinuedInstruction d -> throw new IllegalStateException(d.toString()); default -> throw new IllegalStateException(); } diff --git a/src/generator/runtime/StateMachineBuilder.java b/src/generator/runtime/StateMachineBuilder.java index 2f05fa7..5efd2f3 100644 --- a/src/generator/runtime/StateMachineBuilder.java +++ b/src/generator/runtime/StateMachineBuilder.java @@ -58,7 +58,7 @@ public abstract class StateMachineBuilder { if (!src_mem.flags().has(AccessFlag.STATIC)) { mts = mts.insertParameterTypes(0, src_clm.thisClass().asSymbol()); } - var name = src_clm.thisClass().name().stringValue() + "$" + src_mem.methodName().stringValue() + "$" + uniqueName(); + var name = src_clm.thisClass().asSymbol().displayName() + "$" + src_mem.methodName().stringValue() + "$" + uniqueName(); this.CD_this = ClassDesc.of(src_clm.thisClass().asSymbol().packageName(), name); this.params = mts.parameterArray(); @@ -84,7 +84,7 @@ public abstract class StateMachineBuilder { } public byte[] buildStateMachine(){ - return ClassFile.of(ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED, ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(CD_this, clb -> { + return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(CD_this, clb -> { if(shouldBeInnerClass()){ src_clm.findAttributes(Attributes.sourceFile()).forEach(clb::with); @@ -145,8 +145,8 @@ public abstract class StateMachineBuilder { handlers.add(handler.apply(this, cob)); } } -// if(handlers.isEmpty() && stateSwitchCases.isEmpty()) -// throw new RuntimeException("Not a state machine"); + if(handlers.isEmpty()) + throw new RuntimeException("Not a state machine"); cob.aload(0).getfield(CD_this, STATE_NAME, TypeKind.INT.upperBound()).lookupswitch(invalidState, stateSwitchCases); var start = cob.startLabel(); var end = cob.newLabel(); diff --git a/src/generator/runtime/future/FutureSMBuilder.java b/src/generator/runtime/future/FutureSMBuilder.java index ff56b93..6e0f4d0 100644 --- a/src/generator/runtime/future/FutureSMBuilder.java +++ b/src/generator/runtime/future/FutureSMBuilder.java @@ -24,6 +24,8 @@ public class FutureSMBuilder extends StateMachineBuilder { public final static MethodTypeDesc MTD_Object_Waker = MethodTypeDesc.of(ConstantDescs.CD_Object, CD_Waker); public final static MethodTypeDesc MTD_Obj = MethodTypeDesc.of(ConstantDescs.CD_Object); + public final static String AWAITING_FIELD_NAME = "awaiting"; + static class AwaitHandler implements SpecialMethodHandler{ final int yield_state; final Label yield_label; @@ -36,18 +38,19 @@ public class FutureSMBuilder extends StateMachineBuilder { @Override public void handle(StateMachineBuilder smb, CodeBuilder cob) { + System.out.println("Await"); cob.aload(0).loadConstant(yield_state).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()); var start = cob.newBoundLabel(); - cob.dup().dup() - .aload(1) - .invokeinterface(CD_Future, "poll", MTD_Object_Waker).dup() + cob.dup() + .aload(1).invokeinterface(CD_Future, "poll", MTD_Object_Waker).dup() .instanceOf(CD_Pending); cob.ifThenElse(bcb -> { + bcb.swap().aload(0).swap().putfield(smb.CD_this, AWAITING_FIELD_NAME, CD_Future); smb.lt.savingLocals(smb.CD_this, bcb, () -> { - bcb.swap().aload(0).swap().putfield(smb.CD_this, "meow", CD_Future); bcb.areturn().labelBinding(yield_label); - bcb.aload(0).getfield(smb.CD_this, "meow", CD_Future); }); + bcb.aload(0).getfield(smb.CD_this, AWAITING_FIELD_NAME, CD_Future); + bcb.aload(0).aconst_null().putfield(smb.CD_this, AWAITING_FIELD_NAME, CD_Future); bcb.goto_(start); }, bcb -> { bcb.swap().pop(); @@ -86,6 +89,7 @@ public class FutureSMBuilder extends StateMachineBuilder { @Override public void handle(StateMachineBuilder smb, CodeBuilder cob) { + System.out.println("Return"); cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()).areturn(); } } @@ -102,7 +106,14 @@ public class FutureSMBuilder extends StateMachineBuilder { cob.localVariable(1, "waker", CD_Waker, cob.startLabel(), cob.endLabel()); buildStateMachineMethodCode(clb, cob, 2); })); - clb.withField("meow", CD_Future, ClassFile.ACC_PRIVATE); + clb.withMethod("cancel", MethodTypeDesc.of(ConstantDescs.CD_void), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> { + cob.aload(0).getfield(CD_this, AWAITING_FIELD_NAME, CD_Future).dup().ifThen(Opcode.IFNONNULL, boc -> { + boc.invokeinterface(CD_Future, "cancel", MethodTypeDesc.of(ConstantDescs.CD_void)) + .aload(0).aconst_null().putfield(CD_this, AWAITING_FIELD_NAME, CD_Future).return_(); + }); + cob.pop().return_(); + })); + clb.withField(AWAITING_FIELD_NAME, CD_Future, ClassFile.ACC_PRIVATE); } public FutureSMBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com) {