diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d44ea18..cd43bc6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,6 +20,14 @@ tasks.withType { options.compilerArgs.add("--enable-preview") } +tasks.register("basic"){ + javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) + jvmArgs("--enable-preview") + group = "Demos" + mainClass = "basic.Main" + classpath = sourceSets["main"].runtimeClasspath +} + tasks.register("lexer"){ javaLauncher.set(javaToolchains.launcherFor(java.toolchain)) jvmArgs("--enable-preview") diff --git a/app/src/main/java/basic/Futures.java b/app/src/main/java/basic/Futures.java new file mode 100644 index 0000000..f6e8491 --- /dev/null +++ b/app/src/main/java/basic/Futures.java @@ -0,0 +1,7 @@ +package basic; + +import com.parkertenbroeck.future.Future; +import com.parkertenbroeck.future.Waker; + +public class Futures { +} diff --git a/app/src/main/java/basic/Gens.java b/app/src/main/java/basic/Gens.java new file mode 100644 index 0000000..ae960db --- /dev/null +++ b/app/src/main/java/basic/Gens.java @@ -0,0 +1,17 @@ +package basic; + +import com.parkertenbroeck.generator.Gen; + +public class Gens { + public static Gen 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); + } + } +} diff --git a/app/src/main/java/basic/Main.java b/app/src/main/java/basic/Main.java new file mode 100644 index 0000000..1b4bd16 --- /dev/null +++ b/app/src/main/java/basic/Main.java @@ -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); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/sockets/Sockets.java b/app/src/main/java/sockets/Sockets.java index 8fe0af7..4e08a63 100644 --- a/app/src/main/java/sockets/Sockets.java +++ b/app/src/main/java/sockets/Sockets.java @@ -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; diff --git a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/FrameTracker.java b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/FrameTracker.java index a79a13b..ead6041 100644 --- a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/FrameTracker.java +++ b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/FrameTracker.java @@ -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(); } } diff --git a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/SavedStateTracker.java b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/SavedStateTracker.java index ecf61b7..12965e9 100644 --- a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/SavedStateTracker.java +++ b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/SavedStateTracker.java @@ -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; diff --git a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/StateMachineBuilder.java b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/StateMachineBuilder.java index 1eef78c..3f1a706 100644 --- a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/StateMachineBuilder.java +++ b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/StateMachineBuilder.java @@ -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> { public final static String PARAM_PREFIX = "param_"; public final static String LOCAL_PREFIX = "local_"; @@ -33,6 +35,8 @@ public abstract class StateMachineBuilder> { protected final HashMap> smmap = new HashMap<>(); + public record ParameterVariableAnnotation(Annotation annotation, String param, ClassDesc desc){} + protected final List parameterVariableAnnotations = new ArrayList<>(); record LState(String name, ClassDesc cd) { @@ -63,6 +67,7 @@ public abstract class StateMachineBuilder> { .replace("/", "___") .replace(";", "____") .replace("[", "_____") + .replace(".", "______") ) .collect(Collectors.joining("$")); innerClassName = method_name + "______" + param_cnd; @@ -73,6 +78,25 @@ public abstract class StateMachineBuilder> { this.MTD_init = MethodTypeDesc.of(ConstantDescs.CD_void, params); this.paramSlotOff = Arrays.stream(params).mapToInt(p -> TypeKind.from(p).slotSize()).sum(); + + ArrayList> 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); } diff --git a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/Cancellation.java b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/Cancellation.java index 991d75c..97ef3b4 100644 --- a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/Cancellation.java +++ b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/Cancellation.java @@ -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"; } diff --git a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/FutureSMBuilder.java b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/FutureSMBuilder.java index 7b9c535..1cdc2b0 100644 --- a/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/FutureSMBuilder.java +++ b/lib/src/main/java/com/parkertenbroeck/bcsm/loadtime/future/FutureSMBuilder.java @@ -183,58 +183,9 @@ public class FutureSMBuilder extends StateMachineBuilder { ArrayList> 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(); - 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()); - } - } - - 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){ - 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())); - }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(); - }, cb -> cb.catchingAll(ccob -> { - ccob.aload(2).ifThenElse(Opcode.IFNONNULL, bcob -> { - bcob.aload(2).swap(); - addSuppressed(bcob); - }, bcob -> { - bcob.astore(2); - }); - })); - }); + field_cancellation_behavior.add(make_canceler(param.name(), param.desc(), methodFromCancellationAnnotation(ann.annotation(), owner))); } } cancellation_behavior.put(state.id(), cob -> { @@ -242,6 +193,50 @@ public class FutureSMBuilder extends StateMachineBuilder { }); } + private Method methodFromCancellationAnnotation(Annotation annotation, ClassDesc owner){ + String name = "cancel"; + for(var el : annotation.elements()){ + if (el.name().stringValue().equals("value")) { + name = annotationStringValue(el.value()); + } + } + + try{ + Class clazz = getClass().getClassLoader().loadClass(owner.descriptorString().replace("/", ".").replace(";", "").substring(1)); + var method = findMethod(clazz, name); + if(method==null) + throw new RuntimeException("Cannot find method '"+name+"' for class " + clazz); + + return method; + }catch (Exception e){ + throw new RuntimeException(e); + } + } + + private Consumer 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(); + addSuppressed(bcob); + }, bcob -> { + bcob.astore(2); + }); + })); + }; + } + private static Method findMethod(Class owner, String name){ try{ return owner.getDeclaredMethod(name); @@ -274,8 +269,13 @@ public class FutureSMBuilder extends StateMachineBuilder { 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 { 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 -> {