mirror of
https://github.com/ParkerTenBroeck/coroutines.git
synced 2026-06-06 21:00:35 -04:00
started work on adding custom behavior on local variables during future cancellation
This commit is contained in:
parent
3a2c5290f3
commit
6329257702
10 changed files with 258 additions and 138 deletions
|
|
@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
7
src/generators/loadtime/SpecialMethodBuilder.java
Normal file
7
src/generators/loadtime/SpecialMethodBuilder.java
Normal 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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
15
src/generators/loadtime/future/Cancellation.java
Normal file
15
src/generators/loadtime/future/Cancellation.java
Normal 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue