diff --git a/lib/commons-bcel6-6.0-SNAPSHOT.jar b/lib/commons-bcel6-6.0-SNAPSHOT.jar index 463f5801..d1d1b607 100644 Binary files a/lib/commons-bcel6-6.0-SNAPSHOT.jar and b/lib/commons-bcel6-6.0-SNAPSHOT.jar differ diff --git a/notizen/stan/stackmaptable/.Notizen.md.swp b/notizen/stan/stackmaptable/.Notizen.md.swp deleted file mode 100644 index 61f9c4c6..00000000 Binary files a/notizen/stan/stackmaptable/.Notizen.md.swp and /dev/null differ diff --git a/notizen/stan/stackmaptable/IfElseStatement.java b/notizen/stan/stackmaptable/IfElseStatement.java new file mode 100644 index 00000000..f9748125 --- /dev/null +++ b/notizen/stan/stackmaptable/IfElseStatement.java @@ -0,0 +1,9 @@ +class IfElseStatement{ + Integer method(Boolean flag){ + if(flag){ + return 0; + }else{ + return 1; + } + } +} diff --git a/notizen/stan/stackmaptable/Notizen.md b/notizen/stan/stackmaptable/Notizen.md index 4050403e..6090e1f8 100644 --- a/notizen/stan/stackmaptable/Notizen.md +++ b/notizen/stan/stackmaptable/Notizen.md @@ -8,3 +8,8 @@ * https://stackoverflow.com/questions/24927993/what-kind-of-java-code-requires-stackmap-frames#24930521 * It is illegal to have code after an unconditional branch without a stack map frame being provided for it. +## BCEL Patch +https://issues.apache.org/jira/browse/BCEL-268 + +# Literatur +* Zu JVM allgemein: http://blog.jamesdbloom.com/JVMInternals.html diff --git a/notizen/stan/stackmaptable/StackMapTest4.java b/notizen/stan/stackmaptable/StackMapTest4.java new file mode 100644 index 00000000..6053ecfb --- /dev/null +++ b/notizen/stan/stackmaptable/StackMapTest4.java @@ -0,0 +1,17 @@ +class StackMapTest4{ + +int test = 1; + +void methode(){ +Integer i = 1; +while(System.out == null){ +i+=test; +} +Runnable r = ()->System.out.println(""); +System.out.println(i); +StackMapTest3 o = new StackMapTest3(); +while(i<0){ +i++; +} +} +} diff --git a/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java b/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java index a5e46931..f14f66c2 100644 --- a/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java +++ b/src/de/dhbwstuttgart/bytecode/DHBWInstructionFactory.java @@ -97,7 +97,7 @@ public class DHBWInstructionFactory extends InstructionFactory{ for(int i = 0; i entries = CodeHelper.getStackMapEntries(getInstructionList(), cp); + if(entries.size()==0)return null; + StackMapEntry[] entryArray = new StackMapEntry[entries.size()]; + for(int i = 0; i localVars = new HashMap<>(); + Stack stack = new Stack(); + + public StackItem getLocalType(int index) { + return localVars.get(index); + } + + public void set(int index, StackItem objectRef) { + localVars.put(index, objectRef); + } + + public void push(StackItem si){ + + } + + void pop(int i){ + + } + + public StackItem pop() { + // TODO Auto-generated method stub + return null; + } + + public Menge getStackTypes(ConstantPoolGen cp){ + Menge ret = new Menge(); + for(StackItem si : stack){ + ret.add(si.getType(cp)); + } + return ret; + } + + public Menge getLocalTypes(ConstantPoolGen cp) { + Menge ret = new Menge(); + //TODO + return ret; + } + + +} + +interface StackItem{ + public static final StackItem NULL = new StackItemNull(); + public static final StackItem INTEGER = new StackItemType(BasicType.INT); + public static final StackItem FLOAT = new StackItemType(BasicType.FLOAT); + public static final StackItem LONG = new StackItemType(BasicType.LONG); + public static final StackItem DOUBLE = new StackItemType(BasicType.DOUBLE); + public static final StackItem TOP = new StackItemTop(); + + StackMapType getType(ConstantPoolGen cp); +} + +class StackItemNull implements StackItem{ + + @Override + public StackMapType getType(ConstantPoolGen cp) { + return new StackMapType(Const.ITEM_Null, 0, cp.getConstantPool()); + } +} +class StackItemType implements StackItem{ + + Type t = null; + + //TODO: BasicType kann auch Void sein, dann ändert sich nichts am Stack + public StackItemType(BasicType b){ + t=b; + } + public StackItemType(ReferenceType r){ + t=r; + } + public StackItemType(Type t){ + t=t; + } + @Override + public StackMapType getType(ConstantPoolGen cp) { + if(t instanceof BasicType){ + return null;//TODO + }else if(t instanceof ObjectType){ + int classInfo = cp.addClass(((ObjectType)t)); + return new StackMapType(Const.ITEM_Object,classInfo,cp.getConstantPool()); + }else if(t instanceof ArrayType){ + return null; //TODO + }else{ + return null; + } + } +} +class StackItemTop implements StackItem{ + + @Override + public StackMapType getType(ConstantPoolGen cp) { + return new StackMapType(Const.ITEM_Bogus,0,cp.getConstantPool()); + } + +} +/* +class StackItemObject implements StackItem{ + public StackItemObject(String objName){ + + } +} +*/ +class StackState{ + +} + +class LocalVarState{ + +} + +class Fields{ + +} + +public class CodeHelper { + + private ArrayList outputStack = new ArrayList<>(); + + /** + * Pushes a new type onto the output frame stack. + * + * @param type + * the type that must be pushed. + */ + private void push(final int type) { + outputStack.add(type); + } + + /** + * Generiert die StackMapEntrys zu einer gegebenen Methode + * @param forCode + * @return + */ + public static Menge getStackMapEntries(InstructionList forCode, ConstantPoolGen cp){ + Menge ret = new Menge<>(); + JVMState state = new JVMState(); + if(forCode.isEmpty())return new Menge<>(); + forCode.setPositions(); //Otherwise InstructionHandle positions are wrong + Instruction[] instructions = forCode.getInstructions(); + InstructionHandle[] instructionHandles = forCode.getInstructionHandles(); + int lastPosition = 0; + for(int i = 0; i stackTypes = state.getStackTypes(cp); + Menge localTypes = state.getLocalTypes(cp); + StackMapType[] st = null; + StackMapType[] lt = null; + if(!stackTypes.isEmpty())st = stackTypes.toArray(); + if(!localTypes.isEmpty())lt = localTypes.toArray(); + StackMapEntry ret = new StackMapEntry(Const.FULL_FRAME,bytecodeOffset, lt, st, cp.getConstantPool()); + return ret; + } + + /** + * Ein Frame hört bei einem unconditionalBranch auf bzw. fängt bei dem Sprungziel eines Branches an. + * @see https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1 + * @param position + * @param inCode + * @return + */ + private static boolean isFrameEndpoint(InstructionHandle position, InstructionList inCode){ + if(position.getInstruction() instanceof GotoInstruction){ + //Falls Instruktion ein unconditional Branch ist: + return true; + } + for(InstructionHandle i : inCode.getInstructionHandles()){ + if(i.hasTargeters()){ + for(InstructionTargeter target : i.getTargeters()){ + if(target.containsTarget(position))return true; + } + } + /* + if(i instanceof BranchInstruction){ + inCode.getInstructionHandles()[1].getTargeters() + if(((BranchInstruction) i).containsTarget(position)){ + return true; + } + } + */ + } + return false; + } + + static void getOutput(Instruction ins, JVMState ret, ConstantPoolGen cp){ + /* + * TODO: + * Berechnet den Output auf den Stack und ändert den LocalVarState und den StackState je nach Instruktion ab + */ + int opcode = ins.getOpcode(); + StackItem t1,t2,t3,t4; + switch (opcode) { + case Const.NOP: + case Const.INEG: + case Const.LNEG: + case Const.FNEG: + case Const.DNEG: + case Const.I2B: + case Const.I2C: + case Const.I2S: + case Const.GOTO: + case Const.RETURN: + break; + case Const.ACONST_NULL: + ret.push(StackItem.NULL); + break; + case Const.ICONST_M1: + case Const.ICONST_0: + case Const.ICONST_1: + case Const.ICONST_2: + case Const.ICONST_3: + case Const.ICONST_4: + case Const.ICONST_5: + case Const.BIPUSH: + case Const.SIPUSH: + case Const.ILOAD: + ret.push(StackItem.INTEGER); + break; + case Const.LCONST_0: + case Const.LCONST_1: + case Const.LLOAD: + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case Const.FCONST_0: + case Const.FCONST_1: + case Const.FCONST_2: + case Const.FLOAD: + ret.push(StackItem.FLOAT); + break; + case Const.DCONST_0: + case Const.DCONST_1: + case Const.DLOAD: + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + break; + case Const.LDC: + LDC ldcIns = (LDC) ins; + Type t = ldcIns.getType(cp); + if(t.equals(Type.STRING)){ + ret.push(new StackItemType(Type.STRING)); + }else if(t.equals(Type.INT)){ + ret.push(StackItem.INTEGER); + }else if(t.equals(Type.FLOAT)){ + ret.push(StackItem.FLOAT); + }else if(t.equals(Type.DOUBLE)){ + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + }else if(t.equals(Type.FLOAT)){ + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + }else if(t.equals(Type.CLASS)){ + ret.push(new StackItemType(Type.CLASS)); + } + /* + switch (item.type) { + case ClassWriter.INT: + ret.push(StackItem.INTEGER); + break; + case ClassWriter.StackItem.LONG: + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case ClassWriter.StackItem.FLOAT: + ret.push(StackItem.FLOAT); + break; + case ClassWriter.StackItem.DOUBLE: + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + break; + case ClassWriter.CLASS: + ret.push(new StackItemOBJECT("java/lang/Class")); + break; + case ClassWriter.STR: + ret.push(new StackItemOBJECT("java/lang/String")); + break; + case ClassWriter.MTYPE: + ret.push(new StackItemOBJECT("java/lang/invoke/MethodType")); + break; + // case ClassWriter.HANDLE_BASE + [1..9]: + default: + ret.push(new StackItemOBJECT("java/lang/invoke/MethodHandle")); + break; + } + */ + break; + case Const.ALOAD: + ALOAD aloadIns = (ALOAD) ins; + ret.push(ret.getLocalType(aloadIns.getIndex())); + break; + case Const.IALOAD: + case Const.BALOAD: + case Const.CALOAD: + case Const.SALOAD: + ret.pop(2); + ret.push(StackItem.INTEGER); + break; + case Const.LALOAD: + case Const.D2L: + ret.pop(2); + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case Const.FALOAD: + ret.pop(2); + ret.push(StackItem.FLOAT); + break; + case Const.DALOAD: + case Const.L2D: + ret.pop(2); + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + break; + case Const.AALOAD: + ret.pop(1); + StackItem arrayReference = ret.pop(); + ret.push(arrayReference); //TODO: Fixen, es darf nicht die ArrayReference sonder der Typ eines Elements des Arrays auf den Stack + //ret.push(ELEMENT_OF + t1); + break; + case Const.ISTORE: + case Const.FSTORE: + case Const.ASTORE: + StoreInstruction storeIns = (StoreInstruction)ins; + t1 = ret.pop(); + ret.set(storeIns.getIndex(), t1); + if (storeIns.getIndex() > 0) { + t2 = ret.getLocalType(storeIns.getIndex() - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == StackItem.LONG || t2 == StackItem.DOUBLE) { + ret.set(storeIns.getIndex() - 1, StackItem.TOP); + } + //TODO: + /*else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | StackItem.TOP_IF_StackItem.LONG_OR_StackItem.DOUBLE); + }*/ + } + break; + case Const.LSTORE: + case Const.DSTORE: + StoreInstruction largeStoreIns = (StoreInstruction)ins; + ret.pop(1); + t1 = ret.pop(); + ret.set(largeStoreIns.getIndex(), t1); + ret.set(largeStoreIns.getIndex() + 1, StackItem.TOP); + if (largeStoreIns.getIndex() > 0) { + t2 = ret.getLocalType(largeStoreIns.getIndex() - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == StackItem.LONG || t2 == StackItem.DOUBLE) { + ret.set(largeStoreIns.getIndex() - 1, StackItem.TOP); + } //TODO: + /*else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | StackItem.TOP_IF_StackItem.LONG_OR_StackItem.DOUBLE); + }*/ + } + break; + case Const.IASTORE: + case Const.BASTORE: + case Const.CASTORE: + case Const.SASTORE: + case Const.FASTORE: + case Const.AASTORE: + ret.pop(3); + break; + case Const.LASTORE: + case Const.DASTORE: + ret.pop(4); + break; + case Const.POP: + case Const.IFEQ: + case Const.IFNE: + case Const.IFLT: + case Const.IFGE: + case Const.IFGT: + case Const.IFLE: + case Const.IRETURN: + case Const.FRETURN: + case Const.ARETURN: + case Const.TABLESWITCH: + case Const.LOOKUPSWITCH: + case Const.ATHROW: + case Const.MONITORENTER: + case Const.MONITOREXIT: + case Const.IFNULL: + case Const.IFNONNULL: + ret.pop(1); + break; + case Const.POP2: + case Const.IF_ICMPEQ: + case Const.IF_ICMPNE: + case Const.IF_ICMPLT: + case Const.IF_ICMPGE: + case Const.IF_ICMPGT: + case Const.IF_ICMPLE: + case Const.IF_ACMPEQ: + case Const.IF_ACMPNE: + case Const.LRETURN: + case Const.DRETURN: + ret.pop(2); + break; + case Const.DUP: + t1 = ret.pop(); + ret.push(t1); + ret.push(t1); + break; + case Const.DUP_X1: + t1 = ret.pop(); + t2 = ret.pop(); + ret.push(t1); + ret.push(t2); + ret.push(t1); + break; + case Const.DUP_X2: + t1 = ret.pop(); + t2 = ret.pop(); + t3 = ret.pop(); + ret.push(t1); + ret.push(t3); + ret.push(t2); + ret.push(t1); + break; + case Const.DUP2: + t1 = ret.pop(); + t2 = ret.pop(); + ret.push(t2); + ret.push(t1); + ret.push(t2); + ret.push(t1); + break; + case Const.DUP2_X1: + t1 = ret.pop(); + t2 = ret.pop(); + t3 = ret.pop(); + ret.push(t2); + ret.push(t1); + ret.push(t3); + ret.push(t2); + ret.push(t1); + break; + case Const.DUP2_X2: + t1 = ret.pop(); + t2 = ret.pop(); + t3 = ret.pop(); + t4 = ret.pop(); + ret.push(t2); + ret.push(t1); + ret.push(t4); + ret.push(t3); + ret.push(t2); + ret.push(t1); + break; + case Const.SWAP: + t1 = ret.pop(); + t2 = ret.pop(); + ret.push(t1); + ret.push(t2); + break; + case Const.IADD: + case Const.ISUB: + case Const.IMUL: + case Const.IDIV: + case Const.IREM: + case Const.IAND: + case Const.IOR: + case Const.IXOR: + case Const.ISHL: + case Const.ISHR: + case Const.IUSHR: + case Const.L2I: + case Const.D2I: + case Const.FCMPL: + case Const.FCMPG: + ret.pop(2); + ret.push(StackItem.INTEGER); + break; + case Const.LADD: + case Const.LSUB: + case Const.LMUL: + case Const.LDIV: + case Const.LREM: + case Const.LAND: + case Const.LOR: + case Const.LXOR: + ret.pop(4); + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case Const.FADD: + case Const.FSUB: + case Const.FMUL: + case Const.FDIV: + case Const.FREM: + case Const.L2F: + case Const.D2F: + ret.pop(2); + ret.push(StackItem.FLOAT); + break; + case Const.DADD: + case Const.DSUB: + case Const.DMUL: + case Const.DDIV: + case Const.DREM: + ret.pop(4); + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + break; + case Const.LSHL: + case Const.LSHR: + case Const.LUSHR: + ret.pop(3); + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case Const.IINC: + ret.set(((IINC)ins).getIndex(), StackItem.INTEGER); + break; + case Const.I2L: + case Const.F2L: + ret.pop(1); + ret.push(StackItem.LONG); + ret.push(StackItem.TOP); + break; + case Const.I2F: + ret.pop(1); + ret.push(StackItem.FLOAT); + break; + case Const.I2D: + case Const.F2D: + ret.pop(1); + ret.push(StackItem.DOUBLE); + ret.push(StackItem.TOP); + break; + case Const.F2I: + case Const.ARRAYLENGTH: + case Const.INSTANCEOF: + ret.pop(1); + ret.push(StackItem.INTEGER); + break; + case Const.LCMP: + case Const.DCMPL: + case Const.DCMPG: + ret.pop(4); + ret.push(StackItem.INTEGER); + break; + case Const.JSR: + case Const.RET: + throw new RuntimeException( + "JSR/RET are not supported with computeFrames option"); //TODO: Fehlermeldung anpassen + case Const.GETSTATIC: + //ret.push(cw, item.strVal3); //TODO + break; + case Const.PUTSTATIC: + //ret.pop(item.strVal3); //TODO + break; + case Const.GETFIELD: + GETFIELD getfieldIns = (GETFIELD) ins; + ret.pop(1); + ret.push(new StackItemType(getfieldIns.getFieldType(cp))); + break; + case Const.PUTFIELD: + PUTFIELD putfieldIns = (PUTFIELD) ins; + ret.pop(putfieldIns.consumeStack(cp)); + break; + case Const.INVOKEVIRTUAL: + case Const.INVOKESPECIAL: + case Const.INVOKESTATIC: + case Const.INVOKEINTERFACE: + InvokeInstruction invokeIns = (InvokeInstruction) ins; + ret.pop(invokeIns.consumeStack(cp)); + /* + * TODO: + * Hier return new StackItemOBJECT(returnTypeDerMethode); + * returnTypeDerMethode bestimmen indem man im ConstantPool nach dem Argument für die Instruktion nachsieht. + * Wie kann man bestimmen, ob es sich um Object oder primären Datentyp handelt. bcel-Typen verwenden? Müsste dann weiter oben auch gepatcht werden. + */ + /* + ret.pop(item.strVal3); + + if (opcode != Const.INVOKESTATIC) { + t1 = ret.pop(); + if (opcode == Const.INVOKESPECIAL + && item.strVal2.charAt(0) == '<') { + init(t1); + } + } + + ret.push(cw, item.strVal3); + */ + Type retType = invokeIns.getReturnType(cp); + if(retType instanceof BasicType){ + ret.push(new StackItemType((BasicType)retType)); + }else if(retType instanceof ArrayType){ + //TODO + }else if(retType instanceof ReferenceType){ + ret.push(new StackItemType((ReferenceType) retType)); + } + break; + /* + case Const.INVOKEDYNAMIC: + ret.pop(item.strVal2); + ret.push(cw, item.strVal2); + break; + case Const.NEW: + ret.push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + break; + case Const.NEWARRAY: + ret.pop(); + switch (arg) { + case Const.T_BOOLEAN: + ret.push(ARRAY_OF | BOOLEAN); + break; + case Const.T_CHAR: + ret.push(ARRAY_OF | CHAR); + break; + case Const.T_BYTE: + ret.push(ARRAY_OF | BYTE); + break; + case Const.T_SHORT: + ret.push(ARRAY_OF | SHORT); + break; + case Const.T_INT: + ret.push(ARRAY_OF | StackItem.INTEGER); + break; + case Const.T_StackItem.FLOAT: + ret.push(ARRAY_OF | StackItem.FLOAT); + break; + case Const.T_StackItem.DOUBLE: + ret.push(ARRAY_OF | StackItem.DOUBLE); + break; + // case Const.T_StackItem.LONG: + default: + ret.push(ARRAY_OF | StackItem.LONG); + break; + } + break; + case Const.ANEWARRAY: + String s = item.strVal1; + ret.pop(); + if (s.charAt(0) == '[') { + ret.push(cw, '[' + s); + } else { + ret.push(ARRAY_OF | OBJECT | cw.addType(s)); + } + break; + case Const.CHECKCAST: + s = item.strVal1; + ret.pop(); + if (s.charAt(0) == '[') { + ret.push(cw, s); + } else { + ret.push(OBJECT | cw.addType(s)); + } + break; + // case Const.MULTIANEWARRAY: + default: + ret.pop(arg); + ret.push(cw, item.strVal1); + break; + */ + } + } + + /** + * Simulates the action of the given instruction on the output stack frame. + * + * @param opcode + * the opcode of the instruction. + * @param arg + * the operand of the instruction, if any. + * @param item + * the operand of the instructions, if any. + */ + void execute(Instruction ins) { + + } + + +} diff --git a/src/de/dhbwstuttgart/syntaxtree/statement/IfStmt.java b/src/de/dhbwstuttgart/syntaxtree/statement/IfStmt.java index 4727a2d7..fb7ca5ce 100755 --- a/src/de/dhbwstuttgart/syntaxtree/statement/IfStmt.java +++ b/src/de/dhbwstuttgart/syntaxtree/statement/IfStmt.java @@ -191,10 +191,10 @@ public class IfStmt extends Statement il.append(then_block.genByteCode(_cg, rs)); if(else_block != null && !(else_block instanceof EmptyStmt)){ - GotoInstruction gotoInstruction = new GOTO(null); - il.append(gotoInstruction); + //GotoInstruction gotoInstruction = new GOTO(null); + //il.append(gotoInstruction); ifInstruction.setTarget(il.append(else_block.genByteCode(_cg, rs))); - gotoInstruction.setTarget(il.append(new NOP())); + //gotoInstruction.setTarget(il.append(new NOP())); }else{ ifInstruction.setTarget(il.append(new NOP())); } diff --git a/src/de/dhbwstuttgart/typeinference/Menge.java b/src/de/dhbwstuttgart/typeinference/Menge.java index 86c2a2eb..6834552f 100644 --- a/src/de/dhbwstuttgart/typeinference/Menge.java +++ b/src/de/dhbwstuttgart/typeinference/Menge.java @@ -19,4 +19,11 @@ public class Menge extends Vector implements Set{ return false; } + public A[] toArray(){ + A[] ret = (A[]) new Object[this.size()]; + for(int i = 0; i