Methode generiert StackMapTable

This commit is contained in:
JanUlrich 2016-02-18 18:28:08 +01:00
parent 7c00940cba
commit a4ea466fe6
14 changed files with 834 additions and 8 deletions

Binary file not shown.

View File

@ -0,0 +1,9 @@
class IfElseStatement{
Integer method(Boolean flag){
if(flag){
return 0;
}else{
return 1;
}
}
}

View File

@ -8,3 +8,8 @@
* https://stackoverflow.com/questions/24927993/what-kind-of-java-code-requires-stackmap-frames#24930521 * 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. * 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

View File

@ -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++;
}
}
}

View File

@ -97,7 +97,7 @@ public class DHBWInstructionFactory extends InstructionFactory{
for(int i = 0; i<arguments.size();i++){ for(int i = 0; i<arguments.size();i++){
argumentsArray[i] = arguments.get(i); argumentsArray[i] = arguments.get(i);
} }
BootstrapMethod bMethod = new BootstrapMethod(lambdaMetafactoryHandle, arguments.size(), argumentsArray); BootstrapMethod bMethod = new BootstrapMethod(lambdaMetafactoryHandle, argumentsArray);
int index; int index;

View File

@ -1,12 +1,28 @@
package de.dhbwstuttgart.bytecode; package de.dhbwstuttgart.bytecode;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.commons.bcel6.classfile.Attribute;
import org.apache.commons.bcel6.classfile.ConstantPool;
import org.apache.commons.bcel6.classfile.ConstantUtf8;
import org.apache.commons.bcel6.classfile.Method; import org.apache.commons.bcel6.classfile.Method;
import org.apache.commons.bcel6.classfile.Signature; import org.apache.commons.bcel6.classfile.Signature;
import org.apache.commons.bcel6.classfile.StackMap;
import org.apache.commons.bcel6.classfile.StackMapEntry;
import org.apache.commons.bcel6.classfile.Visitor;
import org.apache.commons.bcel6.generic.BranchInstruction;
import org.apache.commons.bcel6.generic.ConstantPoolGen; import org.apache.commons.bcel6.generic.ConstantPoolGen;
import org.apache.commons.bcel6.generic.Instruction;
import org.apache.commons.bcel6.generic.InstructionList; import org.apache.commons.bcel6.generic.InstructionList;
import org.apache.commons.bcel6.generic.MethodGen; import org.apache.commons.bcel6.generic.MethodGen;
import org.apache.commons.bcel6.generic.Type; import org.apache.commons.bcel6.generic.Type;
import org.apache.commons.bcel6.Const;
import de.dhbwstuttgart.bytecode.stackmaptable.CodeHelper;
import de.dhbwstuttgart.logger.Logger; import de.dhbwstuttgart.logger.Logger;
import de.dhbwstuttgart.logger.Section; import de.dhbwstuttgart.logger.Section;
import de.dhbwstuttgart.syntaxtree.FormalParameter; import de.dhbwstuttgart.syntaxtree.FormalParameter;
@ -14,6 +30,7 @@ import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.statement.Block; import de.dhbwstuttgart.syntaxtree.statement.Block;
import de.dhbwstuttgart.syntaxtree.statement.Return; import de.dhbwstuttgart.syntaxtree.statement.Return;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.Menge;
import de.dhbwstuttgart.typeinference.TypeinferenceResultSet; import de.dhbwstuttgart.typeinference.TypeinferenceResultSet;
public class MethodGenerator extends MethodGen{ public class MethodGenerator extends MethodGen{
@ -32,9 +49,13 @@ public class MethodGenerator extends MethodGen{
il.append(blockInstructions);//Die vom Block generierten Instructions an die InstructionList der Methode anfügen il.append(blockInstructions);//Die vom Block generierten Instructions an die InstructionList der Methode anfügen
//Ein return Statement anfügen, falls nicht vorhanden: //Ein return Statement anfügen, falls nicht vorhanden:
//TODO: Das ist schlecht! Der Parser oder der Typinferenzalgorithmus muss dafür sorgen, dass sich in jeder Methode ein Return befindet.
if (block.get_Statement().size() == 0) { il.append(factory.createReturn( org.apache.commons.bcel6.generic.Type.VOID)); } if (block.get_Statement().size() == 0) { il.append(factory.createReturn( org.apache.commons.bcel6.generic.Type.VOID)); }
else { else {
if (!(block.get_Statement().lastElement() instanceof Return)) { il.append(factory.createReturn( org.apache.commons.bcel6.generic.Type.VOID)); } if (!(block.get_Statement().lastElement() instanceof Return) &&
this.getType().equals(org.apache.commons.bcel6.generic.Type.VOID)) {
il.append(factory.createReturn( org.apache.commons.bcel6.generic.Type.VOID));
}
} }
method.stripAttributes(true); method.stripAttributes(true);
@ -51,8 +72,36 @@ public class MethodGenerator extends MethodGen{
String retTypeSig = retType.getBytecodeSignature(cg, rs); String retTypeSig = retType.getBytecodeSignature(cg, rs);
method.addAttribute(factory.createSignatureAttribute(paramTypesSig+retTypeSig)); method.addAttribute(factory.createSignatureAttribute(paramTypesSig+retTypeSig));
StackMap stackMap = this.generateStackMapFrame();
if(stackMap != null)method.addCodeAttribute(stackMap);
return method.getMethod(); return method.getMethod();
} }
/**
*
* @return null - falls kein StackMapFrame für die Methode notwendig ist
*/
private StackMap generateStackMapFrame(){
int length=2; //+2 wegen NumberOfEntries
Menge<StackMapEntry> entries = CodeHelper.getStackMapEntries(getInstructionList(), cp);
if(entries.size()==0)return null;
StackMapEntry[] entryArray = new StackMapEntry[entries.size()];
for(int i = 0; i<entries.size();i++){
entryArray[i] = entries.get(i);
ByteArrayOutputStream testOut = new ByteArrayOutputStream();
try {
entries.get(i).dump(new DataOutputStream(testOut));
} catch (IOException e) {
//Kann nicht auftreten. Es wird in Byte-Array geschrieben.
e.printStackTrace();
} }
length+=testOut.size();
}
return new StackMap(cp.addUtf8(Const.getAttributeName(Const.ATTR_STACK_MAP_TABLE))
,length, entryArray,cp.getConstantPool());
}
}

View File

@ -0,0 +1,731 @@
package de.dhbwstuttgart.bytecode.stackmaptable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import org.apache.commons.bcel6.generic.ALOAD;
import org.apache.commons.bcel6.generic.ASTORE;
import org.apache.commons.bcel6.generic.ArrayType;
import org.apache.commons.bcel6.generic.BasicType;
import org.apache.commons.bcel6.generic.BranchInstruction;
import org.apache.commons.bcel6.generic.ConstantPoolGen;
import org.apache.commons.bcel6.generic.DSTORE;
import org.apache.commons.bcel6.generic.GETFIELD;
import org.apache.commons.bcel6.generic.GotoInstruction;
import org.apache.commons.bcel6.generic.IINC;
import org.apache.commons.bcel6.generic.INVOKEINTERFACE;
import org.apache.commons.bcel6.generic.Instruction;
import org.apache.commons.bcel6.generic.InstructionHandle;
import org.apache.commons.bcel6.Const;
import org.apache.commons.bcel6.classfile.ConstantPool;
import org.apache.commons.bcel6.classfile.StackMapEntry;
import org.apache.commons.bcel6.classfile.StackMapType;
import org.apache.commons.bcel6.generic.InstructionList;
import org.apache.commons.bcel6.generic.InstructionTargeter;
import org.apache.commons.bcel6.generic.InvokeInstruction;
import org.apache.commons.bcel6.generic.LDC;
import org.apache.commons.bcel6.generic.ObjectType;
import org.apache.commons.bcel6.generic.PUTFIELD;
import org.apache.commons.bcel6.generic.ReferenceType;
import org.apache.commons.bcel6.generic.StoreInstruction;
import org.apache.commons.bcel6.generic.Type;
import de.dhbwstuttgart.bytecode.MethodGenerator;
import de.dhbwstuttgart.typeinference.Menge;
class JVMState{
HashMap<Integer, StackItem> localVars = new HashMap<>();
Stack<StackItem> 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<StackMapType> getStackTypes(ConstantPoolGen cp){
Menge<StackMapType> ret = new Menge<StackMapType>();
for(StackItem si : stack){
ret.add(si.getType(cp));
}
return ret;
}
public Menge<StackMapType> getLocalTypes(ConstantPoolGen cp) {
Menge<StackMapType> ret = new Menge<StackMapType>();
//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<Integer> 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<StackMapEntry> getStackMapEntries(InstructionList forCode, ConstantPoolGen cp){
Menge<StackMapEntry> 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<forCode.getLength();i++){
Instruction ins = instructions[i];
InstructionHandle ih = instructionHandles[i];
getOutput(ins, state, cp);
if(isFrameEndpoint(ih, forCode)){
if(!state.stack.isEmpty()){
StackMapEntry entry = generateFullFrame(ih.getPosition(),state, cp);
ret.add(entry);
}else{
int offset = ih.getPosition()-lastPosition;
ret.add(new StackMapEntry(Const.SAME_FRAME + offset, 0, null, null, cp.getConstantPool()));
}
lastPosition = ih.getPosition()+1;
}
}
return ret;
}
public static StackMapEntry generateFullFrame(int bytecodeOffset, JVMState state, ConstantPoolGen cp){
Menge<StackMapType> stackTypes = state.getStackTypes(cp);
Menge<StackMapType> 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) {
}
}

