mirror of
https://github.com/ParkerTenBroeck/coroutines.git
synced 2026-06-07 05:08:51 -04:00
added stack tracking
This commit is contained in:
parent
61b1ca1c12
commit
21412f4670
5 changed files with 473 additions and 86 deletions
|
|
@ -70,21 +70,34 @@ public class Examples {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static class Delay implements Future<String>{
|
public static class Delay implements Future<String>{
|
||||||
|
private final static Timer timer;
|
||||||
private final int delay;
|
static{
|
||||||
|
timer = new Timer(true);
|
||||||
|
}
|
||||||
|
private int delay;
|
||||||
private boolean ready;
|
private boolean ready;
|
||||||
public Delay(int ms){
|
public Delay(int ms){
|
||||||
|
if(ms<0)throw new IllegalArgumentException("Delay cannot be negative");
|
||||||
delay = ms;
|
delay = ms;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Object poll(Waker waker) {
|
public synchronized Object poll(Waker waker) {
|
||||||
new Timer().schedule(new TimerTask() {
|
if(delay==0){
|
||||||
|
ready=true;
|
||||||
|
delay=-1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(delay != -1){
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ready = true;
|
ready = true;
|
||||||
waker.wake();
|
waker.wake();
|
||||||
}
|
}
|
||||||
}, delay);
|
}, delay);
|
||||||
|
delay = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(ready)return null;
|
if(ready)return null;
|
||||||
return Pending.INSTANCE;
|
return Pending.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
@ -96,9 +109,22 @@ public class Examples {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<String> awaitTest(int number){
|
public Future<String> awaitTest(int number){
|
||||||
|
try(var m = new Meow()){
|
||||||
var result = awaitTest2(number).await();
|
var result = awaitTest2(number).await();
|
||||||
return Future.ret("Result: " + result);
|
return Future.ret("Result: " + result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Meow implements AutoCloseable{
|
||||||
|
{
|
||||||
|
System.out.println("OPen");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
System.out.println("Close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public static Gen<Double, Void> test(double[] nyas){
|
// public static Gen<Double, Void> test(double[] nyas){
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ public interface Future<R> {
|
||||||
throw new RuntimeException("NO!");
|
throw new RuntimeException("NO!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void cancel(){}
|
||||||
|
|
||||||
static <R> Future<R> ret(R r){
|
static <R> Future<R> ret(R r){
|
||||||
throw new RuntimeException("NO!");
|
throw new RuntimeException("NO!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,12 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
var smb = new FutureSMBuilder(src_clm, src_mem, com);
|
var smb = new FutureSMBuilder(src_clm, src_mem, com);
|
||||||
try{
|
try{
|
||||||
add(smb.CD_this.displayName(), smb.buildStateMachine());
|
add(smb.CD_this.displayName(), smb.buildStateMachine());
|
||||||
}catch (Exception ignore){
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
|
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
|
||||||
mb.with(com);
|
mb.with(com);
|
||||||
});
|
});
|
||||||
|
return smb;
|
||||||
}
|
}
|
||||||
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
|
cb.withMethod(src_mem.methodName(), src_mem.methodType(), src_mem.flags().flagsMask(), mb -> {
|
||||||
mb.withCode(smb::buildSourceMethodShim);
|
mb.withCode(smb::buildSourceMethodShim);
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,235 @@
|
||||||
package generator.runtime;
|
package generator.runtime;
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
|
import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute;
|
||||||
|
import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
|
||||||
import java.lang.classfile.attribute.StackMapFrameInfo;
|
import java.lang.classfile.attribute.StackMapFrameInfo;
|
||||||
|
import java.lang.classfile.attribute.StackMapTableAttribute;
|
||||||
|
import java.lang.classfile.instruction.*;
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo.TOP;
|
import static generator.runtime.StateMachineBuilder.LOCAL_PREFIX;
|
||||||
|
import static java.lang.constant.ConstantDescs.*;
|
||||||
|
|
||||||
public class LocalTracker {
|
public class LocalTracker {
|
||||||
|
|
||||||
record LocalStore(String name, ClassDesc cd) {
|
record LocalStore(String name, ClassDesc cd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<Integer, ClassDesc> parameter_map = new HashMap<>();
|
private static final int ITEM_TOP = 0,
|
||||||
|
ITEM_INTEGER = 1,
|
||||||
|
ITEM_FLOAT = 2,
|
||||||
|
ITEM_DOUBLE = 3,
|
||||||
|
ITEM_LONG = 4,
|
||||||
|
ITEM_NULL = 5,
|
||||||
|
ITEM_UNINITIALIZED_THIS = 6,
|
||||||
|
ITEM_OBJECT = 7,
|
||||||
|
ITEM_UNINITIALIZED = 8,
|
||||||
|
ITEM_BOOLEAN = 9,
|
||||||
|
ITEM_BYTE = 10,
|
||||||
|
ITEM_SHORT = 11,
|
||||||
|
ITEM_CHAR = 12,
|
||||||
|
ITEM_LONG_2ND = 13,
|
||||||
|
ITEM_DOUBLE_2ND = 14;
|
||||||
|
|
||||||
HashMap<Integer, TypeKind> localVarTypes = new HashMap<>();
|
private static 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),
|
||||||
|
FLOAT_TYPE = simpleType(ITEM_FLOAT),
|
||||||
|
LONG_TYPE = simpleType(ITEM_LONG),
|
||||||
|
LONG2_TYPE = simpleType(ITEM_LONG_2ND),
|
||||||
|
DOUBLE_TYPE = simpleType(ITEM_DOUBLE),
|
||||||
|
BOOLEAN_TYPE = simpleType(ITEM_BOOLEAN),
|
||||||
|
BYTE_TYPE = simpleType(ITEM_BYTE),
|
||||||
|
CHAR_TYPE = simpleType(ITEM_CHAR),
|
||||||
|
SHORT_TYPE = simpleType(ITEM_SHORT),
|
||||||
|
DOUBLE2_TYPE = simpleType(ITEM_DOUBLE_2ND),
|
||||||
|
UNITIALIZED_THIS_TYPE = simpleType(ITEM_UNINITIALIZED_THIS);
|
||||||
|
|
||||||
|
//frequently used types to reduce footprint
|
||||||
|
static final Type OBJECT_TYPE = referenceType(CD_Object),
|
||||||
|
THROWABLE_TYPE = referenceType(CD_Throwable),
|
||||||
|
INT_ARRAY_TYPE = referenceType(CD_int.arrayType()),
|
||||||
|
BOOLEAN_ARRAY_TYPE = referenceType(CD_boolean.arrayType()),
|
||||||
|
BYTE_ARRAY_TYPE = referenceType(CD_byte.arrayType()),
|
||||||
|
CHAR_ARRAY_TYPE = referenceType(CD_char.arrayType()),
|
||||||
|
SHORT_ARRAY_TYPE = referenceType(CD_short.arrayType()),
|
||||||
|
LONG_ARRAY_TYPE = referenceType(CD_long.arrayType()),
|
||||||
|
DOUBLE_ARRAY_TYPE = referenceType(CD_double.arrayType()),
|
||||||
|
FLOAT_ARRAY_TYPE = referenceType(CD_float.arrayType()),
|
||||||
|
STRING_TYPE = referenceType(CD_String),
|
||||||
|
CLASS_TYPE = referenceType(CD_Class),
|
||||||
|
METHOD_HANDLE_TYPE = referenceType(CD_MethodHandle),
|
||||||
|
METHOD_TYPE = referenceType(CD_MethodType);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return switch(tag){
|
||||||
|
case ITEM_TOP -> "TOP";
|
||||||
|
case ITEM_INTEGER -> "int";
|
||||||
|
case ITEM_FLOAT -> "float";
|
||||||
|
case ITEM_DOUBLE -> "double";
|
||||||
|
case ITEM_LONG -> "long";
|
||||||
|
case ITEM_NULL -> sym==null?"null":"null("+sym.displayName()+")";
|
||||||
|
case ITEM_UNINITIALIZED_THIS -> sym==null?"uninitialized(this)":"uninitialized(this "+sym.displayName()+")";
|
||||||
|
case ITEM_OBJECT -> "Object("+sym.displayName()+")";
|
||||||
|
case ITEM_UNINITIALIZED -> sym==null?"uninitialized()":"uninitialized("+sym.displayName()+")";
|
||||||
|
case ITEM_BOOLEAN -> "boolean";
|
||||||
|
case ITEM_BYTE -> "byte";
|
||||||
|
case ITEM_SHORT -> "short";
|
||||||
|
case ITEM_CHAR -> "char";
|
||||||
|
case ITEM_LONG_2ND -> "float2";
|
||||||
|
case ITEM_DOUBLE_2ND -> "double2";
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + tag);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type simpleType(int tag) {
|
||||||
|
return new Type(tag, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type referenceType(ClassDesc desc) {
|
||||||
|
return new Type(ITEM_OBJECT, desc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type uninitializedType(ClassDesc sym) {
|
||||||
|
return new Type(ITEM_UNINITIALIZED, sym, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override //mandatory override to avoid use of method reference during JDK bootstrap
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof Type t) && t.tag == tag && t.bci == bci && Objects.equals(sym, t.sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isCategory2_2nd() {
|
||||||
|
return this == DOUBLE2_TYPE || this == LONG2_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isReference() {
|
||||||
|
return tag == ITEM_OBJECT || this == NULL_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isObject() {
|
||||||
|
return tag == ITEM_OBJECT && sym.isClassOrInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isArray() {
|
||||||
|
return tag == ITEM_OBJECT && sym.isArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Type verificationType(StackMapFrameInfo.VerificationTypeInfo v){
|
||||||
|
return switch (v){
|
||||||
|
case StackMapFrameInfo.ObjectVerificationTypeInfo o -> Type.referenceType(o.classSymbol());
|
||||||
|
case StackMapFrameInfo.SimpleVerificationTypeInfo s -> Type.simpleType(s.tag());
|
||||||
|
case StackMapFrameInfo.UninitializedVerificationTypeInfo u -> {
|
||||||
|
//Type.simpleType(u.tag());
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassDesc toCD(){
|
||||||
|
return switch (tag) {
|
||||||
|
case ITEM_BOOLEAN -> CD_boolean;
|
||||||
|
case ITEM_BYTE -> CD_byte;
|
||||||
|
case ITEM_CHAR -> CD_char;
|
||||||
|
case ITEM_SHORT -> CD_short;
|
||||||
|
case ITEM_INTEGER -> CD_int;
|
||||||
|
case ITEM_LONG -> CD_long;
|
||||||
|
case ITEM_FLOAT -> CD_float;
|
||||||
|
case ITEM_DOUBLE -> CD_double;
|
||||||
|
case ITEM_OBJECT -> sym;
|
||||||
|
default -> throw new RuntimeException();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Type toArray() {
|
||||||
|
return switch (tag) {
|
||||||
|
case ITEM_BOOLEAN -> BOOLEAN_ARRAY_TYPE;
|
||||||
|
case ITEM_BYTE -> BYTE_ARRAY_TYPE;
|
||||||
|
case ITEM_CHAR -> CHAR_ARRAY_TYPE;
|
||||||
|
case ITEM_SHORT -> SHORT_ARRAY_TYPE;
|
||||||
|
case ITEM_INTEGER -> INT_ARRAY_TYPE;
|
||||||
|
case ITEM_LONG -> LONG_ARRAY_TYPE;
|
||||||
|
case ITEM_FLOAT -> FLOAT_ARRAY_TYPE;
|
||||||
|
case ITEM_DOUBLE -> DOUBLE_ARRAY_TYPE;
|
||||||
|
case ITEM_OBJECT -> Type.referenceType(sym.arrayType());
|
||||||
|
default -> OBJECT_TYPE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Type getComponent() {
|
||||||
|
if (isArray()) {
|
||||||
|
var comp = sym.componentType();
|
||||||
|
if (comp.isPrimitive()) {
|
||||||
|
return switch (comp.descriptorString().charAt(0)) {
|
||||||
|
case 'Z' -> Type.BOOLEAN_TYPE;
|
||||||
|
case 'B' -> Type.BYTE_TYPE;
|
||||||
|
case 'C' -> Type.CHAR_TYPE;
|
||||||
|
case 'S' -> Type.SHORT_TYPE;
|
||||||
|
case 'I' -> Type.INTEGER_TYPE;
|
||||||
|
case 'J' -> Type.LONG_TYPE;
|
||||||
|
case 'F' -> Type.FLOAT_TYPE;
|
||||||
|
case 'D' -> Type.DOUBLE_TYPE;
|
||||||
|
default -> Type.TOP_TYPE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Type.referenceType(comp);
|
||||||
|
}
|
||||||
|
return Type.TOP_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final ArrayList<Type> stack = new ArrayList<>();
|
||||||
|
final ArrayList<Type> locals = new ArrayList<>();
|
||||||
|
// HashMap<Integer, TypeKind> localVarTypes = new HashMap<>();
|
||||||
|
// StackMapFrameInfo currentFrame;
|
||||||
|
|
||||||
|
HashMap<Integer, ClassDesc> parameter_map = new HashMap<>();
|
||||||
HashMap<Label, StackMapFrameInfo> stackMapFrames = new HashMap<>();
|
HashMap<Label, StackMapFrameInfo> stackMapFrames = new HashMap<>();
|
||||||
StackMapFrameInfo currentFrame;
|
|
||||||
ArrayList<LocalStore> localStore = new ArrayList<>();
|
ArrayList<LocalStore> localStore = new ArrayList<>();
|
||||||
|
|
||||||
final int local_param_off;
|
final int local_param_off;
|
||||||
|
final StateMachineBuilder smb;
|
||||||
|
|
||||||
|
|
||||||
LocalTracker(StateMachineBuilder smb, CodeModel com, int local_param_off) {
|
LocalTracker(StateMachineBuilder smb, CodeModel com, int local_param_off) {
|
||||||
this.local_param_off = local_param_off;
|
this.local_param_off = local_param_off;
|
||||||
|
this.smb = smb;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (var param : smb.params) {
|
for (var param : smb.params) {
|
||||||
parameter_map.put(offset, param);
|
parameter_map.put(offset, param);
|
||||||
|
|
||||||
|
if(param == CD_long){
|
||||||
|
setLocal2(offset, Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||||
|
}else if(param == CD_double){
|
||||||
|
setLocal2(offset, Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
}else if(!param.isPrimitive()){
|
||||||
|
setLocal(offset, Type.referenceType(param));
|
||||||
|
}else if(param == CD_float){
|
||||||
|
setLocal(offset, Type.FLOAT_TYPE);
|
||||||
|
}else if(param == CD_char){
|
||||||
|
setLocal(offset, Type.CHAR_TYPE);
|
||||||
|
}else if(param == CD_boolean){
|
||||||
|
setLocal(offset, Type.BOOLEAN_TYPE);
|
||||||
|
}else if(param == CD_byte){
|
||||||
|
setLocal(offset, Type.BYTE_TYPE);
|
||||||
|
}else if(param == CD_short){
|
||||||
|
setLocal(offset, Type.SHORT_TYPE);
|
||||||
|
}else{
|
||||||
|
setLocal(offset, Type.INTEGER_TYPE);
|
||||||
|
}
|
||||||
offset += TypeKind.from(param).slotSize();
|
offset += TypeKind.from(param).slotSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,13 +239,215 @@ public class LocalTracker {
|
||||||
var locals = new ArrayList<>(smfi.locals());
|
var locals = new ArrayList<>(smfi.locals());
|
||||||
for (int i = 0; i < smb.params.length; i++)
|
for (int i = 0; i < smb.params.length; i++)
|
||||||
locals.removeFirst();
|
locals.removeFirst();
|
||||||
// locals.addFirst(StackMapFrameInfo.ObjectVerificationTypeInfo.of(smb.CD_this));
|
|
||||||
entries.add(StackMapFrameInfo.of(smfi.target(), locals, smfi.stack()));
|
entries.add(StackMapFrameInfo.of(smfi.target(), locals, smfi.stack()));
|
||||||
stackMapFrames.put(smfi.target(), entries.getLast());
|
stackMapFrames.put(smfi.target(), entries.getLast());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalTracker pushStack(ClassDesc desc) {
|
||||||
|
if (desc == CD_long) return pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||||
|
return desc == CD_void ? this
|
||||||
|
: pushStack(
|
||||||
|
desc.isPrimitive()
|
||||||
|
? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE)
|
||||||
|
: Type.referenceType(desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalTracker pushStack(Type type) {
|
||||||
|
stack.add(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalTracker pushStack(Type type1, Type type2) {
|
||||||
|
stack.add(type1);
|
||||||
|
stack.add(type2);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type popStack() {
|
||||||
|
return stack.removeLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalTracker decStack(int size) {
|
||||||
|
for(int i = 0; i < size; i ++)stack.removeLast();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLocal(int slot, Type type){
|
||||||
|
while(locals.size()<=slot)locals.add(null);
|
||||||
|
|
||||||
|
var old = locals.get(slot);
|
||||||
|
if(old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE)
|
||||||
|
locals.set(slot+1, Type.TOP_TYPE);
|
||||||
|
if(old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE)
|
||||||
|
locals.set(slot-1, Type.TOP_TYPE);
|
||||||
|
locals.set(slot, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLocal2(int slot, Type type1, Type type2){
|
||||||
|
while(locals.size()<=slot+1)locals.add(null);
|
||||||
|
|
||||||
|
var old = locals.get(slot+1);
|
||||||
|
if(old == Type.DOUBLE_TYPE || old == Type.LONG_TYPE)
|
||||||
|
locals.set(slot+2, Type.TOP_TYPE);
|
||||||
|
old = locals.get(slot);
|
||||||
|
if(old == Type.DOUBLE2_TYPE || old == Type.LONG2_TYPE)
|
||||||
|
locals.set(slot-1, Type.TOP_TYPE);
|
||||||
|
|
||||||
|
locals.set(slot, type1);
|
||||||
|
locals.set(slot+1, type2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encounter(CodeElement ce){
|
||||||
|
switch(ce){
|
||||||
|
case Label l -> encounterLabel(l);
|
||||||
|
case Instruction ins -> {
|
||||||
|
switch (ins) {
|
||||||
|
case ArrayLoadInstruction al -> {
|
||||||
|
popStack();
|
||||||
|
var arr = popStack();
|
||||||
|
pushStack(arr.toCD().componentType());
|
||||||
|
}
|
||||||
|
case ArrayStoreInstruction as -> decStack(1 + as.typeKind().slotSize());
|
||||||
|
case BranchInstruction b when b.opcode() == Opcode.GOTO || b.opcode() == Opcode.GOTO_W -> {}
|
||||||
|
case BranchInstruction b -> popStack();
|
||||||
|
case ConstantInstruction c when ins.opcode() == Opcode.ACONST_NULL -> pushStack(Type.NULL_TYPE);
|
||||||
|
case ConstantInstruction c -> pushStack(c.typeKind().upperBound());
|
||||||
|
case ConvertInstruction c -> decStack(c.fromType().slotSize()).pushStack(c.toType().upperBound());
|
||||||
|
case FieldInstruction f -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
case IncrementInstruction i -> {}
|
||||||
|
case InvokeDynamicInstruction i -> {
|
||||||
|
for(var param : i.typeSymbol().parameterArray())
|
||||||
|
decStack(TypeKind.from(param).slotSize());
|
||||||
|
pushStack(i.typeSymbol().returnType());
|
||||||
|
}
|
||||||
|
case InvokeInstruction i when i.opcode() == Opcode.INVOKESTATIC -> {
|
||||||
|
for(var param : i.typeSymbol().parameterArray())
|
||||||
|
decStack(TypeKind.from(param).slotSize());
|
||||||
|
pushStack(i.typeSymbol().returnType());
|
||||||
|
}
|
||||||
|
case InvokeInstruction i when i.opcode() == Opcode.INVOKESPECIAL && i.name().equalsString(INIT_NAME) -> {
|
||||||
|
for(var param : i.typeSymbol().parameterArray())
|
||||||
|
decStack(TypeKind.from(param).slotSize());
|
||||||
|
var ty = popStack();
|
||||||
|
}
|
||||||
|
case InvokeInstruction i -> {
|
||||||
|
for(var param : i.typeSymbol().parameterArray())
|
||||||
|
decStack(TypeKind.from(param).slotSize());
|
||||||
|
popStack();
|
||||||
|
pushStack(i.typeSymbol().returnType());
|
||||||
|
}
|
||||||
|
case LoadInstruction l when locals.size()<=l.slot()||locals.get(l.slot())==null ->
|
||||||
|
pushStack(l.typeKind().upperBound());
|
||||||
|
case LoadInstruction l ->
|
||||||
|
pushStack(locals.get(l.slot()).toCD());
|
||||||
|
case LookupSwitchInstruction ls -> popStack();
|
||||||
|
case MonitorInstruction m -> popStack();
|
||||||
|
case NewMultiArrayInstruction nma -> decStack(nma.dimensions()).pushStack(nma.arrayType().asSymbol());
|
||||||
|
case NewObjectInstruction no -> pushStack(no.className().asSymbol());
|
||||||
|
case NewPrimitiveArrayInstruction npa -> decStack(1).pushStack(npa.typeKind().upperBound().arrayType());
|
||||||
|
case NewReferenceArrayInstruction nra -> decStack(1).pushStack(nra.componentType().asSymbol());
|
||||||
|
case NopInstruction n -> {}
|
||||||
|
|
||||||
|
case OperatorInstruction o -> {
|
||||||
|
switch(o.opcode()){
|
||||||
|
case IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IOR, IXOR, IAND ->
|
||||||
|
decStack(2).pushStack(Type.INTEGER_TYPE);
|
||||||
|
case INEG, ARRAYLENGTH, INSTANCEOF ->
|
||||||
|
decStack(1).pushStack(Type.INTEGER_TYPE);
|
||||||
|
case LADD, LSUB, LMUL, LDIV, LREM, LAND, LOR, LXOR ->
|
||||||
|
decStack(4).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
case LNEG ->
|
||||||
|
decStack(2).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
case LSHL, LSHR, LUSHR ->
|
||||||
|
decStack(3).pushStack(Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
case FADD, FSUB, FMUL, FDIV, FREM ->
|
||||||
|
decStack(2).pushStack(Type.FLOAT_TYPE);
|
||||||
|
case FNEG ->
|
||||||
|
decStack(1).pushStack(Type.FLOAT_TYPE);
|
||||||
|
case DADD, DSUB, DMUL, DDIV, DREM ->
|
||||||
|
decStack(4).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||||
|
case DNEG ->
|
||||||
|
decStack(2).pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||||
|
default -> throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case StackInstruction s -> {
|
||||||
|
Type type1, type2, type3, type4;
|
||||||
|
switch(s.opcode()){
|
||||||
|
case POP ->
|
||||||
|
decStack(1);
|
||||||
|
case POP2 ->
|
||||||
|
decStack(2);
|
||||||
|
case DUP ->
|
||||||
|
pushStack(type1 = popStack()).pushStack(type1);
|
||||||
|
case DUP_X1 -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
pushStack(type1).pushStack(type2).pushStack(type1);
|
||||||
|
}
|
||||||
|
case DUP_X2 -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
type3 = popStack();
|
||||||
|
pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1);
|
||||||
|
}
|
||||||
|
case DUP2 -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
pushStack(type2).pushStack(type1).pushStack(type2).pushStack(type1);
|
||||||
|
}
|
||||||
|
case DUP2_X1 -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
type3 = popStack();
|
||||||
|
pushStack(type2).pushStack(type1).pushStack(type3).pushStack(type2).pushStack(type1);
|
||||||
|
}
|
||||||
|
case DUP2_X2 -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
type3 = popStack();
|
||||||
|
type4 = popStack();
|
||||||
|
pushStack(type2).pushStack(type1).pushStack(type4).pushStack(type3).pushStack(type2).pushStack(type1);
|
||||||
|
}
|
||||||
|
case SWAP -> {
|
||||||
|
type1 = popStack();
|
||||||
|
type2 = popStack();
|
||||||
|
pushStack(type1);
|
||||||
|
pushStack(type2);
|
||||||
|
}
|
||||||
|
default -> throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case ReturnInstruction r when r.typeKind()==TypeKind.VOID -> {}
|
||||||
|
case ReturnInstruction r -> decStack(r.typeKind().slotSize());
|
||||||
|
|
||||||
|
case StoreInstruction s when s.typeKind() == TypeKind.DOUBLE -> decStack(2).setLocal2(s.slot(), Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
|
||||||
|
case StoreInstruction s when s.typeKind() == TypeKind.LONG -> decStack(2).setLocal2(s.slot(), Type.LONG_TYPE, Type.LONG2_TYPE);
|
||||||
|
case StoreInstruction s -> setLocal(s.slot(), popStack());
|
||||||
|
|
||||||
|
case TableSwitchInstruction ts -> popStack();
|
||||||
|
case ThrowInstruction t -> popStack();
|
||||||
|
case TypeCheckInstruction tc -> {}
|
||||||
|
case DiscontinuedInstruction d -> throw new IllegalStateException(d.toString());
|
||||||
|
default -> throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PseudoInstruction _ -> {}
|
||||||
|
case RuntimeInvisibleTypeAnnotationsAttribute _ -> {}
|
||||||
|
case RuntimeVisibleTypeAnnotationsAttribute _ -> {}
|
||||||
|
case CustomAttribute<?> _ -> {}
|
||||||
|
case StackMapTableAttribute _ -> {}
|
||||||
|
}
|
||||||
|
if(ce instanceof Instruction)
|
||||||
|
System.out.println("loc: " + locals + " stack: " + stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Tries its best to reuse old saved locals field slots, only reuses if types exactly match
|
//Tries its best to reuse old saved locals field slots, only reuses if types exactly match
|
||||||
public void savingLocals(ClassDesc cd, CodeBuilder cob, Runnable run) {
|
public void savingLocals(ClassDesc cd, CodeBuilder cob, Runnable run) {
|
||||||
|
|
@ -51,19 +455,9 @@ public class LocalTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
var saved = new ArrayList<Saved>();
|
var saved = new ArrayList<Saved>();
|
||||||
var lls = new ArrayList<>(localStore);
|
|
||||||
currentLocals((slot, tk, desc) -> {
|
currentLocals((slot, tk, desc) -> {
|
||||||
String name = null;
|
String name = LOCAL_PREFIX + localStore.size();
|
||||||
for (int i = 0; i < lls.size(); i++)
|
|
||||||
if (lls.get(i).cd.equals(desc)) {
|
|
||||||
name = lls.get(i).name;
|
|
||||||
lls.remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (name == null) {
|
|
||||||
name = StateMachineBuilder.LOCAL_PREFIX + localStore.size();
|
|
||||||
localStore.add(new LocalStore(name, desc));
|
localStore.add(new LocalStore(name, desc));
|
||||||
}
|
|
||||||
saved.add(new Saved(slot, name, desc));
|
saved.add(new Saved(slot, name, desc));
|
||||||
cob.aload(0).loadLocal(tk, slot).putfield(cd, name, desc);
|
cob.aload(0).loadLocal(tk, slot).putfield(cd, name, desc);
|
||||||
});
|
});
|
||||||
|
|
@ -83,8 +477,12 @@ public class LocalTracker {
|
||||||
public void encounterLabel(Label l) {
|
public void encounterLabel(Label l) {
|
||||||
var tmp = stackMapFrames.get(l);
|
var tmp = stackMapFrames.get(l);
|
||||||
if (tmp != null) {
|
if (tmp != null) {
|
||||||
localVarTypes.clear();
|
stack.clear();
|
||||||
currentFrame = tmp;
|
locals.clear();
|
||||||
|
for( var sl : tmp.stack())
|
||||||
|
pushStack(Type.verificationType(sl));
|
||||||
|
for( var local : tmp.locals())
|
||||||
|
locals.add(Type.verificationType(local));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,53 +490,17 @@ public class LocalTracker {
|
||||||
return parameter_map.get(slot);
|
return parameter_map.get(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void trackLocal(int slot, TypeKind typeKind) {
|
|
||||||
localVarTypes.put(slot, typeKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface LocalConsumer {
|
public interface LocalConsumer {
|
||||||
void consume(int slot, TypeKind tk, ClassDesc desc);
|
void consume(int slot, TypeKind tk, ClassDesc desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void currentLocals(LocalConsumer consumer) {
|
public void currentLocals(LocalConsumer consumer) {
|
||||||
var slot = local_param_off;
|
int slot = 0;
|
||||||
if (currentFrame != null) {
|
for (var entry : locals) {
|
||||||
for (var kind : currentFrame.locals()) {
|
slot++;
|
||||||
switch (kind) {
|
if (slot <= local_param_off) continue;
|
||||||
case StackMapFrameInfo.ObjectVerificationTypeInfo o -> {
|
if(entry.isCategory2_2nd())continue;
|
||||||
if (slot != 0)
|
consumer.consume(slot - smb.paramSlotOff + local_param_off - 1, TypeKind.from(entry.toCD()), entry.toCD());
|
||||||
consumer.consume(slot, o.className().typeKind(), o.classSymbol());
|
|
||||||
slot += 1;
|
|
||||||
}
|
|
||||||
case StackMapFrameInfo.SimpleVerificationTypeInfo ti -> {
|
|
||||||
if (kind == TOP) {
|
|
||||||
slot += 1;
|
|
||||||
if (localVarTypes.get(slot - 1) instanceof TypeKind tk) {
|
|
||||||
ClassDesc cd = tk.upperBound();
|
|
||||||
consumer.consume(slot - 1, tk, cd);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var type = switch (ti) {
|
|
||||||
case INTEGER -> TypeKind.INT;
|
|
||||||
case FLOAT -> TypeKind.FLOAT;
|
|
||||||
case DOUBLE -> TypeKind.DOUBLE;
|
|
||||||
case LONG -> TypeKind.LONG;
|
|
||||||
case NULL -> TypeKind.REFERENCE;
|
|
||||||
default -> throw new IllegalStateException();
|
|
||||||
};
|
|
||||||
consumer.consume(slot, type, type.upperBound());
|
|
||||||
slot += 1;
|
|
||||||
}
|
|
||||||
case StackMapFrameInfo.UninitializedVerificationTypeInfo _ -> throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
for (var entry : localVarTypes.entrySet()) {
|
|
||||||
if (entry.getKey() < slot) continue;
|
|
||||||
ClassDesc cd = entry.getValue().upperBound();
|
|
||||||
consumer.consume(entry.getKey(), TypeKind.from(cd), cd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,10 +121,6 @@ public abstract class StateMachineBuilder {
|
||||||
ctb -> ctb.catchingAll(
|
ctb -> ctb.catchingAll(
|
||||||
blc ->
|
blc ->
|
||||||
blc.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int)
|
blc.aload(0).loadConstant(-1).putfield(CD_this, STATE_NAME, ConstantDescs.CD_int)
|
||||||
.new_(ClassDesc.ofDescriptor(RuntimeException.class.descriptorString()))
|
|
||||||
.dup_x1()
|
|
||||||
.swap()
|
|
||||||
.invokespecial(ClassDesc.ofDescriptor(RuntimeException.class.descriptorString()), ConstantDescs.INIT_NAME, MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_Throwable))
|
|
||||||
.athrow()
|
.athrow()
|
||||||
)
|
)
|
||||||
).aconst_null().areturn();
|
).aconst_null().areturn();
|
||||||
|
|
@ -133,6 +129,8 @@ 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) {
|
||||||
boolean ignore_next_pop = false;
|
boolean ignore_next_pop = false;
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Begin");
|
||||||
this.lt = new LocalTracker(this, src_com, loc_param_off);
|
this.lt = new LocalTracker(this, src_com, loc_param_off);
|
||||||
|
|
||||||
var invalidState = cob.newLabel();
|
var invalidState = cob.newLabel();
|
||||||
|
|
@ -172,9 +170,6 @@ public abstract class StateMachineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (coe instanceof Label l) {
|
|
||||||
lt.encounterLabel(l);
|
|
||||||
}
|
|
||||||
if (coe instanceof InvokeInstruction is){
|
if (coe instanceof InvokeInstruction is){
|
||||||
if(smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol())) != null){
|
if(smmap.get(new SpecialMethod(is.owner().asSymbol(), is.name().stringValue(), is.typeSymbol())) != null){
|
||||||
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");
|
||||||
|
|
@ -189,7 +184,9 @@ public abstract class StateMachineBuilder {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(coe instanceof LocalVariable lv) System.out.println(lv);
|
|
||||||
|
lt.encounter(coe);
|
||||||
|
|
||||||
|
|
||||||
switch (coe) {
|
switch (coe) {
|
||||||
// locals which were once function parameters can be ignored
|
// locals which were once function parameters can be ignored
|
||||||
|
|
@ -216,10 +213,8 @@ public abstract class StateMachineBuilder {
|
||||||
cob.aload(0).dup_x2().pop().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
cob.aload(0).dup_x2().pop().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
||||||
case StoreInstruction ls when ls.slot() < paramSlotOff ->
|
case StoreInstruction ls when ls.slot() < paramSlotOff ->
|
||||||
cob.aload(0).swap().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
cob.aload(0).swap().putfield(CD_this, PARAM_PREFIX + ls.slot(), lt.paramType(ls.slot()));
|
||||||
case StoreInstruction ls -> {
|
case StoreInstruction ls ->
|
||||||
lt.trackLocal(ls.slot() - paramSlotOff + loc_param_off, ls.typeKind());
|
|
||||||
cob.storeLocal(ls.typeKind(), ls.slot() - paramSlotOff + loc_param_off);
|
cob.storeLocal(ls.typeKind(), ls.slot() - paramSlotOff + loc_param_off);
|
||||||
}
|
|
||||||
|
|
||||||
default -> cob.with(coe);
|
default -> cob.with(coe);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue