mirror of
https://github.com/ParkerTenBroeck/coroutines.git
synced 2026-06-07 05:08:51 -04:00
added support for parameter cancellation
This commit is contained in:
parent
f0bc740e82
commit
051d5142d1
10 changed files with 154 additions and 64 deletions
|
|
@ -20,6 +20,14 @@ tasks.withType<JavaCompile> {
|
|||
options.compilerArgs.add("--enable-preview")
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("basic"){
|
||||
javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
|
||||
jvmArgs("--enable-preview")
|
||||
group = "Demos"
|
||||
mainClass = "basic.Main"
|
||||
classpath = sourceSets["main"].runtimeClasspath
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("lexer"){
|
||||
javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
|
||||
jvmArgs("--enable-preview")
|
||||
|
|
|
|||
7
app/src/main/java/basic/Futures.java
Normal file
7
app/src/main/java/basic/Futures.java
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package basic;
|
||||
|
||||
import com.parkertenbroeck.future.Future;
|
||||
import com.parkertenbroeck.future.Waker;
|
||||
|
||||
public class Futures {
|
||||
}
|
||||
17
app/src/main/java/basic/Gens.java
Normal file
17
app/src/main/java/basic/Gens.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package basic;
|
||||
|
||||
import com.parkertenbroeck.generator.Gen;
|
||||
|
||||
public class Gens {
|
||||
public static Gen<Long, Void> primes(){
|
||||
long number = 1;
|
||||
Gen.yield(2L);
|
||||
outer: while(true){
|
||||
number += 2;
|
||||
for(long i=2; i <= Math.sqrt(number); i ++){
|
||||
if(number%i==0)continue outer;
|
||||
}
|
||||
Gen.yield(number);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
app/src/main/java/basic/Main.java
Normal file
20
app/src/main/java/basic/Main.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package basic;
|
||||
|
||||
import com.parkertenbroeck.bcsm.RT;
|
||||
import com.parkertenbroeck.bcsm.loadtime.StateMachineClassLoader;
|
||||
import com.parkertenbroeck.generator.Gen;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
RT.runWithStateMachines(StateMachineClassLoader.Config.builtin().write_classes("build/modified/generators/"), (Object) args);
|
||||
|
||||
primes();
|
||||
}
|
||||
|
||||
static void primes(){
|
||||
var gen = Gens.primes();
|
||||
while(gen.next() instanceof Gen.Yield(var tok)) {
|
||||
System.out.println(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.parkertenbroeck.async_runtime.io.net.ServerSocket;
|
|||
import com.parkertenbroeck.async_runtime.io.net.Socket;
|
||||
import com.parkertenbroeck.future.Future;
|
||||
import com.parkertenbroeck.bcsm.loadtime.future.Cancellation;
|
||||
import com.parkertenbroeck.future.Waker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.parkertenbroeck.bcsm.loadtime;
|
||||
|
||||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
|
||||
|
|
@ -8,6 +7,7 @@ import java.lang.classfile.attribute.StackMapFrameInfo;
|
|||
import java.lang.classfile.attribute.StackMapTableAttribute;
|
||||
import java.lang.classfile.instruction.*;
|
||||
import java.lang.constant.*;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.*;
|
||||
|
|
@ -180,24 +180,28 @@ public class FrameTracker {
|
|||
this.smb = smb;
|
||||
int offset = 0;
|
||||
|
||||
for (var param : smb.params) {
|
||||
if(param == CD_long){
|
||||
|
||||
|
||||
for (int i = 0; i < smb.params.length; i++) {
|
||||
var param = smb.params[i];
|
||||
|
||||
if (param == CD_long) {
|
||||
setLocal2(offset, Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
}else if(param == CD_double){
|
||||
} else if (param == CD_double) {
|
||||
setLocal2(offset, Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||
}else if(!param.isPrimitive()){
|
||||
} else if (!param.isPrimitive()) {
|
||||
setLocal(offset, Type.referenceType(param));
|
||||
}else if(param == CD_float){
|
||||
} else if (param == CD_float) {
|
||||
setLocal(offset, Type.FLOAT_TYPE);
|
||||
}else if(param == CD_char){
|
||||
} else if (param == CD_char) {
|
||||
setLocal(offset, Type.CHAR_TYPE);
|
||||
}else if(param == CD_boolean){
|
||||
} else if (param == CD_boolean) {
|
||||
setLocal(offset, Type.BOOLEAN_TYPE);
|
||||
}else if(param == CD_byte){
|
||||
} else if (param == CD_byte) {
|
||||
setLocal(offset, Type.BYTE_TYPE);
|
||||
}else if(param == CD_short){
|
||||
} else if (param == CD_short) {
|
||||
setLocal(offset, Type.SHORT_TYPE);
|
||||
}else{
|
||||
} else {
|
||||
setLocal(offset, Type.INTEGER_TYPE);
|
||||
}
|
||||
offset += TypeKind.from(param).slotSize();
|
||||
|
|
@ -412,6 +416,11 @@ public class FrameTracker {
|
|||
decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
case DNEG ->
|
||||
decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||
|
||||
case LCMP, DCMPL, DCMPG ->
|
||||
decStack(4).pushStack(Type.INTEGER_TYPE);
|
||||
case FCMPL, FCMPG ->
|
||||
decStack(2).pushStack(Type.INTEGER_TYPE);
|
||||
default -> throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public class SavedStateTracker {
|
|||
}
|
||||
|
||||
|
||||
public LocalState load_param(int slot) {
|
||||
public LocalState get_saved_local(int slot) {
|
||||
for(var saved : saved){
|
||||
if (saved instanceof LocalState(var name, var desc, int s) && s == slot) {
|
||||
return (LocalState) saved;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import java.lang.reflect.AccessFlag;
|
|||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.*;
|
||||
|
||||
public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
||||
public final static String PARAM_PREFIX = "param_";
|
||||
public final static String LOCAL_PREFIX = "local_";
|
||||
|
|
@ -33,6 +35,8 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
|||
|
||||
protected final HashMap<SpecialMethod, SpecialMethodBuilder<T>> smmap = new HashMap<>();
|
||||
|
||||
public record ParameterVariableAnnotation(Annotation annotation, String param, ClassDesc desc){}
|
||||
protected final List<ParameterVariableAnnotation> parameterVariableAnnotations = new ArrayList<>();
|
||||
|
||||
|
||||
record LState(String name, ClassDesc cd) {
|
||||
|
|
@ -63,6 +67,7 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
|||
.replace("/", "___")
|
||||
.replace(";", "____")
|
||||
.replace("[", "_____")
|
||||
.replace(".", "______")
|
||||
)
|
||||
.collect(Collectors.joining("$"));
|
||||
innerClassName = method_name + "______" + param_cnd;
|
||||
|
|
@ -73,6 +78,25 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
|||
this.MTD_init = MethodTypeDesc.of(ConstantDescs.CD_void, params);
|
||||
this.paramSlotOff = Arrays.stream(params).mapToInt(p -> TypeKind.from(p).slotSize()).sum();
|
||||
|
||||
|
||||
ArrayList<List<Annotation>> param_attrs;
|
||||
var param_ann = src_mem.findAttributes(Attributes.runtimeVisibleParameterAnnotations());
|
||||
if(!param_ann.isEmpty()) {
|
||||
param_attrs = new ArrayList<>(param_ann.getFirst().parameterAnnotations());
|
||||
if(!src_mem.flags().has(AccessFlag.STATIC)){
|
||||
param_attrs.addFirst(List.of());
|
||||
}
|
||||
}else
|
||||
param_attrs = new ArrayList<>(Collections.nCopies((src_mem.flags().has(AccessFlag.STATIC)?0:1)+src_mem.methodTypeSymbol().parameterList().size(), List.of()));
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
for(var attr : param_attrs.get(i))
|
||||
parameterVariableAnnotations.add(new ParameterVariableAnnotation(attr, StateMachineBuilder.PARAM_PREFIX + offset, param));
|
||||
offset += TypeKind.from(param).slotSize();
|
||||
}
|
||||
|
||||
frames = FrameTracker.frames(this, src_com);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.parkertenbroeck.bcsm.loadtime.future;
|
|||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE})
|
||||
@Target({ElementType.TYPE_USE, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER})
|
||||
public @interface Cancellation {
|
||||
String value() default "cancel";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,49 +183,49 @@ public class FutureSMBuilder extends StateMachineBuilder<FutureSMBuilder> {
|
|||
ArrayList<Consumer<CodeBuilder>> field_cancellation_behavior = new ArrayList<>();
|
||||
for(var ann : frame.local_annotations()){
|
||||
if(ann.annotation().classSymbol().descriptorString().equals(Cancellation.class.descriptorString())){
|
||||
var param = sst.load_param(ann.slot()-paramSlotOff+2);
|
||||
var param = sst.get_saved_local(ann.slot()-paramSlotOff+2);
|
||||
ClassDesc owner = frame.locals()[ann.slot()].sym();
|
||||
field_cancellation_behavior.add(make_canceler(param.name(), param.desc(), methodFromCancellationAnnotation(ann.annotation(), owner)));
|
||||
}
|
||||
}
|
||||
cancellation_behavior.put(state.id(), cob -> {
|
||||
for(var fcb : field_cancellation_behavior) fcb.accept(cob);
|
||||
});
|
||||
}
|
||||
|
||||
private Method methodFromCancellationAnnotation(Annotation annotation, ClassDesc owner){
|
||||
String name = "cancel";
|
||||
for(var el : ann.annotation().elements()){
|
||||
switch(el.name().stringValue()){
|
||||
case "value" -> name = annotationStringValue(el.value());
|
||||
case "owner" -> owner = annotationClassValue(el.value());
|
||||
for(var el : annotation.elements()){
|
||||
if (el.name().stringValue().equals("value")) {
|
||||
name = annotationStringValue(el.value());
|
||||
}
|
||||
}
|
||||
|
||||
if(!owner.isClassOrInterface()){
|
||||
throw new RuntimeException("Owner " + owner + " is not a class/interface cannot be used here");
|
||||
}
|
||||
boolean is_interface;
|
||||
TypeKind ret;
|
||||
try{
|
||||
Class<?> clazz = getClass().getClassLoader().loadClass(owner.descriptorString().replace("/", ".").replace(";", "").substring(1));
|
||||
|
||||
var method = findMethod(clazz, name);
|
||||
if(method==null){
|
||||
if(method==null)
|
||||
throw new RuntimeException("Cannot find method '"+name+"' for class " + clazz);
|
||||
}
|
||||
clazz = method.getDeclaringClass();
|
||||
owner = ClassDesc.ofDescriptor(clazz.descriptorString());
|
||||
is_interface = clazz.isInterface();
|
||||
ret = TypeKind.from(ClassDesc.ofDescriptor(method.getReturnType().descriptorString()));
|
||||
|
||||
return method;
|
||||
}catch (Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String final_name = name;
|
||||
ClassDesc final_owner = owner;
|
||||
|
||||
field_cancellation_behavior.add(cob -> {
|
||||
cob.trying(tcob -> {
|
||||
tcob.aload(0).getfield(CD_this, param.name(), param.desc());
|
||||
if(is_interface){
|
||||
tcob.invokeinterface(final_owner, final_name, MethodTypeDesc.of(ConstantDescs.CD_void));
|
||||
}else{
|
||||
tcob.invokevirtual(final_owner, final_name, MethodTypeDesc.of(ConstantDescs.CD_void));
|
||||
}
|
||||
if(ret.slotSize()==1)tcob.pop();
|
||||
if(ret.slotSize()==2)tcob.pop2();
|
||||
|
||||
private Consumer<CodeBuilder> make_canceler(String field_name, ClassDesc field_desc, Method method) {
|
||||
var owner = ClassDesc.ofDescriptor(method.getDeclaringClass().descriptorString());
|
||||
return cob -> {
|
||||
cob.trying(tcob -> {
|
||||
tcob.aload(0).getfield(CD_this, field_name, field_desc);
|
||||
if (method.getDeclaringClass().isInterface()) {
|
||||
tcob.invokeinterface(owner, method.getName(), MethodTypeDesc.of(ConstantDescs.CD_void));
|
||||
} else {
|
||||
tcob.invokevirtual(owner, method.getName(), MethodTypeDesc.of(ConstantDescs.CD_void));
|
||||
}
|
||||
var ret = TypeKind.from(method.getReturnType());
|
||||
if (ret.slotSize() == 1) tcob.pop();
|
||||
if (ret.slotSize() == 2) tcob.pop2();
|
||||
}, cb -> cb.catchingAll(ccob -> {
|
||||
ccob.aload(2).ifThenElse(Opcode.IFNONNULL, bcob -> {
|
||||
bcob.aload(2).swap();
|
||||
|
|
@ -234,12 +234,7 @@ public class FutureSMBuilder extends StateMachineBuilder<FutureSMBuilder> {
|
|||
bcob.astore(2);
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
cancellation_behavior.put(state.id(), cob -> {
|
||||
for(var fcb : field_cancellation_behavior) fcb.accept(cob);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private static Method findMethod(Class<?> owner, String name){
|
||||
|
|
@ -274,8 +269,13 @@ public class FutureSMBuilder extends StateMachineBuilder<FutureSMBuilder> {
|
|||
clb.withMethod("cancel", MethodTypeDesc.of(ConstantDescs.CD_void), ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
|
||||
|
||||
this.synchronized_start(cob);
|
||||
|
||||
cob.aload(0).getfield(CD_this, STATE_NAME, ConstantDescs.CD_int).istore(1);// state
|
||||
cob.aconst_null().astore(2);// exception
|
||||
cob.iload(1).loadConstant(-1).ifThen(Opcode.IF_ICMPEQ, bob -> {
|
||||
this.synchronized_exit(bob);
|
||||
bob.return_();
|
||||
});
|
||||
cob.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int);
|
||||
|
||||
cob.aload(0).getfield(CD_this, AWAITING_FIELD_NAME, CD_Future).ifThen(Opcode.IFNONNULL, boc -> {
|
||||
|
|
@ -310,6 +310,10 @@ public class FutureSMBuilder extends StateMachineBuilder<FutureSMBuilder> {
|
|||
cob.labelBinding(end);
|
||||
}
|
||||
|
||||
for(var la : this.parameterVariableAnnotations){
|
||||
make_canceler(la.param(), la.desc(), methodFromCancellationAnnotation(la.annotation(), la.desc())).accept(cob);
|
||||
}
|
||||
|
||||
|
||||
this.synchronized_exit(cob);
|
||||
cob.aload(2).ifThen(Opcode.IFNONNULL, bcob -> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue