further work on geberating stack maps

This commit is contained in:
Julian Dolby 2014-10-10 17:46:56 -04:00
parent 4e52c00a4b
commit 63232e4a02
21 changed files with 178 additions and 105 deletions

View File

@ -42,7 +42,7 @@ public class AddBytecodeDebug {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", false));

View File

@ -61,7 +61,6 @@ public class Bench {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter();
Writer w = new BufferedWriter(new FileWriter("report", false));
@ -74,6 +73,7 @@ public class Bench {
doException = true;
}
}
instrumenter = new OfflineInstrumenter(!doException);
instrumenter.setPassUnmodifiedClasses(true);
instrumenter.beginTraversal();
ClassInstrumenter ci;

View File

@ -41,7 +41,7 @@ public class InterfaceAnalyzer {
final static HashMap<String, TypeStats> typeStats = new HashMap<String, TypeStats>();
public static void main(String[] args) throws Exception {
OfflineInstrumenter instrumenter = new OfflineInstrumenter();
OfflineInstrumenter instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new OutputStreamWriter(System.out));

View File

@ -57,7 +57,7 @@ public class Mangler {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", false));

View File

@ -39,7 +39,7 @@ public class Statistics {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", false));

View File

@ -60,6 +60,8 @@ public class DynamicCallGraph {
private final static boolean disasm = true;
private final static boolean verify = true;
private static boolean patchExits = true;
private static OfflineInstrumenter instrumenter;
private static Class<?> runtime = Runtime.class;
@ -72,24 +74,26 @@ public class DynamicCallGraph {
ClassInstrumenter ci;
Writer w = new BufferedWriter(new FileWriter("report", false));
instrumenter = new OfflineInstrumenter();
args = instrumenter.parseStandardArgs(args);
for(int i = 0; i < args.length - 1; i++) {
if ("--runtime".equals(args[i])) {
runtime = Class.forName(args[i+1]);
} else if ("--exclusions".equals(args[i])) {
filter = new FileOfClasses(new FileInputStream(args[i+1]));
} else if ("--rt-jar".equals(args[i])) {
System.err.println("using " + args[i+1] + " as stdlib");
OfflineInstrumenter libReader = new OfflineInstrumenter();
libReader.addInputJar(new File(args[i+1]));
while ((ci = libReader.nextClass()) != null) {
CTUtils.addClassToHierarchy(cha, ci.getReader());
for(int i = 0; i < args.length - 1; i++) {
if ("--runtime".equals(args[i])) {
runtime = Class.forName(args[i+1]);
} else if ("--exclusions".equals(args[i])) {
filter = new FileOfClasses(new FileInputStream(args[i+1]));
} else if ("--dont-patch-exits".equals(args[i])) {
patchExits = false;
} else if ("--rt-jar".equals(args[i])) {
System.err.println("using " + args[i+1] + " as stdlib");
OfflineInstrumenter libReader = new OfflineInstrumenter(true);
libReader.addInputJar(new File(args[i+1]));
while ((ci = libReader.nextClass()) != null) {
CTUtils.addClassToHierarchy(cha, ci.getReader());
}
}
}
}
instrumenter = new OfflineInstrumenter(!patchExits);
args = instrumenter.parseStandardArgs(args);
instrumenter.setPassUnmodifiedClasses(true);
instrumenter.beginTraversal();
@ -137,7 +141,7 @@ public class DynamicCallGraph {
if (verify) {
Verifier v = new Verifier(d);
v.setClassHierarchy(cha);
// v.setClassHierarchy(cha);
v.verify();
}
@ -163,42 +167,44 @@ public class DynamicCallGraph {
}
});
me.addMethodExceptionHandler(null, new MethodEditor.Patch() {
@Override
public void emitTo(Output w) {
w.emit(ConstantInstruction.makeString(theClass));
w.emit(ConstantInstruction.makeString(theMethod));
//if (nonStatic)
// w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this
//else
w.emit(Util.makeGet(runtime, "NULL_TAG"));
// w.emit(ConstantInstruction.make(Constants.TYPE_null, null));
w.emit(ConstantInstruction.make(1)); // true
w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class}));
w.emit(ThrowInstruction.make(false));
}
});
me.visitInstructions(new MethodEditor.Visitor() {
@Override
public void visitReturn(ReturnInstruction instruction) {
insertBefore(new MethodEditor.Patch() {
@Override
public void emitTo(MethodEditor.Output w) {
w.emit(ConstantInstruction.makeString(theClass));
w.emit(ConstantInstruction.makeString(theMethod));
if (nonStatic)
w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this
else
w.emit(Util.makeGet(runtime, "NULL_TAG"));
// w.emit(ConstantInstruction.make(Constants.TYPE, null));
w.emit(ConstantInstruction.make(0)); // false
w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class}));
}
});
}
});
if (patchExits) {
me.addMethodExceptionHandler(null, new MethodEditor.Patch() {
@Override
public void emitTo(Output w) {
w.emit(ConstantInstruction.makeString(theClass));
w.emit(ConstantInstruction.makeString(theMethod));
//if (nonStatic)
// w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this
//else
w.emit(Util.makeGet(runtime, "NULL_TAG"));
// w.emit(ConstantInstruction.make(Constants.TYPE_null, null));
w.emit(ConstantInstruction.make(1)); // true
w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class}));
w.emit(ThrowInstruction.make(false));
}
});
me.visitInstructions(new MethodEditor.Visitor() {
@Override
public void visitReturn(ReturnInstruction instruction) {
insertBefore(new MethodEditor.Patch() {
@Override
public void emitTo(MethodEditor.Output w) {
w.emit(ConstantInstruction.makeString(theClass));
w.emit(ConstantInstruction.makeString(theMethod));
if (nonStatic)
w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this
else
w.emit(Util.makeGet(runtime, "NULL_TAG"));
// w.emit(ConstantInstruction.make(Constants.TYPE, null));
w.emit(ConstantInstruction.make(0)); // false
w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class}));
}
});
}
});
}
// this updates the data d
me.applyPatches();
@ -210,7 +216,7 @@ public class DynamicCallGraph {
if (verify) {
Verifier v = new Verifier(d);
v.setClassHierarchy(cha);
// v.setClassHierarchy(cha);
v.verify();
}
}

View File

@ -93,7 +93,7 @@ public class CopyWriter {
final ArrayList<ZipEntry> entries = new ArrayList<ZipEntry>();
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
instrumenter.setManifestBuilder(new OfflineInstrumenter.ManifestBuilder() {
@Override
public void addEntry(ZipEntry ze) {

View File

@ -1681,7 +1681,7 @@ public abstract class Compiler implements Constants {
}
private void makeTypes() {
Verifier v = new Verifier(isConstructor, isStatic, classType, signature, instructions, handlers, instructionsToBytecodes);
Verifier v = new Verifier(isConstructor, isStatic, classType, signature, instructions, handlers, instructionsToBytecodes, null);
if (hierarchy != null) {
v.setClassHierarchy(hierarchy);
}

View File

@ -13,6 +13,7 @@ package com.ibm.wala.shrikeBT.analysis;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
@ -71,12 +72,14 @@ public class Analyzer {
protected int[][] backEdges;
protected int[] instToBC;
protected String[][] varTypes;
protected final static String[] noStrings = new String[0];
protected final static int[] noEdges = new int[0];
public Analyzer(boolean isConstructor, boolean isStatic, String classType, String signature, IInstruction[] instructions, ExceptionHandler[][] handlers, int[] instToBC) {
public Analyzer(boolean isConstructor, boolean isStatic, String classType, String signature, IInstruction[] instructions, ExceptionHandler[][] handlers, int[] instToBC, String[][] vars) {
if (instructions == null) {
throw new IllegalArgumentException("null instructions");
}
@ -95,6 +98,7 @@ public class Analyzer {
this.instructions = instructions;
this.handlers = handlers;
this.instToBC = instToBC;
this.varTypes = vars;
}
/**
@ -203,6 +207,15 @@ public class Analyzer {
return t1;
}
if (String.valueOf(t1).equals("L;") || String.valueOf(t2).equals("L;")) {
System.err.println("++ " + t1 + " -- " + t2 + " ++");
if (String.valueOf(t1).equals("L;")) {
return t2;
} else {
return t1;
}
}
if (t1 == thisType || t2 == thisType || t1 == topType || t2 == topType) {
return topType;
}
@ -213,7 +226,7 @@ public class Analyzer {
String x = ClassHierarchy.findCommonSupertype(hierarchy, patchType(t1), patchType(t2));
if ("L?;".equals(x) && ("J".equals(t1) || "J".equals(t2))) {
if ("L?;".equals(x)) {
System.err.println(t1 + " -- " + t2);
}
@ -694,6 +707,28 @@ public class Analyzer {
instr.visit(localsUpdate); // visit localStore before popping
System.arraycopy(curStack, popped, curStack, 0, curStackSize - popped);
curStackSize -= popped;
if (varTypes != null) {
if (instr instanceof IStoreInstruction) {
int local = ((IStoreInstruction)instr).getVarIndex();
if (Constants.TYPE_null.equals(curLocals[local])) {
for(int idx : new int[]{i, i+1}) {
int bc = instToBC[idx];
if (bc == 667 && local == 16) {
System.err.println("got here");
}
if (bc != -1 && varTypes != null && varTypes.length > bc && varTypes[bc] != null) {
if (varTypes[bc].length > local && varTypes[bc][local] != null) {
String declaredType = varTypes[bc][local];
curLocals[local] = declaredType;
System.err.println("setting local " + local + " to " + declaredType + " at " + instToBC[i] + " in " + classType + " " + signature);
}
}
}
}
}
}
}
}
@ -710,8 +745,13 @@ public class Analyzer {
}
}
//System.err.println(i + " -- " + Arrays.toString(curLocals) + " -- " + Arrays.toString(curStack));
int[] targets = instr.getBranchTargets();
for (int j = 0; j < targets.length; j++) {
if (targets[j] == 29 && classType.contains("MetaClassImpl;") && signature.contains("(Ljava/lang/String;Lorg/codehaus/groovy/reflection/CachedClass;)")) {
System.err.println("got here");
}
if (mergeTypes(targets[j], curStack, curStackSize, curLocals, curLocalsSize[0], path)) {
computeTypes(targets[j], visitor, makeTypesAt, path);
}
@ -830,11 +870,11 @@ public class Analyzer {
}
protected Analyzer(MethodData info) {
this(info.getName().equals("<init>"), info.getIsStatic(), info.getClassType(), info.getSignature(), info.getInstructions(), info.getHandlers(), info.getInstructionsToBytecodes());
this(info.getName().equals("<init>"), info.getIsStatic(), info.getClassType(), info.getSignature(), info.getInstructions(), info.getHandlers(), info.getInstructionsToBytecodes(), null);
}
protected Analyzer(MethodData info, int[] instToBC) {
this(info.getName().equals("<init>"), info.getIsStatic(), info.getClassType(), info.getSignature(), info.getInstructions(), info.getHandlers(), instToBC);
protected Analyzer(MethodData info, int[] instToBC, String[][] vars) {
this(info.getName().equals("<init>"), info.getIsStatic(), info.getClassType(), info.getSignature(), info.getInstructions(), info.getHandlers(), instToBC, vars);
}
public static Analyzer createAnalyzer(MethodData info) {

View File

@ -277,6 +277,11 @@ public final class ClassHierarchy {
}
private static String findCommonSupertypeHierarchy(ClassHierarchyProvider hierarchy, String t1, String t2) {
if (hierarchy != null && t1.contains("Reader") && t2.contains("Reader")) {
System.err.println("got here");
}
if (isSubtypeOf(hierarchy, t1, t2) == YES) {
return t2;
} else if (isSubtypeOf(hierarchy, t2, t1) == YES) {

View File

@ -287,8 +287,8 @@ public final class Verifier extends Analyzer {
/**
* Initialize a verifier.
*/
public Verifier(boolean isConstructor, boolean isStatic, String classType, String signature, IInstruction[] instructions, ExceptionHandler[][] handlers, int[] instToBC) {
super(isConstructor, isStatic, classType, signature, instructions, handlers, instToBC);
public Verifier(boolean isConstructor, boolean isStatic, String classType, String signature, IInstruction[] instructions, ExceptionHandler[][] handlers, int[] instToBC, String[][] vars) {
super(isConstructor, isStatic, classType, signature, instructions, handlers, instToBC, vars);
}
/**
@ -300,8 +300,8 @@ public final class Verifier extends Analyzer {
super(info);
}
public Verifier(MethodData info, int[] instToBC) throws NullPointerException {
super(info, instToBC);
public Verifier(MethodData info, int[] instToBC, String[][] vars) throws NullPointerException {
super(info, instToBC, vars);
}
/**

View File

@ -63,11 +63,13 @@ final public class ClassInstrumenter {
private final ClassHierarchyProvider cha;
private final boolean reuseStackMaps;
/**
* Create a class instrumenter from raw bytes.
*/
public ClassInstrumenter(String inputName, byte[] bytes, ClassHierarchyProvider cha) throws InvalidClassFileException {
this(inputName, new ClassReader(bytes), cha);
public ClassInstrumenter(String inputName, byte[] bytes, ClassHierarchyProvider cha, boolean reuseStackMaps) throws InvalidClassFileException {
this(inputName, new ClassReader(bytes), cha, reuseStackMaps);
}
/**
@ -91,12 +93,13 @@ final public class ClassInstrumenter {
*
* @throws IllegalArgumentException if cr is null
*/
public ClassInstrumenter(String inputName, ClassReader cr, ClassHierarchyProvider cha) throws InvalidClassFileException {
public ClassInstrumenter(String inputName, ClassReader cr, ClassHierarchyProvider cha, boolean reuseStackMaps) throws InvalidClassFileException {
if (cr == null) {
throw new IllegalArgumentException("cr is null");
}
this.cr = cr;
this.cha = cha;
this.reuseStackMaps = reuseStackMaps;
methods = new MethodData[cr.getMethodCount()];
oldCode = new CodeReader[methods.length];
cpr = CTDecoder.makeConstantPoolReader(cr);
@ -426,7 +429,23 @@ final public class ClassInstrumenter {
stacks = new StackMapTableWriter(w, sm, output.getNewBytecodesToOldBytecodes());
codeAttrCount++;
} else { */
stacks = new StackMapTableWriter(w, md, output, cha);
String[][] varTypes = null;
int[] newToOld = output.getNewBytecodesToOldBytecodes();
int[][] vars = LocalVariableTableReader.makeVarMap(oldCode);
if (vars != null) {
varTypes = new String[newToOld.length][];
for(int i = 0; i < newToOld.length; i++) {
int idx = newToOld[i];
if (idx != -1 && vars[idx] != null) {
varTypes[i] = new String[vars[idx].length / 2];
for(int j = 1; j < vars[idx].length; j += 2) {
int type = vars[idx][j];
varTypes[i][j/2] = type==0? null: oldCode.getClassReader().getCP().getCPUtf8(type);
}
}
}
}
stacks = new StackMapTableWriter(w, md, output, cha, varTypes);
codeAttrCount++;
// }
} catch (IOException | FailureException e) {

View File

@ -25,11 +25,12 @@ import com.ibm.wala.shrikeCT.InvalidClassFileException;
* specialization of OfflineInstrumenterBase to use the shrikeCT functionality.
*/
final public class OfflineInstrumenter extends OfflineInstrumenterBase {
private final boolean reuseStackMaps;
/**
* Create an empty collection of classes to instrument.
*/
public OfflineInstrumenter() {
public OfflineInstrumenter(boolean reuseStackMaps) {
this.reuseStackMaps = reuseStackMaps;
}
@Override
@ -37,7 +38,7 @@ final public class OfflineInstrumenter extends OfflineInstrumenterBase {
byte[] bytes = new byte[s.available()];
Util.readFully(s, bytes);
try {
return new ClassInstrumenter(inputName, bytes, cha);
return new ClassInstrumenter(inputName, bytes, cha, reuseStackMaps);
} catch (InvalidClassFileException e) {
throw new IOException("Class is invalid: " + e.getMessage());
}

View File

@ -48,7 +48,7 @@ public class BatchVerifier {
private static int errors = 0;
public static void main(String[] args) throws Exception {
OfflineInstrumenter oi = new OfflineInstrumenter();
OfflineInstrumenter oi = new OfflineInstrumenter(true);
args = oi.parseStandardArgs(args);
for (int i = 0; i < args.length; i++) {

View File

@ -42,7 +42,7 @@ public class BootstrapDumper {
}
public static void main(String[] args) throws Exception {
OfflineInstrumenter oi = new OfflineInstrumenter();
OfflineInstrumenter oi = new OfflineInstrumenter(true);
String[] classpathEntries = oi.parseStandardArgs(args);
PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

View File

@ -72,7 +72,7 @@ public class ClassPrinter {
}
public static void main(String[] args) throws Exception {
OfflineInstrumenter oi = new OfflineInstrumenter();
OfflineInstrumenter oi = new OfflineInstrumenter(true);
args = oi.parseStandardArgs(args);
PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

View File

@ -36,7 +36,7 @@ public class ClassSearcher {
private static int scanned = 0;
public static void main(String[] args) throws Exception {
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", true));

View File

@ -51,7 +51,7 @@ public class MethodTracer {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1; i++) {
instrumenter = new OfflineInstrumenter();
instrumenter = new OfflineInstrumenter(true);
Writer w = new BufferedWriter(new FileWriter("report", false));

View File

@ -27,6 +27,7 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import com.ibm.wala.shrikeBT.analysis.ClassHierarchyProvider;

View File

@ -97,19 +97,9 @@ public final class LocalVariableTableReader extends AttributeReader {
+ " in LocalVariableTable");
}
int rangeStart = startPC;
while (rangeStart < startPC + length) {
int rangeLength = 1;
while (rangeStart + rangeLength < startPC + length && r[rangeStart + rangeLength] == r[rangeStart]) {
rangeLength++;
}
int[] newVector = makeVarVector(r[rangeStart], varIndex, nameIndex, typeIndex);
for (int k = rangeStart; k < rangeStart + rangeLength; k++) {
r[k] = newVector;
}
rangeStart += rangeLength;
for (int k = startPC; k < startPC + length; k++) {
int[] newVector = makeVarVector(r[k], varIndex, nameIndex, typeIndex);
r[k] = newVector;
}
}
}

View File

@ -1,9 +1,6 @@
package com.ibm.wala.shrikeCT;
import static com.ibm.wala.shrikeBT.Constants.TYPE_double;
import static com.ibm.wala.shrikeBT.Constants.TYPE_float;
import static com.ibm.wala.shrikeBT.Constants.TYPE_int;
import static com.ibm.wala.shrikeBT.Constants.TYPE_long;
import static com.ibm.wala.shrikeBT.Constants.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -54,8 +51,8 @@ public class StackMapTableWriter extends Element {
}
public StackMapTableWriter(ClassWriter writer, MethodData method, Output output, ClassHierarchyProvider cha) throws FailureException, IOException {
this(writer, stackMapTable(writer, method, output, cha));
public StackMapTableWriter(ClassWriter writer, MethodData method, Output output, ClassHierarchyProvider cha, String[][] vars) throws FailureException, IOException {
this(writer, stackMapTable(writer, method, output, cha, vars));
}
private static List<StackMapFrame> remapStackFrames(List<StackMapFrame> sm, int[] newBytecodesToOldBytecodes) {
@ -97,6 +94,8 @@ public class StackMapTableWriter extends Element {
static StackMapType item(String type) {
if (type == null) {
return Item.ITEM_Top;
} else if (type.equals(TYPE_null)) {
return Item.ITEM_Null;
} else if (type.equals(Analyzer.topType)) {
return Item.ITEM_Top;
} else if (type.equals(Analyzer.thisType)) {
@ -138,7 +137,7 @@ public class StackMapTableWriter extends Element {
static StackMapType[] trim(StackMapType[] types) {
int i = types.length-1;
while (i >= 0 && (types[i] == null || types[i] == Item.ITEM_Null)) {
while (i >= 0 && (types[i] == null || types[i] == Item.ITEM_Null || types[i] == Item.ITEM_Top)) {
i--;
}
@ -153,12 +152,24 @@ public class StackMapTableWriter extends Element {
}
}
private static String hackUnknown(String type) {
if (type == null) {
return type;
} else if (type.startsWith("[")) {
return "[" + hackUnknown(type.substring(1));
} else if ("L?;".equals(type)) {
return "Ljava/lang/Object;";
} else {
return type;
}
}
static StackMapType[] types(String[] types, boolean locals) {
StackMapType[] stackTypes = new StackMapType[ types.length ];
int x = 0;
for(int j = 0; j < types.length; j++) {
StackMapType stackType = item("L?;".equals(types[j])? "Ljava/lang/Object;": types[j]);
StackMapType stackType = item(hackUnknown(types[j]));
stackTypes[x++] = stackType;
if (locals && stackType.size() == 2) {
j++;
@ -178,13 +189,13 @@ public class StackMapTableWriter extends Element {
return false;
}
public static List<StackMapFrame> stackMapTable(ClassWriter writer, MethodData method, Output output, ClassHierarchyProvider cha) throws FailureException, IOException {
public static List<StackMapFrame> stackMapTable(ClassWriter writer, MethodData method, Output output, ClassHierarchyProvider cha, String[][] vars) throws FailureException, IOException {
List<StackMapFrame> frames = new ArrayList<StackMapFrame>();
int[] instructionToBytecode = output.getInstructionOffsets();
IInstruction[] insts = method.getInstructions();
Verifier typeChecker = new Verifier(method, instructionToBytecode);
Verifier typeChecker = new Verifier(method, instructionToBytecode, vars);
if (cha != null) {
typeChecker.setClassHierarchy(cha);
}