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 async_runtime.net.Socket;
import future.Future; import future.Future;
import future.Waker; import future.Waker;
import generators.loadtime.future.Cancellation;
import java.io.IOException; 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.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -74,7 +71,7 @@ public class AsyncExamples {
public static Future<Void, IOException> echo(Socket socket){ public static Future<Void, IOException> echo(Socket socket){
try(socket){ try(socket){
@Test var buffer = ByteBuffer.allocate(4096*16*3); @Cancellation var buffer = ByteBuffer.allocate(4096*16*3);
while(true){ while(true){
var read = socket.read(buffer).await(); var read = socket.read(buffer).await();
buffer.clear().limit(read); buffer.clear().limit(read);
@ -88,7 +85,7 @@ public class AsyncExamples {
public static Future<Void, IOException> echoForever(String message){ public static Future<Void, IOException> echoForever(String message){
byte[] msg_bytes = message.getBytes(StandardCharsets.UTF_8); 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()); var buffer = ByteBuffer.allocate(message.length());
while(true){ while(true){
buffer.limit(message.length()).put(msg_bytes).position(0); buffer.limit(message.length()).put(msg_bytes).position(0);
@ -107,15 +104,4 @@ public class AsyncExamples {
} }
return Future.ret(null); 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.lang.classfile.instruction.LineNumber;
import java.util.Arrays; 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 @Override
public String toString() { 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){ 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.attribute.StackMapTableAttribute;
import java.lang.classfile.instruction.*; import java.lang.classfile.instruction.*;
import java.lang.constant.*; import java.lang.constant.*;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import static java.lang.constant.ConstantDescs.*; import static java.lang.constant.ConstantDescs.*;
@ -38,16 +35,20 @@ public class FrameTracker {
var frames = new ArrayList<Frame>(); var frames = new ArrayList<Frame>();
for(var coe : src_com){ for(var coe : src_com){
if(coe instanceof Instruction) { if(coe instanceof Instruction) {
frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, ft.current_line_number)); frames.add(new Frame(ft.locals(), ft.stack(), ft.bci, ft.current_line_number, ft.local_annotations()));
System.out.println(frames.getLast() + " " + coe); System.out.println(frames.getLast());
} }
ft.encounter(coe); 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; return frames;
} }
private LocalVariableAnnotation[] local_annotations() {
return this.activeAnnotations.toArray(LocalVariableAnnotation[]::new);
}
public Type[] locals() { public Type[] locals() {
return locals.toArray(Type[]::new); return locals.toArray(Type[]::new);
} }
@ -57,7 +58,6 @@ public class FrameTracker {
public record Type(int tag, ClassDesc sym, int bci) { public record Type(int tag, ClassDesc sym, int bci) {
//singleton types
static final Type TOP_TYPE = simpleType(ITEM_TOP), static final Type TOP_TYPE = simpleType(ITEM_TOP),
NULL_TYPE = simpleType(ITEM_NULL), NULL_TYPE = simpleType(ITEM_NULL),
INTEGER_TYPE = simpleType(ITEM_INTEGER), 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){ return switch (v){
case StackMapFrameInfo.ObjectVerificationTypeInfo o -> Type.referenceType(o.classSymbol()); case StackMapFrameInfo.ObjectVerificationTypeInfo o ->
case StackMapFrameInfo.SimpleVerificationTypeInfo s -> Type.simpleType(s.tag()); Type.referenceType(o.classSymbol());
case StackMapFrameInfo.UninitializedVerificationTypeInfo u -> { case StackMapFrameInfo.SimpleVerificationTypeInfo s ->
// Type.uninitializedType(null, u.newTarget()); Type.simpleType(s.tag());
throw new RuntimeException(); case StackMapFrameInfo.UninitializedVerificationTypeInfo u ->
} Type.uninitializedType(null, t.bciMap.get(u.newTarget()));
}; };
} }
@ -169,7 +169,12 @@ public class FrameTracker {
LineNumber current_line_number = null; LineNumber current_line_number = null;
int bci = 0; int bci = 0;
HashMap<Label, StackMapFrameInfo> stackMapFrames = new HashMap<>(); 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) { FrameTracker(StateMachineBuilder smb, CodeModel com) {
@ -199,6 +204,40 @@ public class FrameTracker {
offset += TypeKind.from(param).slotSize(); 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 attr : com.findAttributes(Attributes.stackMapTable())) {
for (var smfi : attr.entries()) { for (var smfi : attr.entries()) {
stackMapFrames.put(smfi.target(), smfi); stackMapFrames.put(smfi.target(), smfi);
@ -290,8 +329,8 @@ public class FrameTracker {
case String _ -> pushStack(Type.STRING_TYPE); case String _ -> pushStack(Type.STRING_TYPE);
case ClassDesc desc -> pushStack(desc); case ClassDesc desc -> pushStack(desc);
case DynamicConstantDesc dynamicConstantDesc -> pushStack(dynamicConstantDesc.constantType()); case DynamicConstantDesc dynamicConstantDesc -> pushStack(dynamicConstantDesc.constantType());
case MethodHandleDesc methodHandleDesc -> pushStack(Type.METHOD_HANDLE_TYPE); case MethodHandleDesc _ -> pushStack(Type.METHOD_HANDLE_TYPE);
case MethodTypeDesc methodTypeDesc -> pushStack(Type.METHOD_TYPE); case MethodTypeDesc _ -> pushStack(Type.METHOD_TYPE);
} }
} }
case ConvertInstruction c -> decStack(c.fromType().slotSize()).pushStack(c.toType().upperBound()); case ConvertInstruction c -> decStack(c.fromType().slotSize()).pushStack(c.toType().upperBound());
@ -442,65 +481,38 @@ public class FrameTracker {
} }
case PseudoInstruction p -> { case PseudoInstruction p -> {
switch(p){ switch(p){
case CharacterRange cr -> {
}
case ExceptionCatch ec -> {
}
case LabelTarget lt -> {
}
case LineNumber ln -> current_line_number = ln; case LineNumber ln -> current_line_number = ln;
case LocalVariable lv -> { case CharacterRange cr -> {}
} case ExceptionCatch ec -> {}
case LocalVariableType lvt -> { case LabelTarget lt -> {}
} case LocalVariable lv -> {}
case LocalVariableType lvt -> {}
default -> {} default -> {}
} }
} }
case RuntimeInvisibleTypeAnnotationsAttribute _ -> {} case RuntimeInvisibleTypeAnnotationsAttribute _ -> {}
case RuntimeVisibleTypeAnnotationsAttribute tas -> { case RuntimeVisibleTypeAnnotationsAttribute _ -> {}
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 CustomAttribute<?> _ -> {} case CustomAttribute<?> _ -> {}
case StackMapTableAttribute _ -> {} case StackMapTableAttribute _ -> {}
} }
} }
public void encounterLabel(Label l) { 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); var tmp = stackMapFrames.get(l);
if (tmp != null) { if (tmp != null) {
stack.clear(); stack.clear();
locals.clear(); locals.clear();
for( var sl : tmp.stack()) for( var sl : tmp.stack())
pushStack(Type.verificationType(sl)); pushStack(Type.verificationType(sl, this));
for( var sl : tmp.locals()) 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 var value = smb.lstate.stream() // find unused state
.filter(v -> saved.stream().noneMatch(s -> s.name().equals(v.name()))) .filter(v -> saved.stream().noneMatch(s -> s.name().equals(v.name())))
.filter(v -> v.cd().equals(desc)).findFirst(); .filter(v -> v.cd().equals(desc)).findFirst();
@ -28,7 +28,7 @@ public class SavedStateTracker {
return name; 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); var name = get_name(smb, desc);
if(TypeKind.from(desc).slotSize()==2){ if(TypeKind.from(desc).slotSize()==2){
@ -42,7 +42,7 @@ public class SavedStateTracker {
return s; 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); var name = get_name(smb, desc);
cob.aload(0).loadLocal(TypeKind.from(desc), slot).putfield(smb.CD_this, name, desc); cob.aload(0).loadLocal(TypeKind.from(desc), slot).putfield(smb.CD_this, name, desc);
@ -52,7 +52,7 @@ public class SavedStateTracker {
return s; 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(); if(!saved.remove(s))throw new IllegalStateException();
switch(s){ switch(s){
case LocalState(var name, var desc, int slot) -> case LocalState(var name, var desc, int slot) ->
@ -63,21 +63,21 @@ public class SavedStateTracker {
return this; 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 --){ for(int i = saved.size()-1; i >= 0; i --){
if(saved.get(i) instanceof StackState) if(saved.get(i) instanceof StackState)
restore(smb, cob, saved.get(i)); 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 --){ for(int i = saved.size()-1; i >= 0; i --){
if(saved.get(i) instanceof StackState) if(saved.get(i) instanceof StackState)
restore(smb, cob, saved.get(i)); 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()) while(!saved.isEmpty())
restore(smb, cob, saved.getLast()); 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; 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() { default boolean removeCall() {
return true; return true;
} }
void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame); void build_inline(T smb, CodeBuilder cob, Frame frame);
ReplacementKind replacementKind(); ReplacementKind replacementKind();
} }

View file

@ -12,7 +12,7 @@ import java.lang.reflect.AccessFlag;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; 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 PARAM_PREFIX = "param_";
public final static String LOCAL_PREFIX = "local_"; public final static String LOCAL_PREFIX = "local_";
public final static String STATE_NAME = "state"; public final static String STATE_NAME = "state";
@ -31,17 +31,13 @@ public abstract class StateMachineBuilder {
private final ArrayList<Frame> frames; 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) { 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){ public void params(int slot_start, ParamConsumer consumer){
int offset = 0; int offset = 0;
for (var param : params) { for (var param : params) {
@ -202,7 +198,7 @@ public abstract class StateMachineBuilder {
public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob, int loc_param_off) { public void buildStateMachineCode(ClassBuilder clb, CodeBuilder cob, int loc_param_off) {
var stateBuilder = new StateBuilder(); var stateBuilder = new StateBuilder();
var handlers = new ArrayList<SpecialMethodHandler>(); var handlers = new ArrayList<SpecialMethodHandler<T>>();
boolean ignore_next_pop = false; boolean ignore_next_pop = false;
@ -214,7 +210,7 @@ public abstract class StateMachineBuilder {
if (wf.coe() instanceof InvokeInstruction is){ if (wf.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.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())); var h = smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol()));
if(h!=null) { if(h!=null) {
if(wf.frame.line()!=null)cob.with(wf.frame.line()); 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); start_state.bind(cob);
for (var wf : with_frames()) { for (var wf : with_frames()) {
@ -250,7 +246,7 @@ public abstract class StateMachineBuilder {
}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.replacementKind() == ReplacementKind.ReplacingNextReturn){ if (currentHandler !=null && currentHandler.replacementKind() == ReplacementKind.ReplacingNextReturn){
currentHandler.build_inline(this, cob, frame); currentHandler.build_inline((T)this, cob, frame);
currentHandler = null; currentHandler = null;
continue; continue;
} }
@ -261,9 +257,9 @@ public abstract 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.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) { else if(handler.replacementKind() == ReplacementKind.ImmediateReplacingPop) {
handler.build_inline(this, cob, frame); handler.build_inline((T)this, cob, frame);
ignore_next_pop = true; ignore_next_pop = true;
}else }else
currentHandler = handler; 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 generators.loadtime.*;
import java.lang.classfile.*; import java.lang.classfile.*;
import java.lang.classfile.constantpool.MethodRefEntry;
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.HashMap;
import java.util.List; 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_Future = ClassDesc.ofDescriptor(Future.class.descriptorString());
public final static ClassDesc CD_Waker = ClassDesc.ofDescriptor(Waker.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"; 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 StateBuilder.State awaiting;
final Label save_label; final Label save_label;
final Label resume_inline; 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); awaiting = sb.create(cob);
save_label = cob.newLabel(); save_label = cob.newLabel();
resume_inline = cob.newLabel(); resume_inline = cob.newLabel();
smb.yielding_state(awaiting, frame);
} }
public ReplacementKind replacementKind(){return ReplacementKind.Immediate;} public ReplacementKind replacementKind(){return ReplacementKind.Immediate;}
@Override @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); cob.labelBinding(save_label);
var sst = new SavedStateTracker(); var sst = new SavedStateTracker();
frame.save_locals(smb, cob, sst,2); frame.save_locals(smb, cob, sst,2);
@ -52,7 +58,7 @@ public class FutureSMBuilder extends StateMachineBuilder {
} }
@Override @Override
public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {
// [... Future] // [... Future]
var start = cob.newBoundLabel(); var start = cob.newBoundLabel();
cob.dup().aload(1).invokeinterface(CD_Future, "poll", MTD_Object_Waker).dup().instanceOf(CD_Pending); 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 StateBuilder.State resume;
final Label save_ret; final Label save_ret;
final Label end; 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); resume = sb.create(cob);
save_ret = cob.newLabel(); save_ret = cob.newLabel();
end = cob.newLabel(); end = cob.newLabel();
smb.yielding_state(resume, frame);
} }
public ReplacementKind replacementKind(){return ReplacementKind.Immediate;} public ReplacementKind replacementKind(){return ReplacementKind.Immediate;}
@Override @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); cob.labelBinding(save_ret);
var saved = frame.save(smb, cob, 2, 0); var saved = frame.save(smb, cob, 2, 0);
@ -102,21 +110,21 @@ public class FutureSMBuilder extends StateMachineBuilder {
} }
@Override @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.goto_(save_ret);
cob.labelBinding(end); 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 @Override
public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {}
@Override @Override
public void build_inline(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { public void build_inline(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {
cob.aload(1); cob.aload(1);
} }
@ -126,37 +134,102 @@ public class FutureSMBuilder extends StateMachineBuilder {
} }
} }
static class RetHandler implements SpecialMethodHandler{ static class RetHandler implements SpecialMethodHandler<FutureSMBuilder>{
protected RetHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) {} protected RetHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) {}
public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;}
@Override @Override
public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {}
@Override @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()); cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound());
smb.nonresumable_return(cob, TypeKind.REFERENCE); smb.nonresumable_return(cob, TypeKind.REFERENCE);
} }
} }
static class RetVoidHandler implements SpecialMethodHandler{ static class RetVoidHandler implements SpecialMethodHandler<FutureSMBuilder>{
protected RetVoidHandler(StateMachineBuilder smb, CodeBuilder cob, StateBuilder sb) {} protected RetVoidHandler(FutureSMBuilder smb, CodeBuilder cob, Frame frame, StateBuilder sb) {}
public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;}
@Override @Override
public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { public void build_prelude(FutureSMBuilder smb, CodeBuilder cob, Frame frame) {
} }
@Override @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(); cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()).aconst_null();
smb.nonresumable_return(cob, TypeKind.REFERENCE); 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 @Override
protected void buildStateMachineMethod(ClassBuilder clb){ protected void buildStateMachineMethod(ClassBuilder clb){
clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Future))); clb.withInterfaces(List.of(clb.constantPool().classEntry(CD_Future)));
@ -165,11 +238,37 @@ public class FutureSMBuilder extends StateMachineBuilder {
buildStateMachineMethodCode(clb, cob, 2); buildStateMachineMethodCode(clb, cob, 2);
})); }));
clb.withMethod("cancel", MethodTypeDesc.of(ConstantDescs.CD_void), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> { 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)) this.synchronized_start(cob);
.aload(0).aconst_null().putfield(CD_this, AWAITING_FIELD_NAME, CD_Future).return_(); 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); 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.lang.constant.MethodTypeDesc;
import java.util.List; 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_Gen = ClassDesc.ofDescriptor(Gen.class.descriptorString());
public final static ClassDesc CD_Res = ClassDesc.ofDescriptor(Gen.Res.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_Gen = MethodTypeDesc.of(CD_Gen);
public final static MethodTypeDesc MTD_Obj = MethodTypeDesc.of(ConstantDescs.CD_Object); 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 StateBuilder.State yielded;
final Label save; final Label save;
final Label resume; final Label resume;
final boolean is_void; 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); yielded = sb.create(cob);
save = cob.newLabel(); save = cob.newLabel();
resume = cob.newLabel(); resume = cob.newLabel();
@ -36,7 +36,7 @@ public class GenSMBuilder extends StateMachineBuilder {
public ReplacementKind replacementKind(){return ReplacementKind.ImmediateReplacingPop;} public ReplacementKind replacementKind(){return ReplacementKind.ImmediateReplacingPop;}
@Override @Override
public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) { public void build_prelude(GenSMBuilder smb, CodeBuilder cob, Frame frame) {
cob.labelBinding(save); cob.labelBinding(save);
@ -53,7 +53,7 @@ public class GenSMBuilder extends StateMachineBuilder {
} }
@Override @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(); if(is_void)cob.aconst_null();
yielded.setState(smb, cob); 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; 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; this.is_void = is_void;
} }
public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;} public ReplacementKind replacementKind(){return ReplacementKind.ReplacingNextReturn;}
@Override @Override
public void build_prelude(StateMachineBuilder smb, CodeBuilder cob, Frame frame) {} public void build_prelude(GenSMBuilder smb, CodeBuilder cob, Frame frame) {}
@Override @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(); if(is_void)cob.aconst_null();
cob.aload(0).loadConstant(-1).putfield(smb.CD_this, STATE_NAME, TypeKind.INT.upperBound()) 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) { public GenSMBuilder(ClassModel src_clm, MethodModel src_mem, CodeModel src_com) {
super(src_clm, src_mem, src_com, "Gen"); 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_Obj),(smb, cob, frame, 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, "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, sb) -> new RetHandler(smb, cob, sb,false)); 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, sb) -> new RetHandler(smb, cob, sb, true)); smmap.put(new SpecialMethod(CD_Gen, "ret", MTD_Gen),(smb, cob, frame, sb) -> new RetHandler(smb, cob, sb, true));
} }
@Override @Override