diff --git a/src/AsyncExamples.java b/src/AsyncExamples.java index 1227121..84e247e 100644 --- a/src/AsyncExamples.java +++ b/src/AsyncExamples.java @@ -5,12 +5,9 @@ import async_runtime.net.ServerSocket; import async_runtime.net.Socket; import future.Future; import future.Waker; +import generators.loadtime.future.Cancellation; import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -74,7 +71,7 @@ public class AsyncExamples { public static Future echo(Socket socket){ try(socket){ - @Test var buffer = ByteBuffer.allocate(4096*16*3); + @Cancellation var buffer = ByteBuffer.allocate(4096*16*3); while(true){ var read = socket.read(buffer).await(); buffer.clear().limit(read); @@ -88,7 +85,7 @@ public class AsyncExamples { public static Future echoForever(String message){ byte[] msg_bytes = message.getBytes(StandardCharsets.UTF_8); - try(@Test var socket = Socket.connect(new InetSocketAddress("localhost", 42069)).await()){ + try(@Cancellation("close") var socket = Socket.connect(new InetSocketAddress("localhost", 42069)).await()){ var buffer = ByteBuffer.allocate(message.length()); while(true){ buffer.limit(message.length()).put(msg_bytes).position(0); @@ -107,15 +104,4 @@ public class AsyncExamples { } return Future.ret(null); } - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE}) - @interface Test { - - } - - static class Meow implements AutoCloseable{ - @Override - public void close() throws Exception { - } - } } diff --git a/src/generators/loadtime/Frame.java b/src/generators/loadtime/Frame.java index 807d591..0035123 100644 --- a/src/generators/loadtime/Frame.java +++ b/src/generators/loadtime/Frame.java @@ -4,11 +4,16 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.instruction.LineNumber; import java.util.Arrays; -public record Frame(FrameTracker.Type[] locals, FrameTracker.Type[] stack, int bci, LineNumber line) { +public record Frame(FrameTracker.Type[] locals, FrameTracker.Type[] stack, int bci, LineNumber line, FrameTracker.LocalVariableAnnotation[] local_annotations) { @Override public String toString() { - return "Frame[l=" + Arrays.toString(locals) + ", s=" + Arrays.toString(stack) + ", bci=" + bci + ", line="+line + "]"; + return "Frame[l=" + Arrays.toString(locals) + + ", s=" + Arrays.toString(stack) + + ", bci=" + bci + + ", line="+line + + ", local_annotations=" + Arrays.toString(local_annotations) + + "]"; } public void save_locals(StateMachineBuilder smb, CodeBuilder cob, SavedStateTracker sst, int loc_off){ diff --git a/src/generators/loadtime/FrameTracker.java b/src/generators/loadtime/FrameTracker.java index beb486b..d6d5449 100644 --- a/src/generators/loadtime/FrameTracker.java +++ b/src/generators/loadtime/FrameTracker.java @@ -8,10 +8,7 @@ import java.lang.classfile.attribute.StackMapFrameInfo; import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.instruction.*; import java.lang.constant.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Objects; +import java.util.*; import static java.lang.constant.ConstantDescs.*; @@ -38,16 +35,20 @@ public class FrameTracker { var frames = new ArrayList(); for(var coe : src_com){ if(coe instanceof Instruction) { - frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, ft.current_line_number)); - System.out.println(frames.getLast() + " " + coe); + frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, ft.current_line_number, ft.local_annotations())); + System.out.println(frames.getLast()); } ft.encounter(coe); } - frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, null)); + frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, null, ft.local_annotations())); return frames; } + private LocalVariableAnnotation[] local_annotations() { + return this.activeAnnotations.toArray(LocalVariableAnnotation[]::new); + } + public Type[] locals() { return locals.toArray(Type[]::new); } @@ -57,7 +58,6 @@ public class FrameTracker { public record Type(int tag, ClassDesc sym, int bci) { - //singleton types static final Type TOP_TYPE = simpleType(ITEM_TOP), NULL_TYPE = simpleType(ITEM_NULL), INTEGER_TYPE = simpleType(ITEM_INTEGER), @@ -133,14 +133,14 @@ public class FrameTracker { } - static Type verificationType(StackMapFrameInfo.VerificationTypeInfo v){ + static Type verificationType(StackMapFrameInfo.VerificationTypeInfo v, FrameTracker t){ return switch (v){ - case StackMapFrameInfo.ObjectVerificationTypeInfo o -> Type.referenceType(o.classSymbol()); - case StackMapFrameInfo.SimpleVerificationTypeInfo s -> Type.simpleType(s.tag()); - case StackMapFrameInfo.UninitializedVerificationTypeInfo u -> { -// Type.uninitializedType(null, u.newTarget()); - throw new RuntimeException(); - } + case StackMapFrameInfo.ObjectVerificationTypeInfo o -> + Type.referenceType(o.classSymbol()); + case StackMapFrameInfo.SimpleVerificationTypeInfo s -> + Type.simpleType(s.tag()); + case StackMapFrameInfo.UninitializedVerificationTypeInfo u -> + Type.uninitializedType(null, t.bciMap.get(u.newTarget())); }; } @@ -169,7 +169,12 @@ public class FrameTracker { LineNumber current_line_number = null; int bci = 0; HashMap stackMapFrames = new HashMap<>(); + HashMap bciMap = new HashMap<>(); + public record LocalVariableAnnotation(Annotation annotation, int slot){} + final HashSet activeAnnotations = new HashSet<>(); + final HashMap> annotationStartMap = new HashMap<>(); + final HashMap> annotationEndMap = new HashMap<>(); FrameTracker(StateMachineBuilder smb, CodeModel com) { @@ -199,6 +204,40 @@ public class FrameTracker { offset += TypeKind.from(param).slotSize(); } + int bci = 0; + for(var ce : com){ + if(ce instanceof Instruction i) + bci += i.sizeInBytes(); + if(ce instanceof Label l) + bciMap.put(l, bci); + if(ce instanceof RuntimeVisibleTypeAnnotationsAttribute tas){ + for(var ta : tas.annotations()){ + switch(ta.targetInfo()){ + case TypeAnnotation.CatchTarget ct -> {} + case TypeAnnotation.EmptyTarget et -> {} + case TypeAnnotation.FormalParameterTarget fpt -> {} + case TypeAnnotation.LocalVarTarget lvt -> { + for(var el : lvt.table()){ + var lva = new LocalVariableAnnotation(ta.annotation(), el.index()); + annotationStartMap + .computeIfAbsent(el.startLabel(), k -> new ArrayList<>()) + .add(lva); + annotationEndMap + .computeIfAbsent(el.endLabel(), k -> new ArrayList<>()) + .add(lva); + } + } + case TypeAnnotation.OffsetTarget ot -> {} + case TypeAnnotation.SupertypeTarget stt -> {} + case TypeAnnotation.ThrowsTarget tt -> {} + case TypeAnnotation.TypeArgumentTarget tat -> {} + case TypeAnnotation.TypeParameterBoundTarget tpbt -> {} + case TypeAnnotation.TypeParameterTarget tpt -> {} + } + } + } + } + for (var attr : com.findAttributes(Attributes.stackMapTable())) { for (var smfi : attr.entries()) { stackMapFrames.put(smfi.target(), smfi); @@ -290,8 +329,8 @@ public class FrameTracker { case String _ -> pushStack(Type.STRING_TYPE); case ClassDesc desc -> pushStack(desc); case DynamicConstantDesc dynamicConstantDesc -> pushStack(dynamicConstantDesc.constantType()); - case MethodHandleDesc methodHandleDesc -> pushStack(Type.METHOD_HANDLE_TYPE); - case MethodTypeDesc methodTypeDesc -> pushStack(Type.METHOD_TYPE); + case MethodHandleDesc _ -> pushStack(Type.METHOD_HANDLE_TYPE); + case MethodTypeDesc _ -> pushStack(Type.METHOD_TYPE); } } case ConvertInstruction c -> decStack(c.fromType().slotSize()).pushStack(c.toType().upperBound()); @@ -442,65 +481,38 @@ public class FrameTracker { } case PseudoInstruction p -> { switch(p){ - case CharacterRange cr -> { - } - case ExceptionCatch ec -> { - } - case LabelTarget lt -> { - } case LineNumber ln -> current_line_number = ln; - case LocalVariable lv -> { - } - case LocalVariableType lvt -> { - } + case CharacterRange cr -> {} + case ExceptionCatch ec -> {} + case LabelTarget lt -> {} + case LocalVariable lv -> {} + case LocalVariableType lvt -> {} default -> {} } } case RuntimeInvisibleTypeAnnotationsAttribute _ -> {} - case RuntimeVisibleTypeAnnotationsAttribute tas -> { - for(var ta : tas.annotations()){ - switch(ta.targetInfo()){ - case TypeAnnotation.CatchTarget ct -> { - } - case TypeAnnotation.EmptyTarget et -> { - } - case TypeAnnotation.FormalParameterTarget fpt -> { - } - case TypeAnnotation.LocalVarTarget lvt -> { - for(var el : lvt.table()){ - el.endLabel(); - } - } - case TypeAnnotation.OffsetTarget ot -> { - } - case TypeAnnotation.SupertypeTarget stt -> { - } - case TypeAnnotation.ThrowsTarget tt -> { - } - case TypeAnnotation.TypeArgumentTarget tat -> { - } - case TypeAnnotation.TypeParameterBoundTarget tpbt -> { - } - case TypeAnnotation.TypeParameterTarget tpt -> { - } - } - } - } + case RuntimeVisibleTypeAnnotationsAttribute _ -> {} case CustomAttribute _ -> {} case StackMapTableAttribute _ -> {} } } public void encounterLabel(Label l) { + if(annotationStartMap.get(l) instanceof ArrayList list) + activeAnnotations.addAll(list); + + if(annotationEndMap.get(l) instanceof ArrayList list) + activeAnnotations.removeAll(list); + var tmp = stackMapFrames.get(l); if (tmp != null) { stack.clear(); locals.clear(); for( var sl : tmp.stack()) - pushStack(Type.verificationType(sl)); + pushStack(Type.verificationType(sl, this)); for( var sl : tmp.locals()) - locals.add(Type.verificationType(sl)); + locals.add(Type.verificationType(sl, this)); } } } diff --git a/src/generators/loadtime/SavedStateTracker.java b/src/generators/loadtime/SavedStateTracker.java index 5c39db7..682526f 100644 --- a/src/generators/loadtime/SavedStateTracker.java +++ b/src/generators/loadtime/SavedStateTracker.java @@ -17,7 +17,7 @@ public class SavedStateTracker { } - private String get_name(StateMachineBuilder smb, ClassDesc desc){ + private String get_name(StateMachineBuilder smb, ClassDesc desc){ var value = smb.lstate.stream() // find unused state .filter(v -> saved.stream().noneMatch(s -> s.name().equals(v.name()))) .filter(v -> v.cd().equals(desc)).findFirst(); @@ -28,7 +28,7 @@ public class SavedStateTracker { return name; } - public SavedState save_stack(StateMachineBuilder smb, CodeBuilder cob, ClassDesc desc){ + public SavedState save_stack(StateMachineBuilder smb, CodeBuilder cob, ClassDesc desc){ var name = get_name(smb, desc); if(TypeKind.from(desc).slotSize()==2){ @@ -42,7 +42,7 @@ public class SavedStateTracker { return s; } - public SavedState save_local(StateMachineBuilder smb, CodeBuilder cob, ClassDesc desc, int slot){ + public SavedState save_local(StateMachineBuilder smb, CodeBuilder cob, ClassDesc desc, int slot){ var name = get_name(smb, desc); cob.aload(0).loadLocal(TypeKind.from(desc), slot).putfield(smb.CD_this, name, desc); @@ -52,7 +52,7 @@ public class SavedStateTracker { return s; } - public SavedStateTracker restore(StateMachineBuilder smb, CodeBuilder cob, SavedState s){ + public SavedStateTracker restore(StateMachineBuilder smb, CodeBuilder cob, SavedState s){ if(!saved.remove(s))throw new IllegalStateException(); switch(s){ case LocalState(var name, var desc, int slot) -> @@ -63,21 +63,21 @@ public class SavedStateTracker { return this; } - public void restore_stack(StateMachineBuilder smb, CodeBuilder cob){ + public void restore_stack(StateMachineBuilder smb, CodeBuilder cob){ for(int i = saved.size()-1; i >= 0; i --){ if(saved.get(i) instanceof StackState) restore(smb, cob, saved.get(i)); } } - public void restore_locals(StateMachineBuilder smb, CodeBuilder cob){ + public void restore_locals(StateMachineBuilder smb, CodeBuilder cob){ for(int i = saved.size()-1; i >= 0; i --){ if(saved.get(i) instanceof StackState) restore(smb, cob, saved.get(i)); } } - public void restore_all(StateMachineBuilder smb, CodeBuilder cob) { + public void restore_all(StateMachineBuilder smb, CodeBuilder cob) { while(!saved.isEmpty()) restore(smb, cob, saved.getLast()); } diff --git a/src/generators/loadtime/SpecialMethodBuilder.java b/src/generators/loadtime/SpecialMethodBuilder.java new file mode 100644 index 0000000..533961d --- /dev/null +++ b/src/generators/loadtime/SpecialMethodBuilder.java @@ -0,0 +1,7 @@ +package generators.loadtime; + +import java.lang.classfile.CodeBuilder; + +public interface SpecialMethodBuilder> { + SpecialMethodHandler build(T smb, CodeBuilder cob, Frame frame, StateBuilder sb); +} diff --git a/src/generators/loadtime/SpecialMethodHandler.java b/src/generators/loadtime/SpecialMethodHandler.java index 737e1bd..0893588 100644 --- a/src/generators/loadtime/SpecialMethodHandler.java +++ b/src/generators/loadtime/SpecialMethodHandler.java @@ -2,12 +2,12 @@ package generators.loadtime; import java.lang.classfile.CodeBuilder; -public interface SpecialMethodHandler { +public interface SpecialMethodHandler { - void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame); + void build_prelude(T smb, CodeBuilder cob, Frame frame); default boolean removeCall() { return true; } - void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame); + void build_inline(T smb, CodeBuilder cob, Frame frame); ReplacementKind replacementKind(); } diff --git a/src/generators/loadtime/StateMachineBuilder.java b/src/generators/loadtime/StateMachineBuilder.java index f256ac4..28d243c 100644 --- a/src/generators/loadtime/StateMachineBuilder.java +++ b/src/generators/loadtime/StateMachineBuilder.java @@ -12,7 +12,7 @@ import java.lang.reflect.AccessFlag; import java.util.*; import java.util.stream.Collectors; -public abstract class StateMachineBuilder { +public abstract class StateMachineBuilder> { public final static String PARAM_PREFIX = "param_"; public final static String LOCAL_PREFIX = "local_"; public final static String STATE_NAME = "state"; @@ -31,17 +31,13 @@ public abstract class StateMachineBuilder { private final ArrayList frames; - protected final HashMap smmap = new HashMap<>(); + protected final HashMap> smmap = new HashMap<>(); record LState(String name, ClassDesc cd) { } - public interface SpecialMethodBuilder{ - SpecialMethodHandler build(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb); - } - public void params(int slot_start, ParamConsumer consumer){ int offset = 0; for (var param : params) { @@ -202,7 +198,7 @@ public abstract class StateMachineBuilder { public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob, int loc_param_off) { var stateBuilder = new StateBuilder(); - var handlers = new ArrayList(); + var handlers = new ArrayList>(); boolean ignore_next_pop = false; @@ -214,7 +210,7 @@ public abstract class StateMachineBuilder { if (wf.coe() instanceof InvokeInstruction is){ var handler = smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol())); if(handler != null) - handlers.add(handler.build(this, cob, stateBuilder)); + handlers.add(handler.build((T)this, cob, wf.frame(), stateBuilder)); } } @@ -230,13 +226,13 @@ public abstract class StateMachineBuilder { var h = smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol())); if(h!=null) { if(wf.frame.line()!=null)cob.with(wf.frame.line()); - handlers.get(i++).build_prelude(this, cob, wf.frame()); + handlers.get(i++).build_prelude((T)this, cob, wf.frame()); } } } } - SpecialMethodHandler currentHandler = null; + SpecialMethodHandler currentHandler = null; start_state.bind(cob); for (var wf : with_frames()) { @@ -250,7 +246,7 @@ public abstract class StateMachineBuilder { }else throw new RuntimeException("Expected Pop Instruction"); if (i.opcode() == Opcode.ARETURN){ if (currentHandler !=null && currentHandler.replacementKind() == ReplacementKind.ReplacingNextReturn){ - currentHandler.build_inline(this, cob, frame); + currentHandler.build_inline((T)this, cob, frame); currentHandler = null; continue; } @@ -261,9 +257,9 @@ public abstract class StateMachineBuilder { if(currentHandler!=null)throw new RuntimeException("Multiple method handlers at once not supported"); var handler = handlers.removeFirst(); if(!handler.removeCall()) cob.with(coe); - if(handler.replacementKind() == ReplacementKind.Immediate) handler.build_inline(this, cob, frame); + if(handler.replacementKind() == ReplacementKind.Immediate) handler.build_inline((T)this, cob, frame); else if(handler.replacementKind() == ReplacementKind.ImmediateReplacingPop) { - handler.build_inline(this, cob, frame); + handler.build_inline((T)this, cob, frame); ignore_next_pop = true; }else currentHandler = handler; diff --git a/src/generators/loadtime/future/Cancellation.java b/src/generators/loadtime/future/Cancellation.java new file mode 100644 index 0000000..4490415 --- /dev/null +++ b/src/generators/loadtime/future/Cancellation.java @@ -0,0 +1,15 @@ +package generators.loadtime.future; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE}) +public @interface Cancellation { + String value() default "cancel"; + Class param() default void.class; + Class ret() default void.class; + Class owner() default void.class; +} diff --git a/src/generators/loadtime/future/FutureSMBuilder.java b/src/generators/loadtime/future/FutureSMBuilder.java index ab11003..b27996f 100644 --- a/src/generators/loadtime/future/FutureSMBuilder.java +++ b/src/generators/loadtime/future/FutureSMBuilder.java @@ -5,12 +5,15 @@ import future.Waker; import generators.loadtime.*; import java.lang.classfile.*; +import java.lang.classfile.constantpool.MethodRefEntry; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; +import java.util.HashMap; import java.util.List; +import java.util.function.Consumer; -public class FutureSMBuilder extends StateMachineBuilder { +public class FutureSMBuilder extends StateMachineBuilder { public final static ClassDesc CD_Future = ClassDesc.ofDescriptor(Future.class.descriptorString()); public final static ClassDesc CD_Waker = ClassDesc.ofDescriptor(Waker.class.descriptorString()); @@ -23,21 +26,24 @@ public class FutureSMBuilder extends StateMachineBuilder { public final static String AWAITING_FIELD_NAME = "awaiting"; - static class AwaitHandler implements SpecialMethodHandler{ + private final HashMap> cancellation_behavior = new HashMap<>(); + + static class AwaitHandler implements SpecialMethodHandler{ final StateBuilder.State awaiting; final Label save_label; final Label resume_inline; - public AwaitHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) { + public AwaitHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) { awaiting = sb.create(cob); save_label = cob.newLabel(); resume_inline = cob.newLabel(); + smb.yielding_state(awaiting, frame); } public ReplacementKind replacementKind(){return ReplacementKind.Immediate;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.labelBinding(save_label); var sst = new SavedStateTracker(); frame.save_locals(smb, cob, sst,2); @@ -52,7 +58,7 @@ public class FutureSMBuilder extends StateMachineBuilder { } @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { // [... Future] var start = cob.newBoundLabel(); cob.dup().aload(1).invokeinterface(CD_Future, "poll", MTD_Object_Waker).dup().instanceOf(CD_Pending); @@ -74,21 +80,23 @@ public class FutureSMBuilder extends StateMachineBuilder { } } - static class YieldHandler implements SpecialMethodHandler { + static class YieldHandler implements SpecialMethodHandler { final StateBuilder.State resume; final Label save_ret; final Label end; - public YieldHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) { + public YieldHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) { resume = sb.create(cob); save_ret = cob.newLabel(); end = cob.newLabel(); + + smb.yielding_state(resume, frame); } public ReplacementKind replacementKind(){return ReplacementKind.Immediate;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.labelBinding(save_ret); var saved = frame.save(smb, cob, 2, 0); @@ -102,21 +110,21 @@ public class FutureSMBuilder extends StateMachineBuilder { } @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.goto_(save_ret); cob.labelBinding(end); } } - static class WakerHandler implements SpecialMethodHandler{ + static class WakerHandler implements SpecialMethodHandler{ - protected WakerHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) {} + protected WakerHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) {} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} + public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {} @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.aload(1); } @@ -126,37 +134,102 @@ public class FutureSMBuilder extends StateMachineBuilder { } } - static class RetHandler implements SpecialMethodHandler{ - protected RetHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) {} + static class RetHandler implements SpecialMethodHandler{ + protected RetHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) {} public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} + public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {} @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()); smb.nonresumable_return(cob, TypeKind.REFERENCE); } } - static class RetVoidHandler implements SpecialMethodHandler{ - protected RetVoidHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) {} + static class RetVoidHandler implements SpecialMethodHandler{ + protected RetVoidHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) {} public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { } @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) { cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()).aconst_null(); smb.nonresumable_return(cob, TypeKind.REFERENCE); } } + private String fromAnnValue(AnnotationValue value){ + switch(value){ + case AnnotationValue.OfAnnotation ofAnnotation -> { + } + case AnnotationValue.OfArray ofArray -> { + } + case AnnotationValue.OfClass ofClass -> { + } + case AnnotationValue.OfConstant ofConstant -> { + switch(ofConstant){ + case AnnotationValue.OfBoolean ofBoolean -> { + } + case AnnotationValue.OfByte ofByte -> { + } + case AnnotationValue.OfChar ofChar -> { + } + case AnnotationValue.OfDouble ofDouble -> { + } + case AnnotationValue.OfFloat ofFloat -> { + } + case AnnotationValue.OfInt ofInt -> { + } + case AnnotationValue.OfLong ofLong -> { + } + case AnnotationValue.OfShort ofShort -> { + } + case AnnotationValue.OfString ofString -> { + return ofString.stringValue(); + } + } + } + case AnnotationValue.OfEnum ofEnum -> { + } + } + throw new RuntimeException(); + } + + private void yielding_state(StateBuilder.State state, Frame frame){ + if(frame.local_annotations().length==0)return; + cancellation_behavior.put(state.id(), cob -> { + for(var ann : frame.local_annotations()){ + if(ann.annotation().classSymbol().descriptorString().equals(Cancellation.class.descriptorString())){ + ClassDesc owner = frame.locals()[ann.slot()].sym(); + ClassDesc param = frame.locals()[ann.slot()].sym(); + String name = "cancel"; + for(var el : ann.annotation().elements()){ + switch(el.name().stringValue()){ + case "value" -> name = fromAnnValue(el.value()); + case "owner" -> {} + case "param" -> {} + case "ret" -> {} + } + el.name().equalsString("value"); + } + var mre = cob.constantPool().methodRefEntry(owner, name, MethodTypeDesc.of(ConstantDescs.CD_void)); + cob.trying(tcob -> { + tcob.aconst_null() +// .aload(ann.slot()) + .invokevirtual(mre); + }, cb -> cb.catchingAll(ccob -> ccob.pop())); + } + } + }); + } + @Override protected void buildStateMachineMethod(ClassBuilder clb){ clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Future))); @@ -165,11 +238,37 @@ public class FutureSMBuilder extends StateMachineBuilder { buildStateMachineMethodCode(clb, cob, 2); })); 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_(); + + this.synchronized_start(cob); + cob.trying(tcob -> { + tcob.aload(0).getfield(CD_this, STATE_NAME, ConstantDescs.CD_int).istore(1); + tcob.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int); + + tcob.aload(0).getfield(CD_this, AWAITING_FIELD_NAME, CD_Future).ifThen(Opcode.IFNONNULL, boc -> { + boc.aload(0).getfield(CD_this, AWAITING_FIELD_NAME, CD_Future) + .invokeinterface(CD_Future, "cancel", MethodTypeDesc.of(ConstantDescs.CD_void)) + .aload(0).aconst_null().putfield(CD_this, AWAITING_FIELD_NAME, CD_Future); + }); + + for(var cb : cancellation_behavior.entrySet()){ + var end = tcob.newLabel(); + tcob.iload(1); + tcob.loadConstant(cb.getKey()); + tcob.if_icmpne(end); + cb.getValue().accept(tcob); + tcob.labelBinding(end); + } + + this.synchronized_exit(tcob); + tcob.return_(); + }, cb -> { + cb.catchingAll(ccob -> { + ccob.pop(); + this.synchronized_exit(ccob); + ccob.return_(); + }); }); - cob.pop().return_(); + })); clb.withField(AWAITING_FIELD_NAME, CD_Future, ClassFile.ACC_PRIVATE); } diff --git a/src/generators/loadtime/gen/GenSMBuilder.java b/src/generators/loadtime/gen/GenSMBuilder.java index dd600f5..a2747cb 100644 --- a/src/generators/loadtime/gen/GenSMBuilder.java +++ b/src/generators/loadtime/gen/GenSMBuilder.java @@ -9,7 +9,7 @@ import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.util.List; -public class GenSMBuilder extends StateMachineBuilder { +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()); @@ -20,13 +20,13 @@ public class GenSMBuilder extends StateMachineBuilder { 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 { + static class YieldHandler implements SpecialMethodHandler { final StateBuilder.State yielded; final Label save; final Label resume; final boolean is_void; - public YieldHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb, boolean is_void) { + public YieldHandler(GenSMBuilder smb, CodeBuilder cob, StateBuilder sb, boolean is_void) { yielded = sb.create(cob); save = cob.newLabel(); resume = cob.newLabel(); @@ -36,7 +36,7 @@ public class GenSMBuilder extends StateMachineBuilder { public ReplacementKind replacementKind(){return ReplacementKind.ImmediateReplacingPop;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_prelude(GenSMBuilder smb, CodeBuilder cob, Frame frame) { cob.labelBinding(save); @@ -53,7 +53,7 @@ public class GenSMBuilder extends StateMachineBuilder { } @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(GenSMBuilder smb, CodeBuilder cob, Frame frame) { if(is_void)cob.aconst_null(); yielded.setState(smb, cob); @@ -68,20 +68,20 @@ public class GenSMBuilder extends StateMachineBuilder { } } - static class RetHandler implements SpecialMethodHandler { + static class RetHandler implements SpecialMethodHandler { final boolean is_void; - public RetHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb, boolean is_void) { + public RetHandler(GenSMBuilder smb, CodeBuilder cob, StateBuilder sb, boolean is_void) { this.is_void = is_void; } public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} @Override - public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} + public void build_prelude(GenSMBuilder smb, CodeBuilder cob, Frame frame) {} @Override - public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { + public void build_inline(GenSMBuilder smb, CodeBuilder cob, Frame frame) { if(is_void)cob.aconst_null(); cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()) @@ -95,10 +95,10 @@ public class GenSMBuilder extends StateMachineBuilder { public GenSMBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com) { super(src_clm, src_mem, src_com, "Gen"); - smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen_Obj),(smb, cob, sb) -> new YieldHandler(smb, cob, sb, false)); - smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen),(smb, cob, sb) -> new YieldHandler(smb, cob, sb,true)); - smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen_Obj),(smb, cob, sb) -> new RetHandler(smb, cob, sb,false)); - smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen),(smb, cob, sb) -> new RetHandler(smb, cob, sb, true)); + smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen_Obj),(smb, cob, frame, sb) -> new YieldHandler(smb, cob, sb, false)); + smmap.put(new SpecialMethod(CD_Gen, "yield", MTD_Gen),(smb, cob, frame, sb) -> new YieldHandler(smb, cob, sb,true)); + smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen_Obj),(smb, cob, frame, sb) -> new RetHandler(smb, cob, sb,false)); + smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen),(smb, cob, frame, sb) -> new RetHandler(smb, cob, sb, true)); } @Override