started work on adding custom behavior on local variables during future cancellation

This commit is contained in:
ParkerTenBroeck 2025-05-03 20:24:01 -04:00
parent 3a2c5290f3
commit 6329257702
10 changed files with 258 additions and 138 deletions

View file

@ -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<Void, IOException> 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<Void, IOException> 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 {
}
}
}

View file

@ -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){

View file

@ -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<Frame>();
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<Label, StackMapFrameInfo> stackMapFrames = new HashMap<>();
HashMap<Label, Integer> bciMap = new HashMap<>();
public record LocalVariableAnnotation(Annotation annotation, int slot){}
final HashSet<LocalVariableAnnotation> activeAnnotations = new HashSet<>();
final HashMap<Label, List<LocalVariableAnnotation>> annotationStartMap = new HashMap<>();
final HashMap<Label, List<LocalVariableAnnotation>> 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<LocalVariableAnnotation> list)
activeAnnotations.addAll(list);
if(annotationEndMap.get(l) instanceof ArrayList<LocalVariableAnnotation> 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));
}
}
}

View file

@ -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());
}

View file

@ -0,0 +1,7 @@
package generators.loadtime;
import java.lang.classfile.CodeBuilder;
public interface SpecialMethodBuilder<T extends StateMachineBuilder<T>> {
SpecialMethodHandler<T> build(T smb, CodeBuilder cob, Frame frame, StateBuilder sb);
}

View file

@ -2,12 +2,12 @@ package generators.loadtime;
import java.lang.classfile.CodeBuilder;
public interface SpecialMethodHandler {
public interface SpecialMethodHandler<T extends StateMachineBuilder> {
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();
}

View file

@ -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<T extends StateMachineBuilder<T>> {
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<Frame> frames;
protected final HashMap<SpecialMethod, SpecialMethodBuilder> smmap = new HashMap<>();
protected final HashMap<SpecialMethod, SpecialMethodBuilder<T>> 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<SpecialMethodHandler>();
var handlers = new ArrayList<SpecialMethodHandler<T>>();
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<T> 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;

View file

@ -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;
}

View file

@ -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<FutureSMBuilder> {
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<Integer, Consumer<CodeBuilder>> cancellation_behavior = new HashMap<>();
static class AwaitHandler implements SpecialMethodHandler<FutureSMBuilder>{
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<FutureSMBuilder> {
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<FutureSMBuilder>{
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<FutureSMBuilder>{
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<FutureSMBuilder>{
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);
}

View file

@ -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<GenSMBuilder> {
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<GenSMBuilder> {
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<GenSMBuilder> {
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