generalization

This commit is contained in:
ParkerTenBroeck 2025-04-26 10:07:57 -04:00
parent 9b0a9b7ad2
commit 95e7f6a59e
8 changed files with 174 additions and 104 deletions

View file

@ -1,3 +1,4 @@
import generator.future.Future;
import generator.gen.Gen;
public class Examples {
@ -65,25 +66,22 @@ public class Examples {
// return Gen.ret();
// }
public static Gen<Void, String> awaitTest2(int number){
for(int i = 0; i < number; i ++)Gen.yield();
return Gen.ret(number+"");
}
// public static Future<String> awaitTest2(int number){
// for(int i = 0; i < number; i ++)Future.yield();
// return Future.ret(number+"");
// }
public static class Meow implements AutoCloseable{
{
System.out.println("Opened");
}
@Override
public void close() {
System.out.println("Closed");
}
}
public static Gen<Void, String> awaitTest(int number){
try(var m = new Meow()){
return Gen.ret(awaitTest2(number).await());
}
public static Future<String> awaitTest(int number){
int i = 0;
// Future.yield();
// i = 1;
// Future.yield();
// i += i*12;
// Future.yield();
// return Future.ret(awaitTest2(number).await());
for(; i < number; i++)
Future.yield();
return Future.ret("meow"+i);
}
// public static Gen<Double, Void> test(double[] nyas){

View file

@ -1,4 +1,5 @@
import generator.RT;
import generator.future.Future;
import generator.gen.Gen;
import java.util.function.Supplier;
@ -10,47 +11,45 @@ public class Main implements Runnable {
@Override
public void run() {
// await();
lexer();
await();
// lexer();
// lambda();
}
void lambda(){
var gen = ((Supplier<Gen<Integer, String>>)() -> {
Gen.yield(12);
return Gen.ret("hello");
}).get();
while(true) {
var next = gen.next();
if(next instanceof Gen.Yield(var e)) System.out.println(e);
else if(next instanceof Gen.Ret(var ret)){
System.out.println(ret);
break;
}
}
}
// void lambda(){
// var gen = ((Supplier<Gen<Integer, String>>)() -> {
// Gen.yield(12);
// return Gen.ret("hello");
// }).get();
//
// while(true) {
// var next = gen.next();
// if(next instanceof Gen.Yield(var e)) System.out.println(e);
// else if(next instanceof Gen.Ret(var ret)){
// System.out.println(ret);
// break;
// }
// }
// }
void await(){
var gen = Examples.awaitTest(10);
while(true) {
var next = gen.next();
if(next instanceof Gen.Yield(var e)) System.out.println(e);
else if(next instanceof Gen.Ret(var ret)){
System.out.println(ret);
var next = (Object)gen.poll(() -> {});
if(!(next instanceof Future.Pending)){
System.out.println(next);
break;
}
System.out.println("Pending");
}
Runnable meow = () -> {};
}
void lexer(){
var gen = Lexer.parse("f7(x,y,z,w, u,v, othersIg) = v-(x*y+y+ln(z)^2*sin(z*pi/2))/(w*u)+sqrt(othersIg*120e-1)");
// var gen = Examples.test(new double[]{1,2,3,4});
while(gen.next() instanceof Gen.Yield(var tok)) {
System.out.println(tok);
}
}
// void lexer(){
// var gen = Lexer.parse("f7(x,y,z,w, u,v, othersIg) = v-(x*y+y+ln(z)^2*sin(z*pi/2))/(w*u)+sqrt(othersIg*120e-1)");
//// var gen = Examples.test(new double[]{1,2,3,4});
// while(gen.next() instanceof Gen.Yield(var tok)) {
// System.out.println(tok);
// }
// }
}

View file

@ -4,19 +4,23 @@ public interface Future<R> {
@SuppressWarnings("unchecked")
default R poll(Waker waker){
return (R) Pending.INSTANCE;
return (R)Pending.INSTANCE;
}
default R await(){
throw new RuntimeException();
throw new RuntimeException("NO!");
}
static <R> Future<R> ret(R r){
throw new RuntimeException();
throw new RuntimeException("NO!");
}
static void yield() {
throw new RuntimeException("NO!");
}
final class Pending{
private static final Pending INSTANCE = new Pending();
public static final Pending INSTANCE = new Pending();
private Pending(){}
}
}

View file

@ -1,6 +1,8 @@
package generator.runtime;
import generator.future.Future;
import generator.gen.Gen;
import generator.runtime.future.FutureSMBuilder;
import generator.runtime.gen.GenSMBuilder;
import java.io.IOException;
@ -8,6 +10,7 @@ import java.lang.classfile.*;
import java.lang.classfile.attribute.*;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.constant.ClassDesc;
import java.lang.reflect.AccessFlag;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -39,16 +42,17 @@ public class GeneratorClassLoader extends ClassLoader {
var p = "/" + name.replace('.', '/') + ".class";
try (var stream = GeneratorClassLoader.class.getResourceAsStream(p)) {
var bytes = Objects.requireNonNull(stream).readAllBytes();
add(name, searchForGenerators(bytes));
add(name, searchReplaceMethods(bytes));
return customClazzMap.get(name);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
}
public byte[] searchForGenerators(byte[] in) {
public byte[] searchReplaceMethods(byte[] in) {
var clm = ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).parse(in);
var isGen = clm.thisClass().asSymbol().descriptorString().equals(Gen.class.descriptorString());
var isFuture = clm.thisClass().asSymbol().descriptorString().equals(Future.class.descriptorString());
var nestMem = new ArrayList<ClassDesc>();
@ -58,14 +62,18 @@ public class GeneratorClassLoader extends ClassLoader {
return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(clm.thisClass().asSymbol(), cb -> {
for (var ce : clm) {
if (ce instanceof MethodModel mem && !isGen) {
var methodRetGen = mem.methodTypeSymbol().returnType().descriptorString().equals(Gen.class.descriptorString());
if (!methodRetGen) {
if (ce instanceof MethodModel mem && !isGen && !isFuture) {
StateMachineBuilder builder = null;
if(mem.methodTypeSymbol().returnType().descriptorString().equals(Gen.class.descriptorString())){
builder = generatorMethod(cb, mem, clm);
}else if(mem.methodTypeSymbol().returnType().descriptorString().equals(Future.class.descriptorString())){
builder = futureMethod(cb, mem, clm);
}else{
cb.with(mem);
} else{
var gcd = generatorMethod(cb, mem, clm);
// innerCl.add(InnerClassInfo.of(gcd, Optional.of(clm.thisClass().asSymbol()), Optional.of(gcd.displayName()), AccessFlag.PUBLIC, AccessFlag.FINAL, AccessFlag.STATIC));
// nestMem.add(ClassDesc.of(gcd.displayName()));
}
if(builder != null && builder.shouldBeInnerClass()){
innerCl.add(InnerClassInfo.of(builder.CD_this, Optional.of(clm.thisClass().asSymbol()), Optional.of(builder.CD_this.displayName()), AccessFlag.PUBLIC, AccessFlag.FINAL, AccessFlag.STATIC));
nestMem.add(ClassDesc.of(builder.CD_this.displayName()));
}
}
else if (ce instanceof Attribute<?> e){
@ -81,13 +89,23 @@ public class GeneratorClassLoader extends ClassLoader {
});
}
private ClassDesc generatorMethod(ClassBuilder cb, MethodModel src_mem, ClassModel src_clm) {
private StateMachineBuilder generatorMethod(ClassBuilder cb, MethodModel src_mem, ClassModel src_clm) {
var com = src_mem.code().get();
var gb = new GenSMBuilder(src_clm, src_mem, com);
add(gb.CD_this.displayName(), gb.buildStateMachine());
var smb = new GenSMBuilder(src_clm, src_mem, com);
add(smb.CD_this.displayName(), smb.buildStateMachine());
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
mb.withCode(gb::buildSourceMethodShim);
mb.withCode(smb::buildSourceMethodShim);
});
return gb.CD_this;
return smb;
}
private StateMachineBuilder futureMethod(ClassBuilder cb, MethodModel src_mem, ClassModel src_clm) {
var com = src_mem.code().get();
var smb = new FutureSMBuilder(src_clm, src_mem, com);
add(smb.CD_this.displayName(), smb.buildStateMachine());
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
mb.withCode(smb::buildSourceMethodShim);
});
return smb;
}
}

View file

@ -60,8 +60,8 @@ public class LocalTracker {
name = StateMachineBuilder.LOCAL_PREFIX + localStore.size();
localStore.add(new LocalStore(name, desc));
}
saved.add(new Saved(slot, name, desc));
cob.aload(0).loadLocal(tk, slot).putfield(cd, name, desc);
saved.add(new Saved(slot+1, name, desc));
cob.aload(0).loadLocal(tk, slot+1).putfield(cd, name, desc);
});
run.run();
@ -98,7 +98,7 @@ public class LocalTracker {
public void currentLocals(LocalConsumer consumer) {
var slot = 0;
if (currentFrame != null)
if (currentFrame != null && false)
for (var kind : currentFrame.locals()) {
switch (kind) {
case StackMapFrameInfo.ObjectVerificationTypeInfo o -> {
@ -129,10 +129,10 @@ public class LocalTracker {
case StackMapFrameInfo.UninitializedVerificationTypeInfo _ -> throw new IllegalStateException();
}
}
for (var entry : localVarTypes.entrySet()) {
if (entry.getKey() < slot) continue;
ClassDesc cd = entry.getValue().upperBound();
consumer.consume(entry.getKey(), TypeKind.from(cd), cd);
}
// for (var entry : localVarTypes.entrySet()) {
// if (entry.getKey() < slot) continue;
// ClassDesc cd = entry.getValue().upperBound();
// consumer.consume(entry.getKey(), TypeKind.from(cd), cd);
// }
}
}

View file

@ -36,7 +36,7 @@ public abstract class StateMachineBuilder {
private final ArrayList<SwitchCase> stateSwitchCases = new ArrayList<>();
protected final String uniqueName(){
protected String uniqueName(){
return sequence+++"";
}
@ -116,9 +116,9 @@ public abstract class StateMachineBuilder {
protected abstract void buildStateMachineMethod(ClassBuilder clb);
public void buildStateMachineMethodCode(ClassBuilder clb, CodeBuilder cob){
public void buildStateMachineMethodCode(ClassBuilder clb, CodeBuilder cob, int loc_param_off){
cob.trying(
tcob -> buildStateMachineCode(clb, tcob),
tcob -> buildStateMachineCode(clb, tcob, loc_param_off),
// catch anything set our state to -1 and throw the exception
ctb -> ctb.catchingAll(
blc ->
@ -132,7 +132,7 @@ public abstract class StateMachineBuilder {
).aconst_null().areturn();
}
public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob) {
public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob, int loc_param_off) {
boolean ignore_next_pop = false;
var invalidState = cob.newLabel();
@ -187,25 +187,27 @@ public abstract class StateMachineBuilder {
continue;
}
}
if(coe instanceof LocalVariable lv) System.out.println(lv);
switch (coe) {
// locals which were once function parameters can be ignored
case LocalVariable lv when lv.slot() < paramSlotOff -> {
}
case LocalVariable lv ->
cob.localVariable(lv.slot() - paramSlotOff + 1, lv.name(), lv.type(), lv.startScope(), lv.endScope());
cob.localVariable(lv.slot() - paramSlotOff + loc_param_off, lv.name(), lv.type(), lv.startScope(), lv.endScope());
// increment indexes into the stack
case IncrementInstruction ii when ii.slot() < paramSlotOff ->
cob.aload(0).dup().getfield(CD_this, PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int)
.loadConstant(ii.constant()).iadd()
.putfield(CD_this, PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int);
case IncrementInstruction ii -> cob.iinc(ii.slot() - paramSlotOff + 1, ii.constant());
case IncrementInstruction ii -> cob.iinc(ii.slot() - paramSlotOff + loc_param_off, ii.constant());
// convert local function parameters to class fields and offset regular locals
case LoadInstruction li when li.slot() < paramSlotOff ->
cob.aload(0).getfield(CD_this, PARAM_PREFIX + li.slot(), lt.paramType(li.slot()));
case LoadInstruction li -> cob.loadLocal(li.typeKind(), li.slot() - paramSlotOff + 1);
case LoadInstruction li ->
cob.loadLocal(li.typeKind(), li.slot() - paramSlotOff + loc_param_off);
// convert local function parameters to class fields and offset regular locals
case StoreInstruction ls when ls.slot() < paramSlotOff && ls.typeKind().slotSize() == 2 ->
@ -213,8 +215,8 @@ public abstract class StateMachineBuilder {
case StoreInstruction ls when ls.slot() < paramSlotOff ->
cob.aload(0).swap().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
case StoreInstruction ls -> {
lt.trackLocal(ls.slot() - paramSlotOff + 1, ls.typeKind());
cob.storeLocal(ls.typeKind(), ls.slot() - paramSlotOff + 1);
lt.trackLocal(ls.slot() - paramSlotOff + loc_param_off, ls.typeKind());
cob.storeLocal(ls.typeKind(), ls.slot() - paramSlotOff + loc_param_off);
}
default -> cob.with(coe);

View file

@ -1,5 +1,7 @@
package generator.runtime.future;
import generator.future.Future;
import generator.future.Waker;
import generator.gen.Gen;
import generator.runtime.ReplacementKind;
import generator.runtime.SpecialMethod;
@ -14,13 +16,12 @@ import java.util.List;
public class FutureSMBuilder extends StateMachineBuilder {
public final static ClassDesc CD_Gen = ClassDesc.ofDescriptor(Gen.class.descriptorString());
public final static ClassDesc CD_Res = ClassDesc.ofDescriptor(Gen.Res.class.descriptorString());
public final static ClassDesc CD_Yield = ClassDesc.ofDescriptor(Gen.Yield.class.descriptorString());
public final static ClassDesc CD_Ret = ClassDesc.ofDescriptor(Gen.Ret.class.descriptorString());
public final static MethodTypeDesc MTD_Res = MethodTypeDesc.of(CD_Res);
public final static MethodTypeDesc MTD_Gen_Obj = MethodTypeDesc.of(CD_Gen, ConstantDescs.CD_Object);
public final static MethodTypeDesc MTD_Gen = MethodTypeDesc.of(CD_Gen);
public final static ClassDesc CD_Future = ClassDesc.ofDescriptor(Future.class.descriptorString());
public final static ClassDesc CD_Waker = ClassDesc.ofDescriptor(Waker.class.descriptorString());
public final static ClassDesc CD_Pending = ClassDesc.ofDescriptor(Future.Pending.class.descriptorString());
public final static MethodTypeDesc MTD_Future_Obj = MethodTypeDesc.of(CD_Future, ConstantDescs.CD_Object);
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);
static class AwaitHandler implements SpecialMethodHandler{
@ -38,33 +39,76 @@ public class FutureSMBuilder extends StateMachineBuilder {
cob.aload(0).loadConstant(yield_state).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound());
var start = cob.newBoundLabel();
cob.dup().dup()
.invokeinterface(CD_Gen, "next", MethodTypeDesc.of(CD_Res)).dup()
.instanceOf(CD_Ret);
.aload(1)
.invokeinterface(CD_Future, "poll", MTD_Object_Waker).dup()
.instanceOf(CD_Pending);
cob.ifThenElse(bcb -> {
bcb.checkcast(CD_Ret).invokevirtual(CD_Ret, "v", MethodTypeDesc.of(ConstantDescs.CD_Object)).swap().pop();
}, bcb -> {
smb.lt.savingLocals(smb.CD_this, bcb, () -> {
bcb.swap().loadLocal(TypeKind.from(smb.CD_this), 0).swap().putfield(smb.CD_this, "meow", CD_Gen);
bcb.swap().aload(0).swap().putfield(smb.CD_this, "meow", CD_Future);
bcb.areturn().labelBinding(yield_label);
bcb.loadLocal(TypeKind.from(smb.CD_this), 0).getfield(smb.CD_this, "meow", CD_Gen);
bcb.aload(0).getfield(smb.CD_this, "meow", CD_Future);
});
bcb.goto_(start);
}, bcb -> {
bcb.swap().pop();
});
}
}
static class YieldHandler implements SpecialMethodHandler {
final int resume_state;
final Label resume_label;
public YieldHandler(StateMachineBuilder smb, CodeBuilder cob) {
resume_state = smb.add_state(resume_label = cob.newLabel());
}
public ReplacementKind replacementKind(){return ReplacementKind.Immediate;}
@Override
public void handle(StateMachineBuilder smb, CodeBuilder cob) {
smb.lt.savingLocals(smb.CD_this, cob, () -> {
cob.aload(0).loadConstant(resume_state).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound())
.getstatic(CD_Pending, "INSTANCE", CD_Pending)
.areturn();
cob.labelBinding(resume_label);
});
}
}
static class RetHandler implements SpecialMethodHandler{
public RetHandler() {}
public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;}
@Override
public void handle(StateMachineBuilder smb, CodeBuilder cob) {
cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()).areturn();
}
}
@Override
protected String uniqueName() {
return "Fut"+super.uniqueName();
}
@Override
protected void buildStateMachineMethod(ClassBuilder clb){
clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Gen)));
clb.withMethod("next", MethodTypeDesc.of(CD_Res), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
buildStateMachineMethodCode(clb, cob);
clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Future)));
clb.withMethod("poll", MTD_Object_Waker, ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
cob.localVariable(1, "waker", CD_Waker, cob.startLabel(), cob.endLabel());
buildStateMachineMethodCode(clb, cob, 2);
}));
clb.withField("meow", CD_Gen, ClassFile.ACC_PRIVATE);
clb.withField("meow", CD_Future, ClassFile.ACC_PRIVATE);
}
public FutureSMBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com) {
super(src_clm, src_mem, src_com);
smmap.put(new SpecialMethod(CD_Gen, "await", MTD_Obj), AwaitHandler::new);
smmap.put(new SpecialMethod(CD_Future, "await", MTD_Obj), AwaitHandler::new);
smmap.put(new SpecialMethod(CD_Future, "ret", MTD_Future_Obj), (_, _) -> new RetHandler());
smmap.put(new SpecialMethod(CD_Future, "yield", ConstantDescs.MTD_void), YieldHandler::new);
}
}

View file

@ -81,11 +81,16 @@ public class GenSMBuilder extends StateMachineBuilder {
smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen),(_, _) -> new RetHandler(true));
}
@Override
protected String uniqueName() {
return "Gen"+super.uniqueName();
}
@Override
protected void buildStateMachineMethod(ClassBuilder clb){
clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Gen)));
clb.withMethod("next", MethodTypeDesc.of(CD_Res), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
buildStateMachineMethodCode(clb, cob);
buildStateMachineMethodCode(clb, cob, 1);
}));
}
}