forked from JavaTX/JavaCompilerCore
Methode generiert StackMapTable
This commit is contained in:
parent
7c00940cba
commit
a4ea466fe6
Binary file not shown.
Binary file not shown.
9
notizen/stan/stackmaptable/IfElseStatement.java
Normal file
9
notizen/stan/stackmaptable/IfElseStatement.java
Normal file
@ -0,0 +1,9 @@
|
||||
class IfElseStatement{
|
||||
Integer method(Boolean flag){
|
||||
if(flag){
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
17
notizen/stan/stackmaptable/StackMapTest4.java
Normal file
17
notizen/stan/stackmaptable/StackMapTest4.java
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ public class DHBWInstructionFactory extends InstructionFactory{
|
||||
for(int i = 0; i<arguments.size();i++){
|
||||
argumentsArray[i] = arguments.get(i);
|
||||
}
|
||||
BootstrapMethod bMethod = new BootstrapMethod(lambdaMetafactoryHandle, arguments.size(), argumentsArray);
|
||||
BootstrapMethod bMethod = new BootstrapMethod(lambdaMetafactoryHandle, argumentsArray);
|
||||
|
||||
int index;
|
||||
|
||||
|
@ -1,12 +1,28 @@
|
||||
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.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.Instruction;
|
||||
import org.apache.commons.bcel6.generic.InstructionList;
|
||||
import org.apache.commons.bcel6.generic.MethodGen;
|
||||
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.Section;
|
||||
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.Return;
|
||||
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
|
||||
import de.dhbwstuttgart.typeinference.Menge;
|
||||
import de.dhbwstuttgart.typeinference.TypeinferenceResultSet;
|
||||
|
||||
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
|
||||
//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)); }
|
||||
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);
|
||||
@ -51,8 +72,36 @@ public class MethodGenerator extends MethodGen{
|
||||
String retTypeSig = retType.getBytecodeSignature(cg, rs);
|
||||
|
||||
method.addAttribute(factory.createSignatureAttribute(paramTypesSig+retTypeSig));
|
||||
StackMap stackMap = this.generateStackMapFrame();
|
||||
if(stackMap != null)method.addCodeAttribute(stackMap);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
731
src/de/dhbwstuttgart/bytecode/stackmaptable/CodeHelper.java
Normal file
731
src/de/dhbwstuttgart/bytecode/stackmaptable/CodeHelper.java
Normal 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) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
@ -19,4 +19,11 @@ public class Menge<A> extends Vector<A> implements Set<A>{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
class IfElseStatement{
|
||||
method(flag){
|
||||
Integer method(Boolean flag){
|
||||
if(flag){
|
||||
return 0;
|
||||
}else{
|
||||
|
@ -9,6 +9,6 @@ public class IfElseStatementTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile);
|
||||
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,6 @@ public class IfStatementTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory+outputFile);
|
||||
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory);
|
||||
}
|
||||
}
|
||||
|
8
test/bytecode/TestStackMap.java
Normal file
8
test/bytecode/TestStackMap.java
Normal file
@ -0,0 +1,8 @@
|
||||
class TestStackMap{
|
||||
|
||||
public static void main(String[] args){
|
||||
IfElseStatement test = new IfElseStatement();
|
||||
System.out.println(test.method(false));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user