/* Soot - a J*va Optimization Framework * Copyright (C) 1999 Patrick Lam, Patrick Pominville and Raja Vallee-Rai * * This library 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the Sable Research Group and others 1997-1999. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ package soot.baf; import soot.options.*; import soot.tagkit.*; import soot.*; import soot.jimple.*; import soot.toolkits.graph.*; import soot.util.*; import java.util.*; public class JasminClass extends AbstractJasminClass { public JasminClass(SootClass sootClass) { super(sootClass); } protected void assignColorsToLocals(Body body) { super.assignColorsToLocals(body); if(Options.v().time()) Timers.v().packTimer.end(); } protected void emitMethodBody(SootMethod method) { if(Options.v().time()) Timers.v().buildJasminTimer.end(); Body activeBody = method.getActiveBody(); if(!(activeBody instanceof BafBody)) throw new RuntimeException("method: " + method.getName() + " has an invalid active body!"); BafBody body = (BafBody) activeBody; if(body == null) throw new RuntimeException("method: " + method.getName() + " has no active body!"); if(Options.v().time()) Timers.v().buildJasminTimer.start(); Chain instList = body.getUnits(); int stackLimitIndex = -1; subroutineToReturnAddressSlot = new HashMap<Unit, Integer>(10, 0.7f); // Determine the unitToLabel map { Iterator boxIt = body.getUnitBoxes(true).iterator(); unitToLabel = new HashMap(instList.size() * 2 + 1, 0.7f); labelCount = 0; while(boxIt.hasNext()) { // Assign a label for each statement reference { InstBox box = (InstBox) boxIt.next(); if(!unitToLabel.containsKey(box.getUnit())) unitToLabel.put(box.getUnit(), "label" + labelCount++); } } } // Emit the exceptions, recording the Units at the beginning // of handlers so that later on we can recognize blocks that // begin with an exception on the stack. Set<Unit> handlerUnits = new ArraySet(body.getTraps().size()); { Iterator trapIt = body.getTraps().iterator(); while(trapIt.hasNext()) { Trap trap = (Trap) trapIt.next(); handlerUnits.add(trap.getHandlerUnit()); 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())); } } } // Determine where the locals go { int localCount = 0; int[] paramSlots = new int[method.getParameterCount()]; int thisSlot = 0; Set<Local> assignedLocals = new HashSet<Local>(); Map groupColorPairToSlot = new HashMap(body.getLocalCount() * 2 + 1, 0.7f); localToSlot = new HashMap<Local, Integer>(body.getLocalCount() * 2 + 1, 0.7f); //assignColorsToLocals(body); // Determine slots for 'this' and parameters { List paramTypes = method.getParameterTypes(); if(!method.isStatic()) { thisSlot = 0; localCount++; } for(int i = 0; i < paramTypes.size(); i++) { paramSlots[i] = localCount; localCount += sizeOfType((Type) paramTypes.get(i)); } } // Handle identity statements { Iterator instIt = instList.iterator(); while(instIt.hasNext()) { Inst s = (Inst) instIt.next(); if(s instanceof IdentityInst && ((IdentityInst) s).getLeftOp() instanceof Local) { Local l = (Local) ((IdentityInst) s).getLeftOp(); IdentityRef identity = (IdentityRef) ((IdentityInst) s).getRightOp(); int slot = 0; 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; } localToSlot.put(l, new Integer(slot)); assignedLocals.add(l); } } } // Assign the rest of the locals { Iterator localIt = body.getLocals().iterator(); while(localIt.hasNext()) { Local local = (Local) localIt.next(); if(!assignedLocals.contains(local)) { localToSlot.put(local, new Integer(localCount)); localCount += sizeOfType((Type)local.getType()); assignedLocals.add(local); } } if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) { emit(" .limit stack ?"); stackLimitIndex = code.size() - 1; emit(" .limit locals " + localCount); } } } // Emit code in one pass { Iterator codeIt = instList.iterator(); isEmittingMethodCode = true; maxStackHeight = 0; isNextGotoAJsr = false; while(codeIt.hasNext()) { Inst s = (Inst) codeIt.next(); if(unitToLabel.containsKey(s)) emit(unitToLabel.get(s) + ":"); // emit this statement { emitInst(s); } } isEmittingMethodCode = false; // calculate max stack height { maxStackHeight = 0; if(activeBody.getUnits().size() != 0 ) { BlockGraph blockGraph = new BriefBlockGraph(activeBody); List blocks = blockGraph.getBlocks(); if(blocks.size() != 0) { // set the stack height of the entry points List entryPoints = ((DirectedGraph)blockGraph).getHeads(); Iterator entryIt = entryPoints.iterator(); while(entryIt.hasNext()) { Block entryBlock = (Block) entryIt.next(); Integer initialHeight; if(handlerUnits.contains(entryBlock.getHead())) { initialHeight = new Integer(1); } else { initialHeight = new Integer(0); } if (blockToStackHeight == null){ blockToStackHeight = new HashMap<Block, Integer>(); } blockToStackHeight.put(entryBlock, initialHeight); if (blockToLogicalStackHeight == null){ blockToLogicalStackHeight = new HashMap<Block, Integer>(); } blockToLogicalStackHeight.put(entryBlock, initialHeight); } // dfs the block graph using the blocks in the entryPoints list as roots entryIt = entryPoints.iterator(); while(entryIt.hasNext()) { Block nextBlock = (Block) entryIt.next(); calculateStackHeight(nextBlock); calculateLogicalStackHeightCheck(nextBlock); } } } } if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers())) code.set(stackLimitIndex, " .limit stack " + maxStackHeight); } // emit code attributes { Iterator it = body.getTags().iterator(); while(it.hasNext()) { Tag t = (Tag) it.next(); if(t instanceof JasminAttribute) { emit(".code_attribute " + t.getName() +" \"" + ((JasminAttribute) t).getJasminValue(unitToLabel) +"\""); } } } } void emitInst(Inst inst) { inst.apply(new InstSwitch() { public void caseReturnVoidInst(ReturnVoidInst i) { emit("return"); } public void caseReturnInst(ReturnInst i) { i.getOpType().apply(new TypeSwitch() { public void defaultCase(Type t) { throw new RuntimeException("invalid return type " + t.toString()); } public void caseDoubleType(DoubleType t) { emit("dreturn"); } public void caseFloatType(FloatType t) { emit("freturn"); } public void caseIntType(IntType t) { emit("ireturn"); } public void caseByteType(ByteType t) { emit("ireturn"); } public void caseShortType(ShortType t) { emit("ireturn"); } public void caseCharType(CharType t) { emit("ireturn"); } public void caseBooleanType(BooleanType t) { emit("ireturn"); } public void caseLongType(LongType t) { emit("lreturn"); } public void caseArrayType(ArrayType t) { emit("areturn"); } public void caseRefType(RefType t) { emit("areturn"); } public void caseNullType(NullType t) { emit("areturn"); } }); } public void caseNopInst(NopInst i) { emit ("nop"); } public void caseEnterMonitorInst(EnterMonitorInst i) { emit ("monitorenter"); } public void casePopInst(PopInst i) { if(i.getWordCount() == 2) { emit("pop2"); } else emit("pop"); } public void caseExitMonitorInst(ExitMonitorInst i) { emit ("monitorexit"); } public void caseGotoInst(GotoInst i) { emit("goto " + unitToLabel.get(i.getTarget())); } public void caseJSRInst(JSRInst i) { emit("jsr " + unitToLabel.get(i.getTarget())); } public void casePushInst(PushInst i) { if (i.getConstant() instanceof IntConstant) { IntConstant v = (IntConstant)(i.getConstant()); if(v.value == -1) emit("iconst_m1"); else if(v.value >= 0 && v.value <= 5) emit("iconst_" + v.value); else if(v.value >= Byte.MIN_VALUE && v.value <= Byte.MAX_VALUE) emit("bipush " + v.value); else if(v.value >= Short.MIN_VALUE && v.value <= Short.MAX_VALUE) emit("sipush " + v.value); else emit("ldc " + v.toString()); } else if (i.getConstant() instanceof StringConstant) { emit("ldc " + i.getConstant().toString()); } else if (i.getConstant() instanceof ClassConstant) { emit("ldc_w " + ((ClassConstant)i.getConstant()).getValue()); } else if (i.getConstant() instanceof DoubleConstant) { DoubleConstant v = (DoubleConstant)(i.getConstant()); if((v.value == 0) && ((1.0/v.value) > 0.0)) emit("dconst_0"); else if(v.value == 1) emit("dconst_1"); else { String s = v.toString(); if(s.equals("#Infinity")) s="+DoubleInfinity"; if(s.equals("#-Infinity")) s="-DoubleInfinity"; if(s.equals("#NaN")) s="+DoubleNaN"; emit("ldc2_w " + s); } } else if (i.getConstant() instanceof FloatConstant) { FloatConstant v = (FloatConstant)(i.getConstant()); if((v.value == 0) && ((1.0f/v.value) > 1.0f)) emit("fconst_0"); else if(v.value == 1) emit("fconst_1"); else if(v.value == 2) emit("fconst_2"); else { String s = v.toString(); if(s.equals("#InfinityF")) s="+FloatInfinity"; if(s.equals("#-InfinityF")) s="-FloatInfinity"; if(s.equals("#NaNF")) s="+FloatNaN"; emit("ldc " + s); } } else if (i.getConstant() instanceof LongConstant) { LongConstant v = (LongConstant)(i.getConstant()); if(v.value == 0) emit("lconst_0"); else if(v.value == 1) emit("lconst_1"); else emit("ldc2_w " + v.toString()); } else if (i.getConstant() instanceof NullConstant) emit("aconst_null"); else throw new RuntimeException("unsupported opcode"); } public void caseIdentityInst(IdentityInst i) { if(i.getRightOp() instanceof CaughtExceptionRef && i.getLeftOp() instanceof Local) { int slot = localToSlot.get(i.getLeftOp()).intValue(); if(slot >= 0 && slot <= 3) emit("astore_" + slot); else emit("astore " + slot); } } public void caseStoreInst(StoreInst i) { final int slot = localToSlot.get(i.getLocal()).intValue(); i.getOpType().apply(new TypeSwitch() { public void caseArrayType(ArrayType t) { if(slot >= 0 && slot <= 3) emit("astore_" + slot); else emit("astore " + slot); } public void caseDoubleType(DoubleType t) { if(slot >= 0 && slot <= 3) emit("dstore_" + slot); else emit("dstore " + slot); } public void caseFloatType(FloatType t) { if(slot >= 0 && slot <= 3) emit("fstore_" + slot); else emit("fstore " + slot); } public void caseIntType(IntType t) { if(slot >= 0 && slot <= 3) emit("istore_" + slot); else emit("istore " + slot); } public void caseByteType(ByteType t) { if(slot >= 0 && slot <= 3) emit("istore_" + slot); else emit("istore " + slot); } public void caseShortType(ShortType t) { if(slot >= 0 && slot <= 3) emit("istore_" + slot); else emit("istore " + slot); } public void caseCharType(CharType t) { if(slot >= 0 && slot <= 3) emit("istore_" + slot); else emit("istore " + slot); } public void caseBooleanType(BooleanType t) { if(slot >= 0 && slot <= 3) emit("istore_" + slot); else emit("istore " + slot); } public void caseLongType(LongType t) { if(slot >= 0 && slot <= 3) emit("lstore_" + slot); else emit("lstore " + slot); } public void caseRefType(RefType t) { if(slot >= 0 && slot <= 3) emit("astore_" + slot); else emit("astore " + slot); } public void caseStmtAddressType(StmtAddressType t) { isNextGotoAJsr = true; returnAddressSlot = slot; /* if ( slot >= 0 && slot <= 3) emit("astore_" + slot, ); else emit("astore " + slot, ); */ } public void caseNullType(NullType t) { if(slot >= 0 && slot <= 3) emit("astore_" + slot); else emit("astore " + slot); } public void defaultCase(Type t) { throw new RuntimeException("Invalid local type:" + t); } }); } public void caseLoadInst(LoadInst i) { final int slot = localToSlot.get(i.getLocal()).intValue(); i.getOpType().apply(new TypeSwitch() { public void caseArrayType(ArrayType t) { if(slot >= 0 && slot <= 3) emit("aload_" + slot); else emit("aload " + slot); } public void defaultCase(Type t) { throw new RuntimeException("invalid local type to load" + t); } public void caseDoubleType(DoubleType t) { if(slot >= 0 && slot <= 3) emit("dload_" + slot); else emit("dload " + slot); } public void caseFloatType(FloatType t) { if(slot >= 0 && slot <= 3) emit("fload_" + slot); else emit("fload " + slot); } public void caseIntType(IntType t) { if(slot >= 0 && slot <= 3) emit("iload_" + slot); else emit("iload " + slot); } public void caseByteType(ByteType t) { if(slot >= 0 && slot <= 3) emit("iload_" + slot); else emit("iload " + slot); } public void caseShortType(ShortType t) { if(slot >= 0 && slot <= 3) emit("iload_" + slot); else emit("iload " + slot); } public void caseCharType(CharType t) { if(slot >= 0 && slot <= 3) emit("iload_" + slot); else emit("iload " + slot); } public void caseBooleanType(BooleanType t) { if(slot >= 0 && slot <= 3) emit("iload_" + slot); else emit("iload " + slot); } public void caseLongType(LongType t) { if(slot >= 0 && slot <= 3) emit("lload_" + slot); else emit("lload " + slot); } public void caseRefType(RefType t) { if(slot >= 0 && slot <= 3) emit("aload_" + slot); else emit("aload " + slot); } public void caseNullType(NullType t) { if(slot >= 0 && slot <= 3) emit("aload_" + slot); else emit("aload " + slot); } }); } public void caseArrayWriteInst(ArrayWriteInst i) { i.getOpType().apply(new TypeSwitch() { public void caseArrayType(ArrayType t) { emit("aastore"); } public void caseDoubleType(DoubleType t) { emit("dastore"); } public void caseFloatType(FloatType t) { emit("fastore"); } public void caseIntType(IntType t) { emit("iastore"); } public void caseLongType(LongType t) { emit("lastore"); } public void caseRefType(RefType t) { emit("aastore"); } public void caseByteType(ByteType t) { emit("bastore"); } public void caseBooleanType(BooleanType t) { emit("bastore"); } public void caseCharType(CharType t) { emit("castore"); } public void caseShortType(ShortType t) { emit("sastore"); } public void defaultCase(Type t) { throw new RuntimeException("Invalid type: " + t); }}); } public void caseArrayReadInst(ArrayReadInst i) { i.getOpType().apply(new TypeSwitch() { public void caseArrayType(ArrayType ty) { emit("aaload"); } public void caseBooleanType(BooleanType ty) { emit("baload"); } public void caseByteType(ByteType ty) { emit("baload"); } public void caseCharType(CharType ty) { emit("caload"); } public void defaultCase(Type ty) { throw new RuntimeException("invalid base type"); } public void caseDoubleType(DoubleType ty) { emit("daload"); } public void caseFloatType(FloatType ty) { emit("faload"); } public void caseIntType(IntType ty) { emit("iaload"); } public void caseLongType(LongType ty) { emit("laload"); } public void caseNullType(NullType ty) { emit("aaload"); } public void caseRefType(RefType ty) { emit("aaload"); } public void caseShortType(ShortType ty) { emit("saload"); } }); } public void caseIfNullInst(IfNullInst i) { emit("ifnull " + unitToLabel.get(i.getTarget())); } public void caseIfNonNullInst(IfNonNullInst i) { emit("ifnonnull " + unitToLabel.get(i.getTarget())); } public void caseIfEqInst(IfEqInst i) { emit("ifeq " + unitToLabel.get(i.getTarget())); } public void caseIfNeInst(IfNeInst i) { emit("ifne " + unitToLabel.get(i.getTarget())); } public void caseIfGtInst(IfGtInst i) { emit("ifgt " + unitToLabel.get(i.getTarget())); } public void caseIfGeInst(IfGeInst i) { emit("ifge " + unitToLabel.get(i.getTarget())); } public void caseIfLtInst(IfLtInst i) { emit("iflt " + unitToLabel.get(i.getTarget())); } public void caseIfLeInst(IfLeInst i) { emit("ifle " + unitToLabel.get(i.getTarget())); } public void caseIfCmpEqInst(final IfCmpEqInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmpeq " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmpeq " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmpeq " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmpeq " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmpeq " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("ifeq " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("ifeq " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("ifeq " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmpeq " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmpeq " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmpeq " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseIfCmpNeInst(final IfCmpNeInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmpne " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmpne " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmpne " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmpne " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmpne " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("ifne " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("ifne " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("ifne " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmpne " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmpne " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmpne " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseIfCmpGtInst(final IfCmpGtInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmpgt " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmpgt " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmpgt " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmpgt " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmpgt " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("ifgt " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("ifgt " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("ifgt " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmpgt " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmpgt " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmpgt " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseIfCmpGeInst(final IfCmpGeInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmpge " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmpge " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmpge " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmpge " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmpge " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("ifge " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("ifge " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("ifge " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmpge " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmpge " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmpge " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseIfCmpLtInst(final IfCmpLtInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmplt " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmplt " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmplt " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmplt " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmplt " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("iflt " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("iflt " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("iflt " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmplt " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmplt " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmplt " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseIfCmpLeInst(final IfCmpLeInst i) { i.getOpType().apply(new TypeSwitch() { public void caseIntType(IntType t) { emit("if_icmple " + unitToLabel.get(i.getTarget())); } public void caseBooleanType(BooleanType t) { emit("if_icmple " + unitToLabel.get(i.getTarget())); } public void caseShortType(ShortType t) { emit("if_icmple " + unitToLabel.get(i.getTarget())); } public void caseCharType(CharType t) { emit("if_icmple " + unitToLabel.get(i.getTarget())); } public void caseByteType(ByteType t) { emit("if_icmple " + unitToLabel.get(i.getTarget())); } public void caseDoubleType(DoubleType t) { emit("dcmpg"); emit("ifle " + unitToLabel.get(i.getTarget())); } public void caseLongType(LongType t) { emit("lcmp"); emit("ifle " + unitToLabel.get(i.getTarget())); } public void caseFloatType(FloatType t) { emit("fcmpg"); emit("ifle " + unitToLabel.get(i.getTarget())); } public void caseArrayType(ArrayType t) { emit("if_acmple " + unitToLabel.get(i.getTarget())); } public void caseRefType(RefType t) { emit("if_acmple " + unitToLabel.get(i.getTarget())); } public void caseNullType(NullType t) { emit("if_acmple " + unitToLabel.get(i.getTarget())); } public void defaultCase(Type t) { throw new RuntimeException("invalid type"); } }); } public void caseStaticGetInst(StaticGetInst i) { SootFieldRef field = i.getFieldRef(); emit("getstatic " + slashify(field.declaringClass().getName()) + "/" + field.name() + " " + jasminDescriptorOf(field.type())); } public void caseStaticPutInst(StaticPutInst i) { emit("putstatic " + slashify(i.getFieldRef().declaringClass().getName()) + "/" + i.getFieldRef().name() + " " + jasminDescriptorOf(i.getFieldRef().type())); } public void caseFieldGetInst(FieldGetInst i) { emit("getfield " + slashify(i.getFieldRef().declaringClass().getName()) + "/" + i.getFieldRef().name() + " " + jasminDescriptorOf(i.getFieldRef().type())); } public void caseFieldPutInst(FieldPutInst i) { emit("putfield " + slashify(i.getFieldRef().declaringClass().getName()) + "/" + i.getFieldRef().name() + " " + jasminDescriptorOf(i.getFieldRef().type())); } public void caseInstanceCastInst(InstanceCastInst i) { Type castType = i.getCastType(); if(castType instanceof RefType) emit("checkcast " + slashify(castType.toString())); else if(castType instanceof ArrayType) emit("checkcast " + jasminDescriptorOf(castType)); } public void caseInstanceOfInst(InstanceOfInst i) { Type checkType = i.getCheckType(); if(checkType instanceof RefType) emit("instanceof " + slashify(checkType.toString())); else if(checkType instanceof ArrayType) emit("instanceof " + jasminDescriptorOf(checkType)); } public void caseNewInst(NewInst i) { emit("new "+slashify(i.getBaseType().toString())); } public void casePrimitiveCastInst(PrimitiveCastInst i) { emit(i.toString()); } public void caseStaticInvokeInst(StaticInvokeInst i) { SootMethodRef m = i.getMethodRef(); emit("invokestatic " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m)); } public void caseVirtualInvokeInst(VirtualInvokeInst i) { SootMethodRef m = i.getMethodRef(); emit("invokevirtual " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m)); } public void caseInterfaceInvokeInst(InterfaceInvokeInst i) { SootMethodRef m = i.getMethodRef(); emit("invokeinterface " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m) + " " + (argCountOf(m) + 1)); } public void caseSpecialInvokeInst(SpecialInvokeInst i) { SootMethodRef m = i.getMethodRef(); emit("invokespecial " + slashify(m.declaringClass().getName()) + "/" + m.name() + jasminDescriptorOf(m)); } public void caseThrowInst(ThrowInst i) { emit("athrow"); } public void caseCmpInst(CmpInst i) { emit("lcmp"); } public void caseCmplInst(CmplInst i) { if(i.getOpType().equals(FloatType.v())) emit("fcmpl"); else emit("dcmpl"); } public void caseCmpgInst(CmpgInst i) { if(i.getOpType().equals(FloatType.v())) emit("fcmpg"); else emit("dcmpg"); } private void emitOpTypeInst(final String s, final OpTypeArgInst i) { i.getOpType().apply(new TypeSwitch() { private void handleIntCase() { emit("i"+s); } public void caseIntType(IntType t) { handleIntCase(); } public void caseBooleanType(BooleanType t) { handleIntCase(); } public void caseShortType(ShortType t) { handleIntCase(); } public void caseCharType(CharType t) { handleIntCase(); } public void caseByteType(ByteType t) { handleIntCase(); } public void caseLongType(LongType t) { emit("l"+s); } public void caseDoubleType(DoubleType t) { emit("d"+s); } public void caseFloatType(FloatType t) { emit("f"+s); } public void defaultCase(Type t) { throw new RuntimeException("Invalid argument type for div"); } }); } public void caseAddInst(AddInst i) { emitOpTypeInst("add", i); } public void caseDivInst(DivInst i) { emitOpTypeInst("div", i); } public void caseSubInst(SubInst i) { emitOpTypeInst("sub", i); } public void caseMulInst(MulInst i) { emitOpTypeInst("mul", i); } public void caseRemInst(RemInst i) { emitOpTypeInst("rem", i); } public void caseShlInst(ShlInst i) { emitOpTypeInst("shl", i); } public void caseAndInst(AndInst i) { emitOpTypeInst("and", i); } public void caseOrInst(OrInst i) { emitOpTypeInst("or", i); } public void caseXorInst(XorInst i) { emitOpTypeInst("xor", i); } public void caseShrInst(ShrInst i) { emitOpTypeInst("shr", i); } public void caseUshrInst(UshrInst i) { emitOpTypeInst("ushr", i); } public void caseIncInst(IncInst i) { if(((ValueBox) i.getUseBoxes().get(0)).getValue() != ((ValueBox) i.getDefBoxes().get(0)).getValue()) throw new RuntimeException("iinc def and use boxes don't match"); emit("iinc " + localToSlot.get(i.getLocal()) + " " + i.getConstant()); } public void caseArrayLengthInst(ArrayLengthInst i) { emit("arraylength"); } public void caseNegInst(NegInst i) { emitOpTypeInst("neg", i); } public void caseNewArrayInst(NewArrayInst i) { if(i.getBaseType() instanceof RefType) emit("anewarray " + slashify(i.getBaseType().toString())); else if(i.getBaseType() instanceof ArrayType) emit("anewarray " + jasminDescriptorOf(i.getBaseType())); else emit("newarray " + i.getBaseType().toString()); } public void caseNewMultiArrayInst(NewMultiArrayInst i) { emit("multianewarray " + jasminDescriptorOf(i.getBaseType()) + " " + i.getDimensionCount()); } public void caseLookupSwitchInst(LookupSwitchInst i) { emit("lookupswitch"); List lookupValues = i.getLookupValues(); List targets = i.getTargets(); for(int j = 0; j < lookupValues.size(); j++) emit(" " + lookupValues.get(j) + " : " + unitToLabel.get(targets.get(j))); emit(" default : " + unitToLabel.get(i.getDefaultTarget())); } public void caseTableSwitchInst(TableSwitchInst i) { emit("tableswitch " + i.getLowIndex() + " ; high = " + i.getHighIndex()); List targets = i.getTargets(); for(int j = 0; j < targets.size(); j++) emit(" " + unitToLabel.get(targets.get(j))); emit("default : " + unitToLabel.get(i.getDefaultTarget())); } private boolean isDwordType(Type t) { return t instanceof LongType || t instanceof DoubleType || t instanceof DoubleWordType; } public void caseDup1Inst(Dup1Inst i) { Type firstOpType = i.getOp1Type(); if (isDwordType(firstOpType)) emit("dup2"); // (form 2) else emit("dup"); } public void caseDup2Inst(Dup2Inst i) { Type firstOpType = i.getOp1Type(); Type secondOpType = i.getOp2Type(); // The first two cases have no real bytecode equivalents. // Use a pair of insts to simulate them. if(isDwordType(firstOpType)) { emit("dup2"); // (form 2) if(isDwordType(secondOpType)) { emit("dup2"); // (form 2 -- by simulation) } else emit("dup"); // also a simulation } else if(isDwordType(secondOpType)) { if(isDwordType(firstOpType)) { emit("dup2"); // (form 2) } else emit("dup"); emit("dup2"); // (form 2 -- complete the simulation) } else { emit("dup2"); // form 1 } } public void caseDup1_x1Inst(Dup1_x1Inst i) { Type opType = i.getOp1Type(); Type underType = i.getUnder1Type(); if(isDwordType(opType)) { if(isDwordType(underType)) { emit("dup2_x2"); // (form 4) } else emit("dup2_x1"); // (form 2) } else { if(isDwordType(underType)) emit("dup_x2"); // (form 2) else emit("dup_x1"); // (only one form) } } public void caseDup1_x2Inst(Dup1_x2Inst i) { Type opType = i.getOp1Type(); Type under1Type = i.getUnder1Type(); Type under2Type = i.getUnder2Type(); // 07-20-2006 Michael Batchelder // NOW handling all types of dup1_x2 /* From VM Spec: cat1 = category 1 (word type) cat2 = category 2 (doubleword) Form 1: [..., cat1_value3, cat1_value2, cat1_value1]->[..., cat1_value2, cat1_value1, cat1_value3, cat1_value2, cat1_value1] Form 2: [..., cat1_value2, cat2_value1]->[..., cat2_value1, cat1_value2, cat2_value1] */ if (isDwordType(opType)) { if (!isDwordType(under1Type) && !isDwordType(under2Type)) emit("dup2_x2"); // (form 2) else throw new RuntimeException("magic not implemented yet"); } else { if (isDwordType(under1Type) || isDwordType(under2Type)) throw new RuntimeException("magic not implemented yet"); } emit("dup_x2"); // (form 1) } public void caseDup2_x1Inst(Dup2_x1Inst i) { Type op1Type = i.getOp1Type(); Type op2Type = i.getOp2Type(); Type under1Type = i.getUnder1Type(); // 07-20-2006 Michael Batchelder // NOW handling all types of dup2_x1 /* From VM Spec: cat1 = category 1 (word type) cat2 = category 2 (doubleword) Form 1: [..., cat1_value3, cat1_value2, cat1_value1]->[..., cat1_value2, cat1_value1, cat1_value3, cat1_value2, cat1_value1] Form 2: [..., cat1_value2, cat2_value1]->[..., cat2_value1, cat1_value2, cat2_value1] */ if (isDwordType(under1Type)) { if (!isDwordType(op1Type) && !isDwordType(op2Type)) throw new RuntimeException("magic not implemented yet"); else emit("dup2_x2"); // (form 3) } else { if ((isDwordType(op1Type) && op2Type != null) || isDwordType(op2Type)) throw new RuntimeException("magic not implemented yet"); } emit("dup2_x1"); // (form 1) } public void caseDup2_x2Inst(Dup2_x2Inst i) { Type op1Type = i.getOp1Type(); Type op2Type = i.getOp2Type(); Type under1Type = i.getUnder1Type(); Type under2Type = i.getUnder2Type(); // 07-20-2006 Michael Batchelder // NOW handling all types of dup2_x2 /* From VM Spec: cat1 = category 1 (word type) cat2 = category 2 (doubleword) Form 1: [..., cat1_value4, cat1_value3, cat1_value2, cat1_value1]->[..., cat1_value2, cat1_value1, cat1_value4, cat1_value3, cat1_value2, cat1_value1] Form 2: [..., cat1_value3, cat1_value2, cat2_value1]->[ ..., cat2_value1, cat1_value3, cat1_value2, cat2_value1] Form 3: [..., cat2_value3, cat1_value2, cat1_value1]->[..., cat1_value2, cat1_value1, cat2_value3, cat1_value2, cat1_value1] Form 4: [..., cat2_value2, cat2_value1]->[..., cat2_value1, cat2_value2, cat2_value1] */ boolean malformed = true; if (isDwordType(op1Type)) { if (op2Type == null && under1Type != null) if( (under2Type == null && isDwordType(under1Type)) || (!isDwordType(under1Type) && under2Type != null && !isDwordType(under2Type))) malformed = false; } else if (op1Type != null && op2Type != null && !isDwordType(op2Type)) { if ( (under2Type == null && isDwordType(under1Type)) || (under1Type !=null && !isDwordType(under1Type) && under2Type !=null && !isDwordType(under2Type))) malformed = false; } if (malformed) throw new RuntimeException("magic not implemented yet"); emit("dup2_x2"); // (form 1) } public void caseSwapInst(SwapInst i) { emit("swap"); } }); } private void calculateStackHeight(Block aBlock) { Iterator it = aBlock.iterator(); int blockHeight = blockToStackHeight.get(aBlock).intValue(); if( blockHeight > maxStackHeight) { maxStackHeight = blockHeight; } while(it.hasNext()) { Inst nInst = (Inst) it.next(); blockHeight -= nInst.getInMachineCount(); if(blockHeight < 0 ){ throw new RuntimeException("Negative Stack height has been attained in :"+ aBlock.getBody().getMethod().getSignature() +" \n" + "StackHeight: " + blockHeight + "\n" + "At instruction:" + nInst + "\n" + "Block:\n" + aBlock + "\n\nMethod: " + aBlock.getBody().getMethod().getName() + "\n" + aBlock.getBody().getMethod() ); } blockHeight += nInst.getOutMachineCount(); if( blockHeight > maxStackHeight) { maxStackHeight = blockHeight; } //G.v().out.println(">>> " + nInst + " " + blockHeight); } Iterator succs = aBlock.getSuccs().iterator(); while(succs.hasNext()) { Block b = (Block) succs.next(); Integer i = blockToStackHeight.get(b); if(i != null) { if(i.intValue() != blockHeight) { throw new RuntimeException(aBlock.getBody().getMethod().getSignature() + ": incoherent stack height at block merge point " + b + aBlock + "\ncomputed blockHeight == " + blockHeight + " recorded blockHeight = " + i.intValue()); } } else { blockToStackHeight.put(b, new Integer(blockHeight)); calculateStackHeight(b); } } } private void calculateLogicalStackHeightCheck(Block aBlock) { Iterator it = aBlock.iterator(); int blockHeight = blockToLogicalStackHeight.get(aBlock).intValue(); while(it.hasNext()) { Inst nInst = (Inst) it.next(); blockHeight -= nInst.getInCount(); if(blockHeight < 0 ){ throw new RuntimeException("Negative Stack Logical height has been attained: \n" + "StackHeight: " + blockHeight + "\nAt instruction:" + nInst + "\nBlock:\n" + aBlock + "\n\nMethod: " + aBlock.getBody().getMethod().getName() + "\n" + aBlock.getBody().getMethod() ); } blockHeight += nInst.getOutCount(); //G.v().out.println(">>> " + nInst + " " + blockHeight); } Iterator succs = aBlock.getSuccs().iterator(); while(succs.hasNext()) { Block b = (Block) succs.next(); Integer i = blockToLogicalStackHeight.get(b); if(i != null) { if(i.intValue() != blockHeight) { throw new RuntimeException("incoherent logical stack height at block merge point " + b + aBlock); } } else { blockToLogicalStackHeight.put(b, new Integer(blockHeight)); calculateLogicalStackHeightCheck(b); } } } } class GroupIntPair { Object group; int x; GroupIntPair(Object group, int x) { this.group = group; this.x = x; } public boolean equals(Object other) { if(other instanceof GroupIntPair) return ((GroupIntPair) other).group.equals(this.group) && ((GroupIntPair) other).x == this.x; else return false; } public int hashCode() { return group.hashCode() + 1013 * x; } }