mirror of
https://github.com/ParkerTenBroeck/coroutines.git
synced 2026-06-07 05:08:51 -04:00
separated state machine generation into an abstract class
This commit is contained in:
parent
c3532507f3
commit
9b0a9b7ad2
12 changed files with 379 additions and 286 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
import generator.RT;
|
import generator.RT;
|
||||||
import generator.gen.Gen;
|
import generator.gen.Gen;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class Main implements Runnable {
|
public class Main implements Runnable {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
RT.runWithGeneratorSupport(Main.class);
|
RT.runWithGeneratorSupport(Main.class);
|
||||||
|
|
@ -10,6 +12,23 @@ public class Main implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
// await();
|
// await();
|
||||||
lexer();
|
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 await(){
|
void await(){
|
||||||
|
|
@ -22,8 +41,11 @@ public class Main implements Runnable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Runnable meow = () -> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lexer(){
|
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 = 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});
|
// var gen = Examples.test(new double[]{1,2,3,4});
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ public interface Future<R> {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static <R> Future<R> ret(R r){
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
final class Pending{
|
final class Pending{
|
||||||
private static final Pending INSTANCE = new Pending();
|
private static final Pending INSTANCE = new Pending();
|
||||||
private Pending(){}
|
private Pending(){}
|
||||||
|
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
package generator.runtime;
|
|
||||||
|
|
||||||
import generator.gen.Gen;
|
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
|
||||||
import java.lang.classfile.attribute.InnerClassInfo;
|
|
||||||
import java.lang.classfile.attribute.InnerClassesAttribute;
|
|
||||||
import java.lang.classfile.attribute.NestHostAttribute;
|
|
||||||
import java.lang.constant.ClassDesc;
|
|
||||||
import java.lang.constant.ConstantDescs;
|
|
||||||
import java.lang.constant.MethodTypeDesc;
|
|
||||||
import java.lang.reflect.AccessFlag;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class GeneratorBuilder {
|
|
||||||
public final static String PARAM_PREFIX = "param_";
|
|
||||||
public final static String LOCAL_PREFIX = "local_";
|
|
||||||
public final static String STACK_PREFIX = "stack_";
|
|
||||||
public final static String STATE_NAME = "state";
|
|
||||||
|
|
||||||
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 static MethodTypeDesc MTD_Obj = MethodTypeDesc.of(ConstantDescs.CD_Object);
|
|
||||||
|
|
||||||
public final ClassDesc CD_this;
|
|
||||||
public final ClassDesc[] params;
|
|
||||||
public final MethodTypeDesc MTD_init;
|
|
||||||
public final int paramSlotOff;
|
|
||||||
public final ClassModel clm;
|
|
||||||
|
|
||||||
public interface ParamConsumer{
|
|
||||||
void consume(String param, int slot, ClassDesc type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GeneratorBuilder(ClassModel clm, ClassDesc cd, ClassDesc[] params){
|
|
||||||
this.clm = clm;
|
|
||||||
CD_this = cd;
|
|
||||||
this.params = params;
|
|
||||||
MTD_init = MethodTypeDesc.of(ConstantDescs.CD_void, params);
|
|
||||||
paramSlotOff = Arrays.stream(params).mapToInt(p -> TypeKind.from(p).slotSize()).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void params(int slot_start, ParamConsumer consumer){
|
|
||||||
int offset = 0;
|
|
||||||
for (var param : params) {
|
|
||||||
consumer.consume(PARAM_PREFIX+offset, offset+slot_start, param);
|
|
||||||
offset += TypeKind.from(param).slotSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildGeneratorMethodShim(CodeBuilder cob){
|
|
||||||
cob.new_(CD_this).dup();
|
|
||||||
params(0, (_, slot, type) -> {
|
|
||||||
cob.loadLocal(TypeKind.from(type), slot);
|
|
||||||
});
|
|
||||||
cob.invokespecial(CD_this, ConstantDescs.INIT_NAME, MTD_init).areturn();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] buildGenerator(CodeModel com){
|
|
||||||
return ClassFile.of(ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED, ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(CD_this, clb -> {
|
|
||||||
|
|
||||||
clm.findAttributes(Attributes.sourceFile()).forEach(clb::with);
|
|
||||||
clb.with(InnerClassesAttribute.of(InnerClassInfo.of(CD_this, Optional.of(clm.thisClass().asSymbol()), Optional.of(CD_this.displayName().split("\\$")[1]), AccessFlag.PUBLIC, AccessFlag.FINAL, AccessFlag.STATIC)));
|
|
||||||
clb.with(NestHostAttribute.of(clm.thisClass()));
|
|
||||||
|
|
||||||
clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Gen)));
|
|
||||||
// parameter fields
|
|
||||||
params(0, (param, _, type) -> {
|
|
||||||
clb.withField(param, type, ClassFile.ACC_PRIVATE);
|
|
||||||
});
|
|
||||||
// fms state
|
|
||||||
clb.withField(STATE_NAME, ConstantDescs.CD_int, ClassFile.ACC_PRIVATE);
|
|
||||||
|
|
||||||
// constructor
|
|
||||||
clb.withMethod(ConstantDescs.INIT_NAME, MTD_init, ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
|
|
||||||
cob.aload(0).invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void);
|
|
||||||
params(1, (param, slot, type) -> {
|
|
||||||
cob.aload(0).loadLocal(TypeKind.from(type), slot).putfield(CD_this, param, type);
|
|
||||||
});
|
|
||||||
cob.return_();
|
|
||||||
}));
|
|
||||||
|
|
||||||
// fms method
|
|
||||||
clb.withMethod("next", MethodTypeDesc.of(CD_Res), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
|
|
||||||
buildGeneratorNext(clb, cob, com);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildGeneratorNext(ClassBuilder clb, CodeBuilder cob, CodeModel com){
|
|
||||||
cob.trying(
|
|
||||||
tcob -> new StateMachineBuilder(this, clb, tcob, com).generateStateMachine(),
|
|
||||||
// catch anything set our state to -1 and throw the exception
|
|
||||||
ctb -> ctb.catchingAll(
|
|
||||||
blc -> blc.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int).athrow()
|
|
||||||
)
|
|
||||||
).aconst_null().areturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +1,18 @@
|
||||||
package generator.runtime;
|
package generator.runtime;
|
||||||
|
|
||||||
import generator.gen.Gen;
|
import generator.gen.Gen;
|
||||||
|
import generator.runtime.gen.GenSMBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
import java.lang.classfile.attribute.*;
|
import java.lang.classfile.attribute.*;
|
||||||
import java.lang.classfile.constantpool.ClassEntry;
|
import java.lang.classfile.constantpool.ClassEntry;
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
import java.lang.constant.ConstantDescs;
|
|
||||||
import java.lang.reflect.AccessFlag;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class GeneratorClassLoader extends ClassLoader {
|
public class GeneratorClassLoader extends ClassLoader {
|
||||||
private final HashMap<String, byte[]> customClazzDefMap = new HashMap<>();
|
|
||||||
private final HashMap<String, Class<?>> customClazzMap = new HashMap<>();
|
private final HashMap<String, Class<?>> customClazzMap = new HashMap<>();
|
||||||
|
|
||||||
public GeneratorClassLoader(ClassLoader parent) {
|
public GeneratorClassLoader(ClassLoader parent) {
|
||||||
|
|
@ -23,13 +20,12 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(String name, byte[] def){
|
void add(String name, byte[] def){
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(Path.of("out/modified/generators/" + name.replace(".", "/")).getParent());
|
Files.createDirectories(Path.of("out/modified/generators/" + name.replace(".", "/")).getParent());
|
||||||
Files.write(Path.of("out/modified/generators/" + name.replace(".", "/") + ".class"), def);
|
Files.write(Path.of("out/modified/generators/" + name.replace(".", "/") + ".class"), def);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
customClazzDefMap.put(name, def);
|
|
||||||
customClazzMap.put(name, defineClass(name, def, 0, def.length));
|
customClazzMap.put(name, defineClass(name, def, 0, def.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +64,8 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
cb.with(mem);
|
cb.with(mem);
|
||||||
} else{
|
} else{
|
||||||
var gcd = generatorMethod(cb, mem, clm);
|
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));
|
// 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()));
|
// nestMem.add(ClassDesc.of(gcd.displayName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ce instanceof Attribute<?> e){
|
else if (ce instanceof Attribute<?> e){
|
||||||
|
|
@ -85,29 +81,13 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassDesc generatorMethod(ClassBuilder cb, MethodModel mem, ClassModel clm) {
|
private ClassDesc generatorMethod(ClassBuilder cb, MethodModel src_mem, ClassModel src_clm) {
|
||||||
|
var com = src_mem.code().get();
|
||||||
AtomicReference<ClassDesc> gcd = new AtomicReference<>();
|
var gb = new GenSMBuilder(src_clm, src_mem, com);
|
||||||
|
add(gb.CD_this.displayName(), gb.buildStateMachine());
|
||||||
cb.withMethod(mem.methodName(), mem.methodType(), mem.flags().flagsMask(), mb -> {
|
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
|
||||||
for (var me : mem) {
|
mb.withCode(gb::buildSourceMethodShim);
|
||||||
if (me instanceof CodeModel com) {
|
|
||||||
var mts = mem.methodTypeSymbol();
|
|
||||||
mts = mts.changeReturnType(ConstantDescs.CD_void);
|
|
||||||
if (!mem.flags().has(AccessFlag.STATIC)) {
|
|
||||||
mts = mts.insertParameterTypes(0, clm.thisClass().asSymbol());
|
|
||||||
}
|
|
||||||
var name = clm.thisClass().name().stringValue()+"$Gen_" + mem.methodName().stringValue() + "_" + customClazzDefMap.size();
|
|
||||||
|
|
||||||
gcd.set(ClassDesc.of(clm.thisClass().asSymbol().packageName(), name));
|
|
||||||
var gb = new GeneratorBuilder(clm, gcd.get(), mts.parameterArray());
|
|
||||||
|
|
||||||
mb.withCode(gb::buildGeneratorMethodShim);
|
|
||||||
add(gb.CD_this.displayName(), gb.buildGenerator(com));
|
|
||||||
} else mb.with(me);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
return gb.CD_this;
|
||||||
return gcd.get();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import java.util.HashMap;
|
||||||
|
|
||||||
import static java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo.TOP;
|
import static java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo.TOP;
|
||||||
|
|
||||||
class LocalTracker {
|
public class LocalTracker {
|
||||||
|
|
||||||
record LocalStore(String name, ClassDesc cd) {
|
record LocalStore(String name, ClassDesc cd) {
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ class LocalTracker {
|
||||||
|
|
||||||
LocalTracker(StateMachineBuilder smb, CodeModel com) {
|
LocalTracker(StateMachineBuilder smb, CodeModel com) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (var param : smb.gb.params) {
|
for (var param : smb.params) {
|
||||||
parameter_map.put(offset, param);
|
parameter_map.put(offset, param);
|
||||||
offset += TypeKind.from(param).slotSize();
|
offset += TypeKind.from(param).slotSize();
|
||||||
}
|
}
|
||||||
|
|
@ -32,8 +32,8 @@ class LocalTracker {
|
||||||
var entries = new ArrayList<StackMapFrameInfo>();
|
var entries = new ArrayList<StackMapFrameInfo>();
|
||||||
for (var smfi : attr.entries()) {
|
for (var smfi : attr.entries()) {
|
||||||
var locals = new ArrayList<>(smfi.locals());
|
var locals = new ArrayList<>(smfi.locals());
|
||||||
for (int i = 0; i < smb.gb.params.length; i++) locals.removeFirst();
|
for (int i = 0; i < smb.params.length; i++) locals.removeFirst();
|
||||||
locals.addFirst(StackMapFrameInfo.ObjectVerificationTypeInfo.of(smb.gb.CD_this));
|
locals.addFirst(StackMapFrameInfo.ObjectVerificationTypeInfo.of(smb.CD_this));
|
||||||
entries.add(StackMapFrameInfo.of(smfi.target(), locals, smfi.stack()));
|
entries.add(StackMapFrameInfo.of(smfi.target(), locals, smfi.stack()));
|
||||||
stackMapFrames.put(smfi.target(), entries.getLast());
|
stackMapFrames.put(smfi.target(), entries.getLast());
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ class LocalTracker {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = GeneratorBuilder.LOCAL_PREFIX + localStore.size();
|
name = StateMachineBuilder.LOCAL_PREFIX + localStore.size();
|
||||||
localStore.add(new LocalStore(name, desc));
|
localStore.add(new LocalStore(name, desc));
|
||||||
}
|
}
|
||||||
saved.add(new Saved(slot, name, desc));
|
saved.add(new Saved(slot, name, desc));
|
||||||
|
|
|
||||||
7
src/generator/runtime/ParamConsumer.java
Normal file
7
src/generator/runtime/ParamConsumer.java
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package generator.runtime;
|
||||||
|
|
||||||
|
import java.lang.constant.ClassDesc;
|
||||||
|
|
||||||
|
public interface ParamConsumer {
|
||||||
|
void consume(String param, int slot, ClassDesc type);
|
||||||
|
}
|
||||||
7
src/generator/runtime/ReplacementKind.java
Normal file
7
src/generator/runtime/ReplacementKind.java
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package generator.runtime;
|
||||||
|
|
||||||
|
public enum ReplacementKind {
|
||||||
|
ImmediateReplacingPop,
|
||||||
|
Immediate,
|
||||||
|
ReplacingNextReturn,
|
||||||
|
}
|
||||||
7
src/generator/runtime/SpecialMethod.java
Normal file
7
src/generator/runtime/SpecialMethod.java
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package generator.runtime;
|
||||||
|
|
||||||
|
import java.lang.constant.ClassDesc;
|
||||||
|
import java.lang.constant.MethodTypeDesc;
|
||||||
|
|
||||||
|
public record SpecialMethod(ClassDesc owner, String name, MethodTypeDesc desc) {
|
||||||
|
}
|
||||||
13
src/generator/runtime/SpecialMethodHandler.java
Normal file
13
src/generator/runtime/SpecialMethodHandler.java
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
package generator.runtime;
|
||||||
|
|
||||||
|
import java.lang.classfile.CodeBuilder;
|
||||||
|
|
||||||
|
public interface SpecialMethodHandler {
|
||||||
|
void handle(StateMachineBuilder smb, CodeBuilder cob);
|
||||||
|
|
||||||
|
default boolean removeCall() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplacementKind replacementKind();
|
||||||
|
}
|
||||||
|
|
@ -1,162 +1,161 @@
|
||||||
package generator.runtime;
|
package generator.runtime;
|
||||||
|
|
||||||
|
import generator.gen.Gen;
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
|
import java.lang.classfile.attribute.InnerClassInfo;
|
||||||
|
import java.lang.classfile.attribute.InnerClassesAttribute;
|
||||||
|
import java.lang.classfile.attribute.NestHostAttribute;
|
||||||
import java.lang.classfile.instruction.*;
|
import java.lang.classfile.instruction.*;
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
import java.lang.constant.ConstantDescs;
|
import java.lang.constant.ConstantDescs;
|
||||||
import java.lang.constant.MethodTypeDesc;
|
import java.lang.constant.MethodTypeDesc;
|
||||||
import java.util.ArrayList;
|
import java.lang.reflect.AccessFlag;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
public class StateMachineBuilder {
|
public abstract class StateMachineBuilder {
|
||||||
final ClassBuilder clb;
|
public final static String PARAM_PREFIX = "param_";
|
||||||
final CodeBuilder cob;
|
public final static String LOCAL_PREFIX = "local_";
|
||||||
final CodeModel com;
|
public final static String STATE_NAME = "state";
|
||||||
final GeneratorBuilder gb;
|
|
||||||
final LocalTracker lt;
|
|
||||||
|
|
||||||
private HashMap<SpecialMethod, Function<StateMachineBuilder, SpecialMethodHandler>> smmap = new HashMap<>();
|
private static int sequence;
|
||||||
private boolean ignore_next_pop = false;
|
|
||||||
final ArrayList<SwitchCase> stateSwitchCases = new ArrayList<>();
|
|
||||||
final Label invalidState;
|
|
||||||
|
|
||||||
|
public final ClassDesc CD_this;
|
||||||
|
public final ClassDesc[] params;
|
||||||
|
public final MethodTypeDesc MTD_init;
|
||||||
|
public final int paramSlotOff;
|
||||||
|
|
||||||
public enum HandlerRan{
|
public final ClassModel src_clm;
|
||||||
ImmediateRemovePop,
|
public final MethodModel src_mem;
|
||||||
Immediate,
|
public final CodeModel src_com;
|
||||||
ReplacingNextReturn,
|
|
||||||
}
|
public final LocalTracker lt;
|
||||||
public interface SpecialMethodHandler {
|
|
||||||
void handle(StateMachineBuilder smb);
|
protected HashMap<SpecialMethod, BiFunction<StateMachineBuilder, CodeBuilder, SpecialMethodHandler>> smmap = new HashMap<>();
|
||||||
default boolean removeCall(){return true;}
|
|
||||||
default HandlerRan handlerRan(){return HandlerRan.ImmediateRemovePop;}
|
private final ArrayList<SwitchCase> stateSwitchCases = new ArrayList<>();
|
||||||
|
|
||||||
|
protected final String uniqueName(){
|
||||||
|
return sequence+++"";
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SpecialMethod(ClassDesc owner, String name, MethodTypeDesc desc) {
|
public void params(int slot_start, ParamConsumer consumer){
|
||||||
}
|
int offset = 0;
|
||||||
|
for (var param : params) {
|
||||||
static class YieldHandler implements SpecialMethodHandler {
|
consumer.consume(PARAM_PREFIX+offset, offset+slot_start, param);
|
||||||
final int resume_state;
|
offset += TypeKind.from(param).slotSize();
|
||||||
final Label resume_label;
|
|
||||||
final boolean is_void;
|
|
||||||
|
|
||||||
public YieldHandler(StateMachineBuilder smb, boolean is_void) {
|
|
||||||
resume_state = smb.add_state(resume_label = smb.cob.newLabel());
|
|
||||||
this.is_void = is_void;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(StateMachineBuilder smb) {
|
|
||||||
if(is_void)smb.cob.aconst_null();
|
|
||||||
|
|
||||||
smb.lt.savingLocals(smb.gb.CD_this, smb.cob, () -> {
|
|
||||||
smb.cob.aload(0).loadConstant(resume_state).putfield(smb.gb.CD_this, GeneratorBuilder.STATE_NAME, TypeKind.INT.upperBound())
|
|
||||||
.new_(GeneratorBuilder.CD_Yield)
|
|
||||||
.dup_x1()
|
|
||||||
.swap()
|
|
||||||
.invokespecial(GeneratorBuilder.CD_Yield, ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Object))
|
|
||||||
.areturn();
|
|
||||||
smb.cob.labelBinding(resume_label);
|
|
||||||
});
|
|
||||||
smb.ignore_next_pop = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class RetHandler implements SpecialMethodHandler {
|
public StateMachineBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com){
|
||||||
final boolean is_void;
|
this.src_clm = src_clm;
|
||||||
|
this.src_mem = src_mem;
|
||||||
|
this.src_com = src_com;
|
||||||
|
|
||||||
public RetHandler(boolean is_void) {
|
var mts = src_mem.methodTypeSymbol();
|
||||||
this.is_void = is_void;
|
mts = mts.changeReturnType(ConstantDescs.CD_void);
|
||||||
|
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();
|
||||||
|
|
||||||
public HandlerRan handlerRan(){return HandlerRan.ReplacingNextReturn;}
|
this.CD_this = ClassDesc.of(src_clm.thisClass().asSymbol().packageName(), name);
|
||||||
|
this.params = mts.parameterArray();
|
||||||
|
this.MTD_init = MethodTypeDesc.of(ConstantDescs.CD_void, params);
|
||||||
|
this.paramSlotOff = Arrays.stream(params).mapToInt(p -> TypeKind.from(p).slotSize()).sum();
|
||||||
|
|
||||||
@Override
|
this.lt = new LocalTracker(this, src_com);
|
||||||
public void handle(StateMachineBuilder smb) {
|
|
||||||
if(is_void)smb.cob.aconst_null();
|
|
||||||
|
|
||||||
smb.cob.aload(0).loadConstant(-1).putfield(smb.gb.CD_this, GeneratorBuilder.STATE_NAME, TypeKind.INT.upperBound())
|
|
||||||
.new_(GeneratorBuilder.CD_Ret)
|
|
||||||
.dup_x1()
|
|
||||||
.swap()
|
|
||||||
.invokespecial(GeneratorBuilder.CD_Ret, ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Object))
|
|
||||||
.areturn();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AwaitHandler implements SpecialMethodHandler{
|
public int add_state(Label label) {
|
||||||
final int yield_state;
|
|
||||||
final Label yield_label;
|
|
||||||
|
|
||||||
public AwaitHandler(StateMachineBuilder smb) {
|
|
||||||
yield_state = smb.add_state(yield_label = smb.cob.newLabel());
|
|
||||||
}
|
|
||||||
|
|
||||||
public HandlerRan handlerRan(){return HandlerRan.Immediate;}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(StateMachineBuilder smb) {
|
|
||||||
smb.cob.aload(0).loadConstant(yield_state).putfield(smb.gb.CD_this, GeneratorBuilder.STATE_NAME, TypeKind.INT.upperBound());
|
|
||||||
var start = smb.cob.newBoundLabel();
|
|
||||||
smb.cob.dup().dup()
|
|
||||||
.invokeinterface(GeneratorBuilder.CD_Gen, "next", MethodTypeDesc.of(GeneratorBuilder.CD_Res)).dup()
|
|
||||||
.instanceOf(GeneratorBuilder.CD_Ret);
|
|
||||||
smb.cob.ifThenElse(bcb -> {
|
|
||||||
bcb.checkcast(GeneratorBuilder.CD_Ret).invokevirtual(GeneratorBuilder.CD_Ret, "v", MethodTypeDesc.of(ConstantDescs.CD_Object)).swap().pop();
|
|
||||||
}, bcb -> {
|
|
||||||
smb.lt.savingLocals(smb.gb.CD_this, bcb, () -> {
|
|
||||||
bcb.swap().loadLocal(TypeKind.from(smb.gb.CD_this), 0).swap().putfield(smb.gb.CD_this, "meow", GeneratorBuilder.CD_Gen);
|
|
||||||
bcb.areturn().labelBinding(yield_label);
|
|
||||||
bcb.loadLocal(TypeKind.from(smb.gb.CD_this), 0).getfield(smb.gb.CD_this, "meow", GeneratorBuilder.CD_Gen);
|
|
||||||
});
|
|
||||||
bcb.goto_(start);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StateMachineBuilder(GeneratorBuilder gb, ClassBuilder clb, CodeBuilder cob, CodeModel com) {
|
|
||||||
this.gb = gb;
|
|
||||||
this.clb = clb;
|
|
||||||
this.cob = cob;
|
|
||||||
this.com = com;
|
|
||||||
this.lt = new LocalTracker(this, com);
|
|
||||||
invalidState = cob.newLabel();
|
|
||||||
|
|
||||||
smmap.put(new SpecialMethod(GeneratorBuilder.CD_Gen, "yield", GeneratorBuilder.MTD_Gen_Obj),smb -> new YieldHandler(smb, false));
|
|
||||||
smmap.put(new SpecialMethod(GeneratorBuilder.CD_Gen, "yield", GeneratorBuilder.MTD_Gen),smb -> new YieldHandler(smb, true));
|
|
||||||
smmap.put(new SpecialMethod(GeneratorBuilder.CD_Gen, "ret", GeneratorBuilder.MTD_Gen_Obj),_ -> new RetHandler(false));
|
|
||||||
smmap.put(new SpecialMethod(GeneratorBuilder.CD_Gen, "ret", GeneratorBuilder.MTD_Gen),_ -> new RetHandler(true));
|
|
||||||
smmap.put(new SpecialMethod(GeneratorBuilder.CD_Gen, "await", GeneratorBuilder.MTD_Obj), AwaitHandler::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
int add_state(Label label) {
|
|
||||||
stateSwitchCases.add(SwitchCase.of(stateSwitchCases.size(), label));
|
stateSwitchCases.add(SwitchCase.of(stateSwitchCases.size(), label));
|
||||||
return stateSwitchCases.size() - 1;
|
return stateSwitchCases.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateStateMachine() {
|
public void buildSourceMethodShim(CodeBuilder cob){
|
||||||
|
cob.new_(CD_this).dup();
|
||||||
|
params(0, (_, slot, type) -> {
|
||||||
|
cob.loadLocal(TypeKind.from(type), slot);
|
||||||
|
});
|
||||||
|
cob.invokespecial(CD_this, ConstantDescs.INIT_NAME, MTD_init).areturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldBeInnerClass(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] buildStateMachine(){
|
||||||
|
return ClassFile.of(ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED, ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).build(CD_this, clb -> {
|
||||||
|
|
||||||
|
if(shouldBeInnerClass()){
|
||||||
|
src_clm.findAttributes(Attributes.sourceFile()).forEach(clb::with);
|
||||||
|
clb.with(InnerClassesAttribute.of(InnerClassInfo.of(CD_this, Optional.of(src_clm.thisClass().asSymbol()), Optional.of(CD_this.displayName().split("\\$")[1]), AccessFlag.PUBLIC, AccessFlag.FINAL, AccessFlag.STATIC)));
|
||||||
|
clb.with(NestHostAttribute.of(src_clm.thisClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameter fields
|
||||||
|
params(0, (param, _, type) -> {
|
||||||
|
clb.withField(param, type, ClassFile.ACC_PRIVATE);
|
||||||
|
});
|
||||||
|
|
||||||
|
clb.withField(STATE_NAME, ConstantDescs.CD_int, ClassFile.ACC_PRIVATE);
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
clb.withMethod(ConstantDescs.INIT_NAME, MTD_init, ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
|
||||||
|
cob.aload(0).invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void);
|
||||||
|
params(1, (param, slot, type) -> {
|
||||||
|
cob.aload(0).loadLocal(TypeKind.from(type), slot).putfield(CD_this, param, type);
|
||||||
|
});
|
||||||
|
cob.return_();
|
||||||
|
}));
|
||||||
|
|
||||||
|
buildStateMachineMethod(clb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void buildStateMachineMethod(ClassBuilder clb);
|
||||||
|
|
||||||
|
public void buildStateMachineMethodCode(ClassBuilder clb, CodeBuilder cob){
|
||||||
|
cob.trying(
|
||||||
|
tcob -> buildStateMachineCode(clb, tcob),
|
||||||
|
// catch anything set our state to -1 and throw the exception
|
||||||
|
ctb -> ctb.catchingAll(
|
||||||
|
blc ->
|
||||||
|
blc.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int)
|
||||||
|
.new_(ClassDesc.ofDescriptor(RuntimeException.class.descriptorString()))
|
||||||
|
.dup_x1()
|
||||||
|
.swap()
|
||||||
|
.invokespecial(ClassDesc.ofDescriptor(RuntimeException.class.descriptorString()), ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Throwable))
|
||||||
|
.athrow()
|
||||||
|
)
|
||||||
|
).aconst_null().areturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob) {
|
||||||
|
boolean ignore_next_pop = false;
|
||||||
|
|
||||||
|
var invalidState = cob.newLabel();
|
||||||
var start_label = cob.newLabel();
|
var start_label = cob.newLabel();
|
||||||
add_state(start_label);
|
add_state(start_label);
|
||||||
|
|
||||||
var handlers = new ArrayList<SpecialMethodHandler>();
|
var handlers = new ArrayList<SpecialMethodHandler>();
|
||||||
for (CodeElement coe : com) {
|
for (CodeElement coe : src_com) {
|
||||||
if (coe instanceof InvokeInstruction is){
|
if (coe instanceof InvokeInstruction is){
|
||||||
var handler = smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol()));
|
var handler = smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol()));
|
||||||
if(handler != null)
|
if(handler != null)
|
||||||
handlers.add(handler.apply(this));
|
handlers.add(handler.apply(this, cob));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cob.aload(0).getfield(gb.CD_this, GeneratorBuilder.STATE_NAME, TypeKind.INT.upperBound()).lookupswitch(invalidState, stateSwitchCases);
|
cob.aload(0).getfield(CD_this, STATE_NAME, TypeKind.INT.upperBound()).lookupswitch(invalidState, stateSwitchCases);
|
||||||
var start = cob.startLabel();
|
var start = cob.startLabel();
|
||||||
var end = cob.newLabel();
|
var end = cob.newLabel();
|
||||||
cob.localVariable(0, "this", gb.CD_this, start, end);
|
cob.localVariable(0, "this", CD_this, start, end);
|
||||||
|
|
||||||
SpecialMethodHandler currentHandler = null;
|
SpecialMethodHandler currentHandler = null;
|
||||||
|
|
||||||
cob.labelBinding(start_label);
|
cob.labelBinding(start_label);
|
||||||
for (CodeElement coe : com) {
|
for (CodeElement coe : src_com) {
|
||||||
if (coe instanceof Instruction i) {
|
if (coe instanceof Instruction i) {
|
||||||
if (ignore_next_pop)
|
if (ignore_next_pop)
|
||||||
if (i.opcode() == Opcode.POP) {
|
if (i.opcode() == Opcode.POP) {
|
||||||
|
|
@ -164,8 +163,8 @@ public class StateMachineBuilder {
|
||||||
continue;
|
continue;
|
||||||
}else throw new RuntimeException("Expected Pop Instruction");
|
}else throw new RuntimeException("Expected Pop Instruction");
|
||||||
if (i.opcode() == Opcode.ARETURN){
|
if (i.opcode() == Opcode.ARETURN){
|
||||||
if (currentHandler !=null && currentHandler.handlerRan() == HandlerRan.ReplacingNextReturn){
|
if (currentHandler !=null && currentHandler.replacementKind() == ReplacementKind.ReplacingNextReturn){
|
||||||
currentHandler.handle(this);
|
currentHandler.handle(this, cob);
|
||||||
currentHandler = null;
|
currentHandler = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -179,9 +178,9 @@ public class StateMachineBuilder {
|
||||||
if(currentHandler!=null)throw new RuntimeException("Multiple method handlers at once not supported");
|
if(currentHandler!=null)throw new RuntimeException("Multiple method handlers at once not supported");
|
||||||
var handler = handlers.removeFirst();
|
var handler = handlers.removeFirst();
|
||||||
if(!handler.removeCall()) cob.with(coe);
|
if(!handler.removeCall()) cob.with(coe);
|
||||||
if(handler.handlerRan() == HandlerRan.Immediate) handler.handle(this);
|
if(handler.replacementKind() == ReplacementKind.Immediate) handler.handle(this, cob);
|
||||||
else if(handler.handlerRan() == HandlerRan.ImmediateRemovePop) {
|
else if(handler.replacementKind() == ReplacementKind.ImmediateReplacingPop) {
|
||||||
handler.handle(this);
|
handler.handle(this, cob);
|
||||||
ignore_next_pop = true;
|
ignore_next_pop = true;
|
||||||
}else
|
}else
|
||||||
currentHandler = handler;
|
currentHandler = handler;
|
||||||
|
|
@ -189,35 +188,33 @@ public class StateMachineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// System.out.println(coe);
|
|
||||||
|
|
||||||
switch (coe) {
|
switch (coe) {
|
||||||
// locals which were once function parameters can be ignored
|
// locals which were once function parameters can be ignored
|
||||||
case LocalVariable lv when lv.slot() < gb.paramSlotOff -> {
|
case LocalVariable lv when lv.slot() < paramSlotOff -> {
|
||||||
}
|
}
|
||||||
case LocalVariable lv ->
|
case LocalVariable lv ->
|
||||||
cob.localVariable(lv.slot() - gb.paramSlotOff + 1, lv.name(), lv.type(), lv.startScope(), lv.endScope());
|
cob.localVariable(lv.slot() - paramSlotOff + 1, lv.name(), lv.type(), lv.startScope(), lv.endScope());
|
||||||
|
|
||||||
// increment indexes into the stack
|
// increment indexes into the stack
|
||||||
case IncrementInstruction ii when ii.slot() < gb.paramSlotOff ->
|
case IncrementInstruction ii when ii.slot() < paramSlotOff ->
|
||||||
cob.aload(0).dup().getfield(gb.CD_this, GeneratorBuilder.PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int)
|
cob.aload(0).dup().getfield(CD_this, PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int)
|
||||||
.loadConstant(ii.constant()).iadd()
|
.loadConstant(ii.constant()).iadd()
|
||||||
.putfield(gb.CD_this, GeneratorBuilder.PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int);
|
.putfield(CD_this, PARAM_PREFIX + ii.slot(), ConstantDescs.CD_int);
|
||||||
case IncrementInstruction ii -> cob.iinc(ii.slot() - gb.paramSlotOff + 1, ii.constant());
|
case IncrementInstruction ii -> cob.iinc(ii.slot() - paramSlotOff + 1, ii.constant());
|
||||||
|
|
||||||
// convert local function parameters to class fields and offset regular locals
|
// convert local function parameters to class fields and offset regular locals
|
||||||
case LoadInstruction li when li.slot() < gb.paramSlotOff ->
|
case LoadInstruction li when li.slot() < paramSlotOff ->
|
||||||
cob.aload(0).getfield(gb.CD_this, GeneratorBuilder.PARAM_PREFIX + li.slot(), lt.paramType(li.slot()));
|
cob.aload(0).getfield(CD_this, PARAM_PREFIX + li.slot(), lt.paramType(li.slot()));
|
||||||
case LoadInstruction li -> cob.loadLocal(li.typeKind(), li.slot() - gb.paramSlotOff + 1);
|
case LoadInstruction li -> cob.loadLocal(li.typeKind(), li.slot() - paramSlotOff + 1);
|
||||||
|
|
||||||
// convert local function parameters to class fields and offset regular locals
|
// convert local function parameters to class fields and offset regular locals
|
||||||
case StoreInstruction ls when ls.slot() < gb.paramSlotOff && ls.typeKind().slotSize() == 2 ->
|
case StoreInstruction ls when ls.slot() < paramSlotOff && ls.typeKind().slotSize() == 2 ->
|
||||||
cob.aload(0).dup_x2().pop().putfield(gb.CD_this, GeneratorBuilder.PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
cob.aload(0).dup_x2().pop().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
||||||
case StoreInstruction ls when ls.slot() < gb.paramSlotOff ->
|
case StoreInstruction ls when ls.slot() < paramSlotOff ->
|
||||||
cob.aload(0).swap().putfield(gb.CD_this, GeneratorBuilder.PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
cob.aload(0).swap().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
||||||
case StoreInstruction ls -> {
|
case StoreInstruction ls -> {
|
||||||
lt.trackLocal(ls.slot() - gb.paramSlotOff + 1, ls.typeKind());
|
lt.trackLocal(ls.slot() - paramSlotOff + 1, ls.typeKind());
|
||||||
cob.storeLocal(ls.typeKind(), ls.slot() - gb.paramSlotOff + 1);
|
cob.storeLocal(ls.typeKind(), ls.slot() - paramSlotOff + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
default -> cob.with(coe);
|
default -> cob.with(coe);
|
||||||
|
|
@ -230,6 +227,5 @@ public class StateMachineBuilder {
|
||||||
cob.labelBinding(end);
|
cob.labelBinding(end);
|
||||||
|
|
||||||
lt.createLocalStoreFields(clb);
|
lt.createLocalStoreFields(clb);
|
||||||
clb.withField("meow", GeneratorBuilder.CD_Gen, ClassFile.ACC_PRIVATE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
70
src/generator/runtime/future/FutureSMBuilder.java
Normal file
70
src/generator/runtime/future/FutureSMBuilder.java
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
package generator.runtime.future;
|
||||||
|
|
||||||
|
import generator.gen.Gen;
|
||||||
|
import generator.runtime.ReplacementKind;
|
||||||
|
import generator.runtime.SpecialMethod;
|
||||||
|
import generator.runtime.SpecialMethodHandler;
|
||||||
|
import generator.runtime.StateMachineBuilder;
|
||||||
|
|
||||||
|
import java.lang.classfile.*;
|
||||||
|
import java.lang.constant.ClassDesc;
|
||||||
|
import java.lang.constant.ConstantDescs;
|
||||||
|
import java.lang.constant.MethodTypeDesc;
|
||||||
|
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 MethodTypeDesc MTD_Obj = MethodTypeDesc.of(ConstantDescs.CD_Object);
|
||||||
|
|
||||||
|
static class AwaitHandler implements SpecialMethodHandler{
|
||||||
|
final int yield_state;
|
||||||
|
final Label yield_label;
|
||||||
|
|
||||||
|
public AwaitHandler(StateMachineBuilder smb, CodeBuilder cob) {
|
||||||
|
yield_state = smb.add_state(yield_label = cob.newLabel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementKind replacementKind(){return ReplacementKind.Immediate;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(StateMachineBuilder smb, CodeBuilder cob) {
|
||||||
|
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);
|
||||||
|
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.areturn().labelBinding(yield_label);
|
||||||
|
bcb.loadLocal(TypeKind.from(smb.CD_this), 0).getfield(smb.CD_this, "meow", CD_Gen);
|
||||||
|
});
|
||||||
|
bcb.goto_(start);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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.withField("meow", CD_Gen, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/generator/runtime/gen/GenSMBuilder.java
Normal file
91
src/generator/runtime/gen/GenSMBuilder.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
package generator.runtime.gen;
|
||||||
|
|
||||||
|
import generator.gen.Gen;
|
||||||
|
import generator.runtime.ReplacementKind;
|
||||||
|
import generator.runtime.SpecialMethod;
|
||||||
|
import generator.runtime.SpecialMethodHandler;
|
||||||
|
import generator.runtime.StateMachineBuilder;
|
||||||
|
|
||||||
|
import java.lang.classfile.*;
|
||||||
|
import java.lang.constant.ClassDesc;
|
||||||
|
import java.lang.constant.ConstantDescs;
|
||||||
|
import java.lang.constant.MethodTypeDesc;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GenSMBuilder 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 MethodTypeDesc MTD_Obj = MethodTypeDesc.of(ConstantDescs.CD_Object);
|
||||||
|
|
||||||
|
static class YieldHandler implements SpecialMethodHandler {
|
||||||
|
final int resume_state;
|
||||||
|
final Label resume_label;
|
||||||
|
final boolean is_void;
|
||||||
|
|
||||||
|
public YieldHandler(StateMachineBuilder smb, CodeBuilder cob, boolean is_void) {
|
||||||
|
resume_state = smb.add_state(resume_label = cob.newLabel());
|
||||||
|
this.is_void = is_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementKind replacementKind(){return ReplacementKind.ImmediateReplacingPop;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(StateMachineBuilder smb, CodeBuilder cob) {
|
||||||
|
if(is_void)cob.aconst_null();
|
||||||
|
|
||||||
|
smb.lt.savingLocals(smb.CD_this, cob, () -> {
|
||||||
|
cob.aload(0).loadConstant(resume_state).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound())
|
||||||
|
.new_(CD_Yield)
|
||||||
|
.dup_x1()
|
||||||
|
.swap()
|
||||||
|
.invokespecial(CD_Yield, ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Object))
|
||||||
|
.areturn();
|
||||||
|
cob.labelBinding(resume_label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RetHandler implements SpecialMethodHandler {
|
||||||
|
final boolean is_void;
|
||||||
|
|
||||||
|
public RetHandler(boolean is_void) {
|
||||||
|
this.is_void = is_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(StateMachineBuilder smb, CodeBuilder cob) {
|
||||||
|
if(is_void)cob.aconst_null();
|
||||||
|
|
||||||
|
cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound())
|
||||||
|
.new_(CD_Ret)
|
||||||
|
.dup_x1()
|
||||||
|
.swap()
|
||||||
|
.invokespecial(CD_Ret, ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Object))
|
||||||
|
.areturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenSMBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com) {
|
||||||
|
super(src_clm, src_mem, src_com);
|
||||||
|
smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen_Obj),(smb, cob) -> new YieldHandler(smb, cob, false));
|
||||||
|
smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen),(smb, cob) -> new YieldHandler(smb, cob, true));
|
||||||
|
smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen_Obj),(_, _) -> new RetHandler(false));
|
||||||
|
smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen),(_, _) -> new RetHandler(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue