Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
soot.jimple.JasminClass Maven / Gradle / Ivy
package soot.jimple;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1997 - 1999 Raja Vallee-Rai
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.AbstractJasminClass;
import soot.ArrayType;
import soot.Body;
import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.G;
import soot.IntType;
import soot.IntegerType;
import soot.Local;
import soot.LongType;
import soot.Modifier;
import soot.NullType;
import soot.RefType;
import soot.ShortType;
import soot.SootClass;
import soot.SootFieldRef;
import soot.SootMethod;
import soot.SootMethodRef;
import soot.StmtAddressType;
import soot.Timers;
import soot.Trap;
import soot.Type;
import soot.TypeSwitch;
import soot.Unit;
import soot.UnitBox;
import soot.Value;
import soot.ValueBox;
import soot.VoidType;
import soot.grimp.AbstractGrimpValueSwitch;
import soot.grimp.NewInvokeExpr;
import soot.jimple.internal.StmtBox;
import soot.options.Options;
import soot.tagkit.LineNumberTag;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.ExceptionalUnitGraphFactory;
import soot.toolkits.scalar.FastColorer;
import soot.toolkits.scalar.LocalDefs;
import soot.toolkits.scalar.LocalUses;
import soot.util.Chain;
/*
* TODO This is the right JasminClass
*/
/** Methods for producing Jasmin code from Jimple. */
public class JasminClass extends AbstractJasminClass {
private static final Logger logger = LoggerFactory.getLogger(JasminClass.class);
void emit(String s, int stackChange) {
modifyStackHeight(stackChange);
okayEmit(s);
}
void modifyStackHeight(int stackChange) {
if (currentStackHeight > maxStackHeight) {
maxStackHeight = currentStackHeight;
}
currentStackHeight += stackChange;
if (currentStackHeight < 0) {
throw new RuntimeException("Stack height is negative!");
}
if (currentStackHeight > maxStackHeight) {
maxStackHeight = currentStackHeight;
}
}
public JasminClass(SootClass sootClass) {
super(sootClass);
}
@Override
protected void assignColorsToLocals(Body body) {
super.assignColorsToLocals(body);
// Call the graph colorer.
FastColorer.assignColorsToLocals(body, localToGroup, localToColor, groupToColorCount);
if (Options.v().time()) {
Timers.v().packTimer.end();
}
}
@Override
protected void emitMethodBody(SootMethod method) {
if (Options.v().time()) {
Timers.v().buildJasminTimer.end();
}
Body activeBody = method.getActiveBody();
if (!(activeBody instanceof StmtBody)) {
throw new RuntimeException("method: " + method.getName() + " has an invalid active body!");
}
StmtBody body = (StmtBody) activeBody;
body.validate();
// if(body == null)
if (Options.v().time()) {
Timers.v().buildJasminTimer.start();
}
if (Options.v().verbose()) {
logger.debug("[" + body.getMethod().getName() + "] Performing peephole optimizations...");
}
subroutineToReturnAddressSlot = new HashMap(10, 0.7f);
Chain units = body.getUnits();
// Determine the unitToLabel map
{
unitToLabel = new HashMap(units.size() * 2 + 1, 0.7f);
labelCount = 0;
for (UnitBox ubox : body.getUnitBoxes(true)) {
// Assign a label for each statement reference
StmtBox box = (StmtBox) ubox;
if (!unitToLabel.containsKey(box.getUnit())) {
unitToLabel.put(box.getUnit(), "label" + labelCount++);
}
}
}
// Emit the exceptions
for (Trap trap : body.getTraps()) {
if (trap.getBeginUnit() != trap.getEndUnit()) {
emit(".catch " + slashify(trap.getException().getName()) + " from " + unitToLabel.get(trap.getBeginUnit()) + " to "
+ unitToLabel.get(trap.getEndUnit()) + " using " + unitToLabel.get(trap.getHandlerUnit()));
}
}
int stackLimitIndex = -1;
// Determine where the locals go
{
int localCount = 0;
int[] paramSlots = new int[method.getParameterCount()];
int thisSlot = 0;
Set assignedLocals = new HashSet();
Map groupColorPairToSlot
= new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
localToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f);
assignColorsToLocals(body);
// Determine slots for 'this' and parameters
{
if (!method.isStatic()) {
thisSlot = 0;
localCount++;
}
List paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.size(); i++) {
paramSlots[i] = localCount;
localCount += sizeOfType((Type) paramTypes.get(i));
}
}
// Handle identity statements
for (Unit u : units) {
if (u instanceof IdentityStmt) {
IdentityStmt is = (IdentityStmt) u;
Value leftOp = is.getLeftOp();
if (leftOp instanceof Local) {
int slot = 0;
IdentityRef identity = (IdentityRef) is.getRightOp();
if (identity instanceof ThisRef) {
if (method.isStatic()) {
throw new RuntimeException("Attempting to use 'this' in static method");
}
slot = thisSlot;
} else if (identity instanceof ParameterRef) {
slot = paramSlots[((ParameterRef) identity).getIndex()];
} else {
// Exception ref. Skip over this
continue;
}
Local l = (Local) leftOp;
// Make this (group, color) point to the given slot,
// so that all locals of the same color can be pointed here too
groupColorPairToSlot.put(new GroupIntPair(localToGroup.get(l), localToColor.get(l)), slot);
localToSlot.put(l, slot);
assignedLocals.add(l);
}
}
}
// Assign the rest of the locals
{
for (Local local : body.getLocals()) {
if (!assignedLocals.contains(local)) {
int slot;
GroupIntPair pair = new GroupIntPair(localToGroup.get(local), localToColor.get(local));
if (groupColorPairToSlot.containsKey(pair)) {
// This local should share the same slot as the previous local with
// the same (group, color);
slot = groupColorPairToSlot.get(pair);
} else {
slot = localCount;
localCount += sizeOfType(local.getType());
groupColorPairToSlot.put(pair, slot);
}
localToSlot.put(local, slot);
assignedLocals.add(local);
}
}
int modifiers = method.getModifiers();
if (!Modifier.isNative(modifiers) && !Modifier.isAbstract(modifiers)) {
emit(" .limit stack ?");
stackLimitIndex = code.size() - 1;
emit(" .limit locals " + localCount);
}
}
}
// let's create a u-d web for the ++ peephole optimization.
ExceptionalUnitGraph stmtGraph = null;
LocalDefs ld = null;
LocalUses lu = null;
// final boolean enablePeephole = !PhaseOptions.getBoolean(options, "no-peephole");
final boolean enablePeephole = false;
if (enablePeephole) {
stmtGraph = ExceptionalUnitGraphFactory.createExceptionalUnitGraph(body);
ld = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(stmtGraph);
lu = LocalUses.Factory.newLocalUses(body, ld);
}
// Emit code in one pass
{
isEmittingMethodCode = true;
maxStackHeight = 0;
isNextGotoAJsr = false;
LOOP: for (Iterator codeIt = units.iterator(); codeIt.hasNext();) {
Stmt s = (Stmt) codeIt.next();
if (unitToLabel.containsKey(s)) {
emit(unitToLabel.get(s) + ":");
}
if (subroutineToReturnAddressSlot.containsKey(s)) {
AssignStmt assignStmt = (AssignStmt) s;
modifyStackHeight(1); // simulate the pushing of address onto the stack by the jsr
int slot = localToSlot.get(assignStmt.getLeftOp());
if (slot >= 0 && slot <= 3) {
emit("astore_" + slot, -1);
} else {
emit("astore " + slot, -1);
}
// emit("astore " + ( ( Integer ) subroutineToReturnAddressSlot.get( s ) ).intValue() );
}
PEEP: if (enablePeephole) {
// Test for postincrement operators ++ and --
// We can optimize them further.
// sanityCheck: see that we have another statement after s.
if (!(s instanceof AssignStmt) || !codeIt.hasNext()) {
break PEEP;
}
AssignStmt nextStmt;
Stmt nextNextStmt;
{
Stmt ns = (Stmt) stmtGraph.getSuccsOf(s).get(0);
if (!(ns instanceof AssignStmt)) {
break PEEP;
}
List l = stmtGraph.getSuccsOf(ns);
if (l.size() != 1) {
break PEEP;
}
nextStmt = (AssignStmt) ns;
nextNextStmt = (Stmt) l.get(0);
}
AssignStmt stmt = (AssignStmt) s;
final Value lvalue = stmt.getLeftOp();
final Value rvalue = stmt.getRightOp();
// we're looking for this pattern:
// a: = ; = +/- 1; use();
// b: = ; = +/- 1; use();
// case a is emitted when rvalue is a local;
// case b when rvalue is, eg. a field ref.
//
// we use structural equality
// for rvalue & nextStmt.getLeftOp().
if (!(lvalue instanceof Local) || !nextStmt.getLeftOp().equivTo(rvalue)
|| !(nextStmt.getRightOp() instanceof AddExpr)) {
break PEEP;
}
// make sure that nextNextStmt uses the local exactly once
{
boolean foundExactlyOnce = false;
for (ValueBox box : nextNextStmt.getUseBoxes()) {
if (box.getValue() == lvalue) {
if (!foundExactlyOnce) {
foundExactlyOnce = true;
} else {
foundExactlyOnce = false;
break;
}
}
}
if (!foundExactlyOnce) {
break PEEP;
}
}
// Specifically exclude the case where rvalue is on the lhs
// of nextNextStmt (what a mess!)
// this takes care of the extremely pathological case where
// the thing being incremented is also on the lhs of nns (!)
for (ValueBox box : nextNextStmt.getDefBoxes()) {
if (box.getValue().equivTo(rvalue)) {
break PEEP;
}
}
AddExpr addexp = (AddExpr) nextStmt.getRightOp();
{
Value op1 = addexp.getOp1();
if (!op1.equivTo(lvalue) && !op1.equivTo(rvalue)) {
break PEEP;
}
Value op2 = addexp.getOp2();
if (!(op2 instanceof IntConstant) || ((IntConstant) (op2)).value != 1) {
break PEEP;
}
}
/* check that we have two uses and that these */
/* uses live precisely in nextStmt and nextNextStmt */
/* LocalDefs tells us this: if there was no use, */
/* there would be no corresponding def. */
if (addexp.getOp1().equivTo(lvalue)) {
if (lu.getUsesOf(s).size() != 2 || ld.getDefsOfAt((Local) lvalue, nextStmt).size() != 1
|| ld.getDefsOfAt((Local) lvalue, nextNextStmt).size() != 1) {
break PEEP;
}
plusPlusState = 0;
} else {
if (lu.getUsesOf(s).size() != 1 || ld.getDefsOfAt((Local) lvalue, nextNextStmt).size() != 1) {
break PEEP;
}
plusPlusState = 10;
}
/* emit dup slot */
// logger.debug("found ++ instance:");
// logger.debug(""+s); logger.debug(""+nextStmt);
// logger.debug(""+nextNextStmt);
/* this should be redundant, but we do it */
/* just in case. */
if (!IntType.v().equals(lvalue.getType())) {
break PEEP;
}
/* our strategy is as follows: eat the */
/* two incrementing statements, push the lvalue to */
/* be incremented & its holding local on a */
/* plusPlusStack and deal with it in */
/* emitLocal. */
currentStackHeight = 0;
/* emit statements as before */
plusPlusValue = rvalue;
plusPlusHolder = (Local) lvalue;
plusPlusIncrementer = nextStmt;
/* emit new statement with quickness */
emitStmt(nextNextStmt);
/* hm. we didn't use local. emit incrementage */
if (plusPlusHolder != null) {
emitStmt(s);
emitStmt(nextStmt);
}
if (currentStackHeight != 0) {
throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
}
codeIt.next();
codeIt.next();
continue LOOP;
} // end of peephole opts.
// emit this statement
{
currentStackHeight = 0;
emitStmt(s);
if (currentStackHeight != 0) {
throw new RuntimeException("Stack has height " + currentStackHeight + " after execution of stmt: " + s);
}
}
}
isEmittingMethodCode = false;
int modifiers = method.getModifiers();
if (!Modifier.isNative(modifiers) && !Modifier.isAbstract(modifiers)) {
code.set(stackLimitIndex, " .limit stack " + maxStackHeight);
}
}
}
void emitAssignStmt(AssignStmt stmt) {
final Value lvalue = stmt.getLeftOp();
final Value rvalue = stmt.getRightOp();
// Handle simple subcase where you can use the efficient iinc bytecode
if (lvalue instanceof Local && (rvalue instanceof AddExpr || rvalue instanceof SubExpr)) {
Local l = (Local) lvalue;
BinopExpr expr = (BinopExpr) rvalue;
Value op1 = expr.getOp1();
Value op2 = expr.getOp2();
// more peephole stuff.
if (lvalue == plusPlusHolder) {
emitValue(lvalue);
plusPlusHolder = null;
plusPlusState = 0;
}
// end of peephole
if (IntType.v().equals(l.getType())) {
boolean isValidCase = false;
int x = 0;
if (op1 == l && op2 instanceof IntConstant) {
x = ((IntConstant) op2).value;
isValidCase = true;
} else if (expr instanceof AddExpr && op2 == l && op1 instanceof IntConstant) {
// Note expr can't be a SubExpr because that would be x = 3 - x
x = ((IntConstant) op1).value;
isValidCase = true;
}
if (isValidCase && x >= Short.MIN_VALUE && x <= Short.MAX_VALUE) {
emit("iinc " + localToSlot.get(l) + " " + ((expr instanceof AddExpr) ? x : -x), 0);
return;
}
}
}
lvalue.apply(new AbstractJimpleValueSwitch() {
@Override
public void caseArrayRef(ArrayRef v) {
emitValue(v.getBase());
emitValue(v.getIndex());
emitValue(rvalue);
v.getType().apply(new TypeSwitch() {
@Override
public void caseArrayType(ArrayType t) {
emit("aastore", -3);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dastore", -4);
}
@Override
public void caseFloatType(FloatType t) {
emit("fastore", -3);
}
@Override
public void caseIntType(IntType t) {
emit("iastore", -3);
}
@Override
public void caseLongType(LongType t) {
emit("lastore", -4);
}
@Override
public void caseRefType(RefType t) {
emit("aastore", -3);
}
@Override
public void caseByteType(ByteType t) {
emit("bastore", -3);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("bastore", -3);
}
@Override
public void caseCharType(CharType t) {
emit("castore", -3);
}
@Override
public void caseShortType(ShortType t) {
emit("sastore", -3);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid type: " + t);
}
});
}
@Override
public void caseInstanceFieldRef(InstanceFieldRef v) {
emitValue(v.getBase());
emitValue(rvalue);
emit("putfield " + slashify(v.getFieldRef().declaringClass().getName()) + '/' + v.getFieldRef().name() + ' '
+ jasminDescriptorOf(v.getFieldRef().type()), -1 + -sizeOfType(v.getFieldRef().type()));
}
@Override
public void caseLocal(final Local v) {
final int slot = localToSlot.get(v);
v.getType().apply(new TypeSwitch() {
private void handleIntegerType(IntegerType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("istore_" + slot, -1);
} else {
emit("istore " + slot, -1);
}
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntegerType(t);
}
@Override
public void caseByteType(ByteType t) {
handleIntegerType(t);
}
@Override
public void caseShortType(ShortType t) {
handleIntegerType(t);
}
@Override
public void caseCharType(CharType t) {
handleIntegerType(t);
}
@Override
public void caseIntType(IntType t) {
handleIntegerType(t);
}
@Override
public void caseArrayType(ArrayType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("astore_" + slot, -1);
} else {
emit("astore " + slot, -1);
}
}
@Override
public void caseDoubleType(DoubleType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("dstore_" + slot, -2);
} else {
emit("dstore " + slot, -2);
}
}
@Override
public void caseFloatType(FloatType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("fstore_" + slot, -1);
} else {
emit("fstore " + slot, -1);
}
}
@Override
public void caseLongType(LongType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("lstore_" + slot, -2);
} else {
emit("lstore " + slot, -2);
}
}
@Override
public void caseRefType(RefType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("astore_" + slot, -1);
} else {
emit("astore " + slot, -1);
}
}
@Override
public void caseStmtAddressType(StmtAddressType t) {
isNextGotoAJsr = true;
returnAddressSlot = slot;
/*
* if ( slot >= 0 && slot <= 3) emit("astore_" + slot, ); else emit("astore " + slot, );
*/
}
@Override
public void caseNullType(NullType t) {
emitValue(rvalue);
if (slot >= 0 && slot <= 3) {
emit("astore_" + slot, -1);
} else {
emit("astore " + slot, -1);
}
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid local type: " + t);
}
});
}
@Override
public void caseStaticFieldRef(StaticFieldRef v) {
SootFieldRef field = v.getFieldRef();
emitValue(rvalue);
emit("putstatic " + slashify(field.declaringClass().getName()) + '/' + field.name() + ' '
+ jasminDescriptorOf(field.type()), -sizeOfType(v.getFieldRef().type()));
}
});
}
void emitIfStmt(IfStmt stmt) {
Value cond = stmt.getCondition();
final Value op1 = ((BinopExpr) cond).getOp1();
final Value op2 = ((BinopExpr) cond).getOp2();
final String label = unitToLabel.get(stmt.getTarget());
// Handle simple subcase where op1 is null
if (op2 instanceof NullConstant || op1 instanceof NullConstant) {
if (op2 instanceof NullConstant) {
emitValue(op1);
} else {
emitValue(op2);
}
if (cond instanceof EqExpr) {
emit("ifnull " + label, -1);
} else if (cond instanceof NeExpr) {
emit("ifnonnull " + label, -1);
} else {
throw new RuntimeException("invalid condition");
}
return;
}
// Handle simple subcase where op2 is 0
if (op2 instanceof IntConstant && ((IntConstant) op2).value == 0) {
emitValue(op1);
cond.apply(new AbstractJimpleValueSwitch() {
@Override
public void caseEqExpr(EqExpr expr) {
emit("ifeq " + label, -1);
}
@Override
public void caseNeExpr(NeExpr expr) {
emit("ifne " + label, -1);
}
@Override
public void caseLtExpr(LtExpr expr) {
emit("iflt " + label, -1);
}
@Override
public void caseLeExpr(LeExpr expr) {
emit("ifle " + label, -1);
}
@Override
public void caseGtExpr(GtExpr expr) {
emit("ifgt " + label, -1);
}
@Override
public void caseGeExpr(GeExpr expr) {
emit("ifge " + label, -1);
}
});
return;
}
// Handle simple subcase where op1 is 0 (flip directions)
if (op1 instanceof IntConstant && ((IntConstant) op1).value == 0) {
emitValue(op2);
cond.apply(new AbstractJimpleValueSwitch() {
@Override
public void caseEqExpr(EqExpr expr) {
emit("ifeq " + label, -1);
}
@Override
public void caseNeExpr(NeExpr expr) {
emit("ifne " + label, -1);
}
@Override
public void caseLtExpr(LtExpr expr) {
emit("ifgt " + label, -1);
}
@Override
public void caseLeExpr(LeExpr expr) {
emit("ifge " + label, -1);
}
@Override
public void caseGtExpr(GtExpr expr) {
emit("iflt " + label, -1);
}
@Override
public void caseGeExpr(GeExpr expr) {
emit("ifle " + label, -1);
}
});
return;
}
emitValue(op1);
emitValue(op2);
cond.apply(new AbstractJimpleValueSwitch() {
@Override
public void caseEqExpr(EqExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmpeq " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmpeq " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmpeq " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmpeq " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmpeq " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("ifeq " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("ifeq " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("ifeq " + label, -1);
}
@Override
public void caseArrayType(ArrayType t) {
emit("if_acmpeq " + label, -2);
}
@Override
public void caseRefType(RefType t) {
emit("if_acmpeq " + label, -2);
}
@Override
public void caseNullType(NullType t) {
emit("if_acmpeq " + label, -2);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseNeExpr(NeExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmpne " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmpne " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmpne " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmpne " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmpne " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("ifne " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("ifne " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("ifne " + label, -1);
}
@Override
public void caseArrayType(ArrayType t) {
emit("if_acmpne " + label, -2);
}
@Override
public void caseRefType(RefType t) {
emit("if_acmpne " + label, -2);
}
@Override
public void caseNullType(NullType t) {
emit("if_acmpne " + label, -2);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type for NeExpr: " + t);
}
});
}
@Override
public void caseLtExpr(LtExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmplt " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmplt " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmplt " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmplt " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmplt " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("iflt " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("iflt " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("iflt " + label, -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseLeExpr(LeExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmple " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmple " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmple " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmple " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmple " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("ifle " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("ifle " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("ifle " + label, -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseGtExpr(GtExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmpgt " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmpgt " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmpgt " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmpgt " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmpgt " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("ifgt " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("ifgt " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("ifgt " + label, -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseGeExpr(GeExpr expr) {
op1.getType().apply(new TypeSwitch() {
@Override
public void caseIntType(IntType t) {
emit("if_icmpge " + label, -2);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("if_icmpge " + label, -2);
}
@Override
public void caseShortType(ShortType t) {
emit("if_icmpge " + label, -2);
}
@Override
public void caseCharType(CharType t) {
emit("if_icmpge " + label, -2);
}
@Override
public void caseByteType(ByteType t) {
emit("if_icmpge " + label, -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("ifge " + label, -1);
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("ifge " + label, -1);
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("ifge " + label, -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
});
}
void emitStmt(Stmt stmt) {
LineNumberTag lnTag = (LineNumberTag) stmt.getTag(LineNumberTag.NAME);
if (lnTag != null) {
emit(".line " + lnTag.getLineNumber());
}
stmt.apply(new AbstractStmtSwitch() {
@Override
public void caseAssignStmt(AssignStmt s) {
emitAssignStmt(s);
}
@Override
public void caseIdentityStmt(IdentityStmt s) {
if (s.getRightOp() instanceof CaughtExceptionRef) {
Value leftOp = s.getLeftOp();
if (leftOp instanceof Local) {
// simulate the pushing of the exception onto the stack by the jvm
modifyStackHeight(1);
int slot = localToSlot.get((Local) leftOp);
if (slot >= 0 && slot <= 3) {
emit("astore_" + slot, -1);
} else {
emit("astore " + slot, -1);
}
}
}
}
@Override
public void caseBreakpointStmt(BreakpointStmt s) {
emit("breakpoint", 0);
}
@Override
public void caseInvokeStmt(InvokeStmt s) {
emitValue(s.getInvokeExpr());
Type returnType = ((InvokeExpr) s.getInvokeExpr()).getMethodRef().returnType();
if (!VoidType.v().equals(returnType)) {
// Need to do some cleanup because this value is not used.
if (sizeOfType(returnType) == 1) {
emit("pop", -1);
} else {
emit("pop2", -2);
}
}
}
@Override
public void caseEnterMonitorStmt(EnterMonitorStmt s) {
emitValue(s.getOp());
emit("monitorenter", -1);
}
@Override
public void caseExitMonitorStmt(ExitMonitorStmt s) {
emitValue(s.getOp());
emit("monitorexit", -1);
}
@Override
public void caseGotoStmt(GotoStmt s) {
if (isNextGotoAJsr) {
emit("jsr " + unitToLabel.get(s.getTarget()));
isNextGotoAJsr = false;
subroutineToReturnAddressSlot.put(s.getTarget(), returnAddressSlot);
} else {
emit("goto " + unitToLabel.get(s.getTarget()));
}
}
@Override
public void caseIfStmt(IfStmt s) {
emitIfStmt(s);
}
@Override
public void caseLookupSwitchStmt(LookupSwitchStmt s) {
emitValue(s.getKey());
emit("lookupswitch", -1);
List targets = s.getTargets();
List lookupValues = s.getLookupValues();
for (int i = 0; i < lookupValues.size(); i++) {
emit(" " + lookupValues.get(i) + " : " + unitToLabel.get(targets.get(i)));
}
emit(" default : " + unitToLabel.get(s.getDefaultTarget()));
}
@Override
public void caseNopStmt(NopStmt s) {
emit("nop", 0);
}
@Override
public void caseRetStmt(RetStmt s) {
emit("ret " + localToSlot.get(s.getStmtAddress()), 0);
}
@Override
public void caseReturnStmt(ReturnStmt s) {
Value returnValue = s.getOp();
emitValue(returnValue);
returnValue.getType().apply(new TypeSwitch() {
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid return type " + t.toString());
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dreturn", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("freturn", -1);
}
@Override
public void caseIntType(IntType t) {
emit("ireturn", -1);
}
@Override
public void caseByteType(ByteType t) {
emit("ireturn", -1);
}
@Override
public void caseShortType(ShortType t) {
emit("ireturn", -1);
}
@Override
public void caseCharType(CharType t) {
emit("ireturn", -1);
}
@Override
public void caseBooleanType(BooleanType t) {
emit("ireturn", -1);
}
@Override
public void caseLongType(LongType t) {
emit("lreturn", -2);
}
@Override
public void caseArrayType(ArrayType t) {
emit("areturn", -1);
}
@Override
public void caseRefType(RefType t) {
emit("areturn", -1);
}
@Override
public void caseNullType(NullType t) {
emit("areturn", -1);
}
});
}
@Override
public void caseReturnVoidStmt(ReturnVoidStmt s) {
emit("return", 0);
}
@Override
public void caseTableSwitchStmt(TableSwitchStmt s) {
emitValue(s.getKey());
emit("tableswitch " + s.getLowIndex() + " ; high = " + s.getHighIndex(), -1);
for (Unit t : s.getTargets()) {
emit(" " + unitToLabel.get(t));
}
emit("default : " + unitToLabel.get(s.getDefaultTarget()));
}
@Override
public void caseThrowStmt(ThrowStmt s) {
emitValue(s.getOp());
emit("athrow", -1);
}
});
}
/* try to pre-duplicate a local and fix-up its dup_xn parameter. */
/* if we find that we're unable to proceed, we swap the dup_xn */
/* for a store pl, load pl combination */
Value plusPlusValue;
Local plusPlusHolder;
int plusPlusState;
int plusPlusPlace;
int plusPlusHeight;
Stmt plusPlusIncrementer;
/* end of plusplus stuff. */
void emitLocal(final Local v) {
final int slot = localToSlot.get(v);
v.getType().apply(new TypeSwitch() {
@Override
public void caseArrayType(ArrayType t) {
if (slot >= 0 && slot <= 3) {
emit("aload_" + slot, 1);
} else {
emit("aload " + slot, 1);
}
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid local type to load" + t);
}
@Override
public void caseDoubleType(DoubleType t) {
if (slot >= 0 && slot <= 3) {
emit("dload_" + slot, 2);
} else {
emit("dload " + slot, 2);
}
}
@Override
public void caseFloatType(FloatType t) {
if (slot >= 0 && slot <= 3) {
emit("fload_" + slot, 1);
} else {
emit("fload " + slot, 1);
}
}
// add boolean, byte, short, and char type
@Override
public void caseBooleanType(BooleanType t) {
handleIntegerType(t);
}
@Override
public void caseByteType(ByteType t) {
handleIntegerType(t);
}
@Override
public void caseShortType(ShortType t) {
handleIntegerType(t);
}
@Override
public void caseCharType(CharType t) {
handleIntegerType(t);
}
@Override
public void caseIntType(IntType t) {
handleIntegerType(t);
}
// peephole stuff appears here.
public void handleIntegerType(IntegerType t) {
if (v.equals(plusPlusHolder)) {
switch (plusPlusState) {
case 0: {
// ok, we're called upon to emit the
// ++ target, whatever it was.
// now we need to emit a statement incrementing
// the correct value.
// actually, just remember the local to be incremented.
// here ppi is of the form ppv = pph + 1
plusPlusState = 1;
emitStmt(plusPlusIncrementer);
int diff = plusPlusHeight - currentStackHeight + 1;
if (diff > 0) {
code.set(plusPlusPlace, " dup_x" + diff);
}
plusPlusHolder = null;
// afterwards we have the value on the stack.
return;
}
case 1:
plusPlusHeight = currentStackHeight;
plusPlusHolder = null;
emitValue(plusPlusValue);
plusPlusPlace = code.size();
emit("dup", 1);
return;
case 10: {
// this time we have ppi of the form ppv = ppv + 1
plusPlusState = 11;
// logger.debug("ppV "+plusPlusValue);
// logger.debug("ppH "+plusPlusHolder);
// logger.debug("ppI "+plusPlusIncrementer);
plusPlusHolder = (Local) plusPlusValue;
emitStmt(plusPlusIncrementer);
int diff = plusPlusHeight - currentStackHeight + 1;
if (diff > 0 && plusPlusState == 11) {
code.set(plusPlusPlace, " dup_x" + diff);
}
plusPlusHolder = null;
// afterwards we have the value on the stack.
return;
}
case 11:
plusPlusHeight = currentStackHeight;
plusPlusHolder = null;
emitValue(plusPlusValue);
if (plusPlusState != 11) {
emit("dup", 1);
}
plusPlusPlace = code.size();
return;
}
}
if (slot >= 0 && slot <= 3) {
emit("iload_" + slot, 1);
} else {
emit("iload " + slot, 1);
}
}
// end of peephole stuff.
@Override
public void caseLongType(LongType t) {
if (slot >= 0 && slot <= 3) {
emit("lload_" + slot, 2);
} else {
emit("lload " + slot, 2);
}
}
@Override
public void caseRefType(RefType t) {
if (slot >= 0 && slot <= 3) {
emit("aload_" + slot, 1);
} else {
emit("aload " + slot, 1);
}
}
@Override
public void caseNullType(NullType t) {
if (slot >= 0 && slot <= 3) {
emit("aload_" + slot, 1);
} else {
emit("aload " + slot, 1);
}
}
});
}
void emitValue(Value value) {
value.apply(new AbstractGrimpValueSwitch() {
@Override
public void caseAddExpr(AddExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("iadd", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("ladd", -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dadd", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("fadd", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for add");
}
});
}
@Override
public void caseAndExpr(AndExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("iand", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("land", -2);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for and");
}
});
}
@Override
public void caseArrayRef(ArrayRef v) {
emitValue(v.getBase());
emitValue(v.getIndex());
v.getType().apply(new TypeSwitch() {
@Override
public void caseArrayType(ArrayType ty) {
emit("aaload", -1);
}
@Override
public void caseBooleanType(BooleanType ty) {
emit("baload", -1);
}
@Override
public void caseByteType(ByteType ty) {
emit("baload", -1);
}
@Override
public void caseCharType(CharType ty) {
emit("caload", -1);
}
@Override
public void defaultCase(Type ty) {
throw new RuntimeException("invalid base type");
}
@Override
public void caseDoubleType(DoubleType ty) {
emit("daload", 0);
}
@Override
public void caseFloatType(FloatType ty) {
emit("faload", -1);
}
@Override
public void caseIntType(IntType ty) {
emit("iaload", -1);
}
@Override
public void caseLongType(LongType ty) {
emit("laload", 0);
}
@Override
public void caseNullType(NullType ty) {
emit("aaload", -1);
}
@Override
public void caseRefType(RefType ty) {
emit("aaload", -1);
}
@Override
public void caseShortType(ShortType ty) {
emit("saload", -1);
}
});
}
@Override
public void caseCastExpr(final CastExpr v) {
final Value op = v.getOp();
emitValue(op);
final Type toType = v.getCastType();
if (toType instanceof RefType) {
emit("checkcast " + slashify(toType.toString()), 0);
} else if (toType instanceof ArrayType) {
emit("checkcast " + jasminDescriptorOf(toType), 0);
} else {
op.getType().apply(new TypeSwitch() {
@Override
public void defaultCase(Type ty) {
throw new RuntimeException("invalid fromType " + op.getType());
}
@Override
public void caseDoubleType(DoubleType ty) {
if (IntType.v().equals(toType)) {
emit("d2i", -1);
} else if (LongType.v().equals(toType)) {
emit("d2l", 0);
} else if (FloatType.v().equals(toType)) {
emit("d2f", -1);
} else {
throw new RuntimeException("invalid toType from double: " + toType);
}
}
@Override
public void caseFloatType(FloatType ty) {
if (IntType.v().equals(toType)) {
emit("f2i", 0);
} else if (LongType.v().equals(toType)) {
emit("f2l", 1);
} else if (DoubleType.v().equals(toType)) {
emit("f2d", 1);
} else {
throw new RuntimeException("invalid toType from float: " + toType);
}
}
@Override
public void caseIntType(IntType ty) {
emitIntToTypeCast();
}
@Override
public void caseBooleanType(BooleanType ty) {
emitIntToTypeCast();
}
@Override
public void caseByteType(ByteType ty) {
emitIntToTypeCast();
}
@Override
public void caseCharType(CharType ty) {
emitIntToTypeCast();
}
@Override
public void caseShortType(ShortType ty) {
emitIntToTypeCast();
}
private void emitIntToTypeCast() {
if (ByteType.v().equals(toType)) {
emit("i2b", 0);
} else if (CharType.v().equals(toType)) {
emit("i2c", 0);
} else if (ShortType.v().equals(toType)) {
emit("i2s", 0);
} else if (FloatType.v().equals(toType)) {
emit("i2f", 0);
} else if (LongType.v().equals(toType)) {
emit("i2l", 1);
} else if (DoubleType.v().equals(toType)) {
emit("i2d", 1);
} else if (IntType.v().equals(toType)) {
// this shouldn't happen?
} else if (BooleanType.v().equals(toType)) {
// intentionally empty
} else {
throw new RuntimeException("invalid toType from int: " + toType + " " + v.toString());
}
}
@Override
public void caseLongType(LongType ty) {
if (IntType.v().equals(toType)) {
emit("l2i", -1);
} else if (FloatType.v().equals(toType)) {
emit("l2f", -1);
} else if (DoubleType.v().equals(toType)) {
emit("l2d", 0);
} else if (ByteType.v().equals(toType)) {
emit("l2i", -1);
emitIntToTypeCast();
} else if (ShortType.v().equals(toType)) {
emit("l2i", -1);
emitIntToTypeCast();
} else if (CharType.v().equals(toType)) {
emit("l2i", -1);
emitIntToTypeCast();
} else if (BooleanType.v().equals(toType)) {
emit("l2i", -1);
emitIntToTypeCast();
} else {
throw new RuntimeException("invalid toType from long: " + toType);
}
}
});
}
}
@Override
public void caseCmpExpr(CmpExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
emit("lcmp", -3);
}
@Override
public void caseCmpgExpr(CmpgExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
if (FloatType.v().equals(v.getOp1().getType())) {
emit("fcmpg", -1);
} else {
emit("dcmpg", -3);
}
}
@Override
public void caseCmplExpr(CmplExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
if (FloatType.v().equals(v.getOp1().getType())) {
emit("fcmpl", -1);
} else {
emit("dcmpl", -3);
}
}
@Override
public void caseDivExpr(DivExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("idiv", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("ldiv", -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("ddiv", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("fdiv", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for div");
}
});
}
@Override
public void caseDoubleConstant(DoubleConstant v) {
double val = v.value;
if ((val == 0) && ((1.0 / val) > 0.0)) {
emit("dconst_0", 2);
} else if (val == 1) {
emit("dconst_1", 2);
} else {
emit("ldc2_w " + doubleToString(v), 2);
}
}
@Override
public void caseFloatConstant(FloatConstant v) {
float val = v.value;
if ((val == 0) && ((1.0f / val) > 0.0f)) {
emit("fconst_0", 1);
} else if (val == 1) {
emit("fconst_1", 1);
} else if (val == 2) {
emit("fconst_2", 1);
} else {
emit("ldc " + floatToString(v), 1);
}
}
@Override
public void caseInstanceFieldRef(InstanceFieldRef v) {
emitValue(v.getBase());
SootFieldRef field = v.getFieldRef();
emit("getfield " + slashify(field.declaringClass().getName()) + '/' + field.name() + ' '
+ jasminDescriptorOf(field.type()), -1 + sizeOfType(field.type()));
}
@Override
public void caseInstanceOfExpr(InstanceOfExpr v) {
emitValue(v.getOp());
Type checkType = v.getCheckType();
if (checkType instanceof RefType) {
emit("instanceof " + slashify(checkType.toString()), 0);
} else if (checkType instanceof ArrayType) {
emit("instanceof " + jasminDescriptorOf(checkType), 0);
}
}
@Override
public void caseIntConstant(IntConstant v) {
int val = v.value;
if (val == -1) {
emit("iconst_m1", 1);
} else if (val >= 0 && val <= 5) {
emit("iconst_" + val, 1);
} else if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
emit("bipush " + val, 1);
} else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
emit("sipush " + val, 1);
} else {
emit("ldc " + v.toString(), 1);
}
}
@Override
public void caseInterfaceInvokeExpr(InterfaceInvokeExpr v) {
emitValue(v.getBase());
SootMethodRef m = v.getMethodRef();
for (int i = 0; i < m.parameterTypes().size(); i++) {
emitValue(v.getArg(i));
}
emit("invokeinterface " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m) + " "
+ (argCountOf(m) + 1), -(argCountOf(m) + 1) + sizeOfType(m.returnType()));
}
@Override
public void caseLengthExpr(LengthExpr v) {
emitValue(v.getOp());
emit("arraylength", 0);
}
@Override
public void caseLocal(Local v) {
emitLocal(v);
}
@Override
public void caseLongConstant(LongConstant v) {
long val = v.value;
if (val == 0) {
emit("lconst_0", 2);
} else if (val == 1) {
emit("lconst_1", 2);
} else {
emit("ldc2_w " + v.toString(), 2);
}
}
@Override
public void caseMulExpr(MulExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("imul", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lmul", -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dmul", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("fmul", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for mul");
}
});
}
@Override
public void caseLtExpr(LtExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emitBooleanBranch("iflt");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emitBooleanBranch("iflt");
}
private void handleIntCase() {
emit("if_icmplt", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emitBooleanBranch("iflt");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseLeExpr(LeExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emitBooleanBranch("ifle");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emitBooleanBranch("ifle");
}
private void handleIntCase() {
emit("if_icmple", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emitBooleanBranch("ifle");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseGtExpr(GtExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emitBooleanBranch("ifgt");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emitBooleanBranch("ifgt");
}
private void handleIntCase() {
emit("if_icmpgt", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emitBooleanBranch("ifgt");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseGeExpr(GeExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emitBooleanBranch("ifge");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emitBooleanBranch("ifge");
}
private void handleIntCase() {
emit("if_icmpge", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emitBooleanBranch("ifge");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseNeExpr(NeExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpne");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -1);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpne");
}
private void handleIntCase() {
emit("if_icmpne", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpne");
}
@Override
public void caseArrayType(ArrayType t) {
emitBooleanBranch("if_acmpne");
}
@Override
public void caseRefType(RefType t) {
emitBooleanBranch("if_acmpne");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseEqExpr(EqExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getOp1().getType().apply(new TypeSwitch() {
@Override
public void caseDoubleType(DoubleType t) {
emit("dcmpg", -3);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpeq");
}
@Override
public void caseFloatType(FloatType t) {
emit("fcmpg", -3);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpeq");
}
private void handleIntCase() {
emit("if_icmpeq", -2);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lcmp", -3);
emit("iconst_0", 1);
emitBooleanBranch("if_icmpeq");
}
@Override
public void caseArrayType(ArrayType t) {
emitBooleanBranch("if_acmpeq");
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("invalid type");
}
});
}
@Override
public void caseNegExpr(final NegExpr v) {
emitValue(v.getOp());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("ineg", 0);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lneg", 0);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dneg", 0);
}
@Override
public void caseFloatType(FloatType t) {
emit("fneg", 0);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for neg: " + t + ": " + v);
}
});
}
@Override
public void caseNewArrayExpr(NewArrayExpr v) {
emitValue(v.getSize());
Type baseType = v.getBaseType();
if (baseType instanceof RefType) {
emit("anewarray " + slashify(baseType.toString()), 0);
} else if (baseType instanceof ArrayType) {
emit("anewarray " + jasminDescriptorOf(baseType), 0);
} else {
emit("newarray " + baseType.toString(), 0);
}
}
@Override
public void caseNewMultiArrayExpr(NewMultiArrayExpr v) {
for (Value val : v.getSizes()) {
emitValue(val);
}
int size = v.getSizeCount();
emit("multianewarray " + jasminDescriptorOf(v.getBaseType()) + " " + size, -size + 1);
}
@Override
public void caseNewExpr(NewExpr v) {
emit("new " + slashify(v.getBaseType().toString()), 1);
}
@Override
public void caseNewInvokeExpr(NewInvokeExpr v) {
emit("new " + slashify(v.getBaseType().toString()), 1);
emit("dup", 1);
// emitValue(v.getBase());
// already on the stack
SootMethodRef m = v.getMethodRef();
for (int i = 0; i < m.parameterTypes().size(); i++) {
emitValue(v.getArg(i));
}
emit("invokespecial " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m),
-(argCountOf(m) + 1) + sizeOfType(m.returnType()));
}
@Override
public void caseNullConstant(NullConstant v) {
emit("aconst_null", 1);
}
@Override
public void caseOrExpr(OrExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("ior", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lor", -2);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for or");
}
});
}
@Override
public void caseRemExpr(RemExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("irem", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lrem", -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("drem", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("frem", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for rem");
}
});
}
@Override
public void caseShlExpr(ShlExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("ishl", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lshl", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for shl");
}
});
}
@Override
public void caseShrExpr(ShrExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("ishr", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lshr", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for shr");
}
});
}
@Override
public void caseSpecialInvokeExpr(SpecialInvokeExpr v) {
emitValue(v.getBase());
SootMethodRef m = v.getMethodRef();
for (int i = 0; i < m.parameterTypes().size(); i++) {
emitValue(v.getArg(i));
}
emit("invokespecial " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m),
-(argCountOf(m) + 1) + sizeOfType(m.returnType()));
}
@Override
public void caseStaticInvokeExpr(StaticInvokeExpr v) {
SootMethodRef m = v.getMethodRef();
for (int i = 0; i < m.parameterTypes().size(); i++) {
emitValue(v.getArg(i));
}
emit("invokestatic " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m),
-(argCountOf(m)) + sizeOfType(m.returnType()));
}
@Override
public void caseStaticFieldRef(StaticFieldRef v) {
SootFieldRef field = v.getFieldRef();
emit("getstatic " + slashify(field.declaringClass().getName()) + "/" + field.name() + " "
+ jasminDescriptorOf(field.type()), sizeOfType(field.type()));
}
@Override
public void caseStringConstant(StringConstant v) {
emit("ldc " + v.toString(), 1);
}
@Override
public void caseClassConstant(ClassConstant v) {
emit("ldc " + v.toInternalString(), 1);
}
@Override
public void caseSubExpr(SubExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("isub", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lsub", -2);
}
@Override
public void caseDoubleType(DoubleType t) {
emit("dsub", -2);
}
@Override
public void caseFloatType(FloatType t) {
emit("fsub", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for sub");
}
});
}
@Override
public void caseUshrExpr(UshrExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("iushr", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lushr", -1);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for ushr");
}
});
}
@Override
public void caseVirtualInvokeExpr(VirtualInvokeExpr v) {
emitValue(v.getBase());
SootMethodRef m = v.getMethodRef();
for (int i = 0; i < m.parameterTypes().size(); i++) {
emitValue(v.getArg(i));
}
emit("invokevirtual " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m),
-(argCountOf(m) + 1) + sizeOfType(m.returnType()));
}
@Override
public void caseXorExpr(XorExpr v) {
emitValue(v.getOp1());
emitValue(v.getOp2());
v.getType().apply(new TypeSwitch() {
private void handleIntCase() {
emit("ixor", -1);
}
@Override
public void caseIntType(IntType t) {
handleIntCase();
}
@Override
public void caseBooleanType(BooleanType t) {
handleIntCase();
}
@Override
public void caseShortType(ShortType t) {
handleIntCase();
}
@Override
public void caseCharType(CharType t) {
handleIntCase();
}
@Override
public void caseByteType(ByteType t) {
handleIntCase();
}
@Override
public void caseLongType(LongType t) {
emit("lxor", -2);
}
@Override
public void defaultCase(Type t) {
throw new RuntimeException("Invalid argument type for xor");
}
});
}
});
}
public void emitBooleanBranch(String s) {
int count;
if (s.contains("icmp") || s.contains("acmp")) {
count = -2;
} else {
count = -1;
}
emit(s + " label" + labelCount, count);
emit("iconst_0", 1);
emit("goto label" + labelCount + 1, 0);
emit("label" + labelCount++ + ":");
emit("iconst_1", 1);
emit("label" + labelCount++ + ":");
}
}