View File

@ -191,10 +191,10 @@ public class IfStmt extends Statement
il.append(then_block.genByteCode(_cg, rs)); il.append(then_block.genByteCode(_cg, rs));
if(else_block != null && !(else_block instanceof EmptyStmt)){ if(else_block != null && !(else_block instanceof EmptyStmt)){
GotoInstruction gotoInstruction = new GOTO(null); //GotoInstruction gotoInstruction = new GOTO(null);
il.append(gotoInstruction); //il.append(gotoInstruction);
ifInstruction.setTarget(il.append(else_block.genByteCode(_cg, rs))); ifInstruction.setTarget(il.append(else_block.genByteCode(_cg, rs)));
gotoInstruction.setTarget(il.append(new NOP())); //gotoInstruction.setTarget(il.append(new NOP()));
}else{ }else{
ifInstruction.setTarget(il.append(new NOP())); ifInstruction.setTarget(il.append(new NOP()));
} }

View File

@ -19,4 +19,11 @@ public class Menge<A> extends Vector<A> implements Set<A>{
return false; return false;
} }
public A[] toArray(){
A[] ret = (A[]) new Object[this.size()];
for(int i = 0; i<this.size();i++){
ret[i] = this.get(i);
}
return ret;
}
} }

View File

@ -1,5 +1,5 @@
class IfElseStatement{ class IfElseStatement{
method(flag){ Integer method(Boolean flag){
if(flag){ if(flag){
return 0; return 0;
}else{ }else{

View File

@ -9,6 +9,6 @@ public class IfElseStatementTest {
@Test @Test
public void test() { public void test() {
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory);
} }
} }

View File

@ -9,6 +9,6 @@ public class IfStatementTest {
@Test @Test
public void test() { public void test() {
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile); SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory);
} }
} }

View File

@ -0,0 +1,8 @@
class TestStackMap{
public static void main(String[] args){
IfElseStatement test = new IfElseStatement();
System.out.println(test.method(false));
}
}