BCEL Library aktualisiert, Stackmaptable angefügt, Tests angepasst

This commit is contained in:
JanUlrich 2016-03-10 15:28:03 +01:00
parent a4ea466fe6
commit b1d6b44fb9
11 changed files with 97 additions and 77 deletions

Binary file not shown.

View File

@ -10,6 +10,12 @@
## BCEL Patch ## BCEL Patch
https://issues.apache.org/jira/browse/BCEL-268 https://issues.apache.org/jira/browse/BCEL-268
* Submitting patch: https://commons.apache.org/patches.html
### Änderungen im BCEL-Projekt
* Neue Datei StackMapTableGen
* Testen TODO:
* Mittels BCELifier Code generieren lassen, welcher Methoden erstellt, die Branches enthalten
* Dies dann dem StackMapTableGen übergeben und auf das erstellen von StackMapEntries abprüfen
# Literatur # Literatur
* Zu JVM allgemein: http://blog.jamesdbloom.com/JVMInternals.html * Zu JVM allgemein: http://blog.jamesdbloom.com/JVMInternals.html

View File

@ -0,0 +1,12 @@
class StackMapTest5{
void methode(){
int i = 0;
while(System.out == null){
i+=1;
while(true){
String s = "2";
}
}
}
}

View File

@ -95,7 +95,7 @@ public class ClassGenerator extends ClassGen{
int innerClassesUTF8 = this.getConstantPool().addUtf8("InnerClasses"); int innerClassesUTF8 = this.getConstantPool().addUtf8("InnerClasses");
this.addAttribute(new InnerClasses(innerClassesUTF8,numberOfInnerClasses*8+2,innerClasses,this.getConstantPool().getConstantPool())); this.addAttribute(new InnerClasses(innerClassesUTF8,numberOfInnerClasses*8+2,innerClasses,this.getConstantPool().getConstantPool()));
} }
public int addBootstrapMethod(BootstrapMethod bMethod) { public int addBootstrapMethod(BootstrapMethod bMethod) {
int numberOfBootstrapMethods = 1; int numberOfBootstrapMethods = 1;
int name_index = this.getConstantPool().addUtf8("BootstrapMethods"); int name_index = this.getConstantPool().addUtf8("BootstrapMethods");

View File

@ -18,6 +18,7 @@ import org.apache.commons.bcel6.generic.ConstantPoolGen;
import org.apache.commons.bcel6.generic.Instruction; 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.StackMapTableGen;
import org.apache.commons.bcel6.generic.Type; import org.apache.commons.bcel6.generic.Type;
import org.apache.commons.bcel6.Const; import org.apache.commons.bcel6.Const;
@ -72,36 +73,13 @@ 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();
StackMap stackMap = new StackMapTableGen(this.getInstructionList(), cp).getStackMap();
if(stackMap != null)method.addCodeAttribute(stackMap); 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

@ -14,6 +14,7 @@ import org.apache.commons.bcel6.generic.DSTORE;
import org.apache.commons.bcel6.generic.GETFIELD; import org.apache.commons.bcel6.generic.GETFIELD;
import org.apache.commons.bcel6.generic.GotoInstruction; import org.apache.commons.bcel6.generic.GotoInstruction;
import org.apache.commons.bcel6.generic.IINC; import org.apache.commons.bcel6.generic.IINC;
import org.apache.commons.bcel6.generic.INVOKEDYNAMIC;
import org.apache.commons.bcel6.generic.INVOKEINTERFACE; import org.apache.commons.bcel6.generic.INVOKEINTERFACE;
import org.apache.commons.bcel6.generic.Instruction; import org.apache.commons.bcel6.generic.Instruction;
import org.apache.commons.bcel6.generic.InstructionHandle; import org.apache.commons.bcel6.generic.InstructionHandle;
@ -25,6 +26,7 @@ import org.apache.commons.bcel6.generic.InstructionList;
import org.apache.commons.bcel6.generic.InstructionTargeter; import org.apache.commons.bcel6.generic.InstructionTargeter;
import org.apache.commons.bcel6.generic.InvokeInstruction; import org.apache.commons.bcel6.generic.InvokeInstruction;
import org.apache.commons.bcel6.generic.LDC; import org.apache.commons.bcel6.generic.LDC;
import org.apache.commons.bcel6.generic.NEW;
import org.apache.commons.bcel6.generic.ObjectType; import org.apache.commons.bcel6.generic.ObjectType;
import org.apache.commons.bcel6.generic.PUTFIELD; import org.apache.commons.bcel6.generic.PUTFIELD;
import org.apache.commons.bcel6.generic.ReferenceType; import org.apache.commons.bcel6.generic.ReferenceType;
@ -130,6 +132,20 @@ class StackItemTop implements StackItem{
return new StackMapType(Const.ITEM_Bogus,0,cp.getConstantPool()); return new StackMapType(Const.ITEM_Bogus,0,cp.getConstantPool());
} }
}
class StackItemUninitialized implements StackItem{
private NEW newIns;
private InstructionHandle handle;
public StackItemUninitialized(NEW newInstruction, InstructionHandle instructionHandle){
newIns = newInstruction;
handle = instructionHandle;
}
@Override
public StackMapType getType(ConstantPoolGen cp) {
return new StackMapType(Const.ITEM_NewObject,handle.getPosition(),cp.getConstantPool());
}
} }
/* /*
class StackItemObject implements StackItem{ class StackItemObject implements StackItem{
@ -138,32 +154,10 @@ class StackItemObject implements StackItem{
} }
} }
*/ */
class StackState{
}
class LocalVarState{
}
class Fields{
}
public class CodeHelper { public class CodeHelper {
private ArrayList<Integer> outputStack = new ArrayList<>(); 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 * Generiert die StackMapEntrys zu einer gegebenen Methode
* @param forCode * @param forCode
@ -177,10 +171,9 @@ public class CodeHelper {
Instruction[] instructions = forCode.getInstructions(); Instruction[] instructions = forCode.getInstructions();
InstructionHandle[] instructionHandles = forCode.getInstructionHandles(); InstructionHandle[] instructionHandles = forCode.getInstructionHandles();
int lastPosition = 0; int lastPosition = 0;
for(int i = 0; i<forCode.getLength();i++){
Instruction ins = instructions[i]; for(InstructionHandle ih : forCode.getInstructionHandles()){
InstructionHandle ih = instructionHandles[i]; getOutput(ih, state, cp);
getOutput(ins, state, cp);
if(isFrameEndpoint(ih, forCode)){ if(isFrameEndpoint(ih, forCode)){
if(!state.stack.isEmpty()){ if(!state.stack.isEmpty()){
StackMapEntry entry = generateFullFrame(ih.getPosition(),state, cp); StackMapEntry entry = generateFullFrame(ih.getPosition(),state, cp);
@ -236,11 +229,12 @@ public class CodeHelper {
return false; return false;
} }
static void getOutput(Instruction ins, JVMState ret, ConstantPoolGen cp){ static void getOutput(InstructionHandle instructionHandle, JVMState ret, ConstantPoolGen cp){
/* /*
* TODO: * TODO:
* Berechnet den Output auf den Stack und ändert den LocalVarState und den StackState je nach Instruktion ab * Berechnet den Output auf den Stack und ändert den LocalVarState und den StackState je nach Instruktion ab
*/ */
Instruction ins = instructionHandle.getInstruction();
int opcode = ins.getOpcode(); int opcode = ins.getOpcode();
StackItem t1,t2,t3,t4; StackItem t1,t2,t3,t4;
switch (opcode) { switch (opcode) {
@ -618,6 +612,7 @@ public class CodeHelper {
case Const.INVOKESPECIAL: case Const.INVOKESPECIAL:
case Const.INVOKESTATIC: case Const.INVOKESTATIC:
case Const.INVOKEINTERFACE: case Const.INVOKEINTERFACE:
case Const.INVOKEDYNAMIC:
InvokeInstruction invokeIns = (InvokeInstruction) ins; InvokeInstruction invokeIns = (InvokeInstruction) ins;
ret.pop(invokeIns.consumeStack(cp)); ret.pop(invokeIns.consumeStack(cp));
/* /*
@ -648,14 +643,12 @@ public class CodeHelper {
ret.push(new StackItemType((ReferenceType) retType)); ret.push(new StackItemType((ReferenceType) retType));
} }
break; break;
/*
case Const.INVOKEDYNAMIC:
ret.pop(item.strVal2);
ret.push(cw, item.strVal2);
break;
case Const.NEW: case Const.NEW:
ret.push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); NEW newIns = (NEW) ins;
ret.push(new StackItemUninitialized(newIns, instructionHandle));
//ret.push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg));
break; break;
/*
case Const.NEWARRAY: case Const.NEWARRAY:
ret.pop(); ret.pop();
switch (arg) { switch (arg) {
@ -712,20 +705,6 @@ public class CodeHelper {
*/ */
} }
} }
/**
* 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

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

View File

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

View File

@ -0,0 +1,10 @@
class IfStatement{
Integer methode(Boolean b){
if(b){
return 1;
}else{
return 2;
}
}
}

View File

@ -0,0 +1,16 @@
package bytecode.stackmaptable;
import org.junit.Test;
import bytecode.SingleClassTester;
public class IfStatementTest {
public final static String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/stackmaptable/";
public final static String testFile = "IfStatement.jav";
public final static String outputFile = "IfStatement.class";
@Test
public void test() {
SingleClassTester.compileToBytecode(rootDirectory+testFile, rootDirectory);
}
}

View File

@ -0,0 +1,18 @@
import java.util.Vector;
class OverloadingReplace{
Vector<String> test;
void method(){
method(test);
}
void method(Vector<String> v) {
}
void method(Vector<Integer> v) {
}
}