use of soot.util.ArraySet in project soot by Sable.
the class OutFlow method jimplify.
/**
* Main.v() entry point for converting list of Instructions to Jimple statements;
* performs flow analysis, constructs Jimple statements, and fixes jumps.
* @param constant_pool constant pool of ClassFile.
* @param this_class constant pool index of the CONSTANT_Class_info object for
* this' class.
* @param clearStacks if <i>true</i> semantic stacks will be deleted after
* the process is complete.
* @return <i>true</i> if all ok, <i>false</i> if there was an error.
* @see CFG#jimplify(cp_info[], int)
* @see Stmt
*/
void jimplify(cp_info[] constant_pool, int this_class) {
Code_attribute codeAttribute = method.locate_code_attribute();
Set<Instruction> handlerInstructions = new ArraySet<Instruction>();
Map<Instruction, SootClass> handlerInstructionToException = new HashMap<Instruction, SootClass>();
Map<Instruction, TypeStack> instructionToTypeStack;
Map<Instruction, TypeStack> instructionToPostTypeStack;
{
// build graph in
buildInsnCFGfromBBCFG();
// Put in successors due to exception handlers
{
for (int i = 0; i < codeAttribute.exception_table_length; i++) {
Instruction startIns = codeAttribute.exception_table[i].start_inst;
Instruction endIns = codeAttribute.exception_table[i].end_inst;
Instruction handlerIns = codeAttribute.exception_table[i].handler_inst;
handlerInstructions.add(handlerIns);
// Determine exception to catch
{
int catchType = codeAttribute.exception_table[i].catch_type;
SootClass exception;
if (catchType != 0) {
CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
name = name.replace('/', '.');
exception = cm.getSootClass(name);
} else
exception = cm.getSootClass("java.lang.Throwable");
handlerInstructionToException.put(handlerIns, exception);
}
if (startIns == endIns)
throw new RuntimeException("Empty catch range for exception handler");
Instruction ins = startIns;
for (; ; ) {
Instruction[] succs = ins.succs;
Instruction[] newsuccs = new Instruction[succs.length + 1];
System.arraycopy(succs, 0, newsuccs, 0, succs.length);
newsuccs[succs.length] = handlerIns;
ins.succs = newsuccs;
ins = ins.next;
if (ins == endIns || ins == null)
break;
}
}
}
}
Set<Instruction> reachableInstructions = new HashSet<Instruction>();
// Mark all the reachable instructions
{
LinkedList<Instruction> instructionsToVisit = new LinkedList<Instruction>();
reachableInstructions.add(firstInstruction);
instructionsToVisit.addLast(firstInstruction);
while (!instructionsToVisit.isEmpty()) {
Instruction ins = instructionsToVisit.removeFirst();
Instruction[] succs = ins.succs;
for (Instruction succ : succs) {
if (!reachableInstructions.contains(succ)) {
reachableInstructions.add(succ);
instructionsToVisit.addLast(succ);
}
}
}
}
/*
// Check to see if any instruction is unmarked.
{
BasicBlock b = cfg;
while(b != null)
{
Instruction ins = b.head;
while(ins != null)
{
if(!reachableInstructions.contains(ins))
throw new RuntimeException("Method to jimplify contains unreachable code! (not handled for now)");
ins = ins.next;
}
b = b.next;
}
}
*/
// Perform the flow analysis, and build up instructionToTypeStack and instructionToLocalArray
{
instructionToTypeStack = new HashMap<Instruction, TypeStack>();
instructionToPostTypeStack = new HashMap<Instruction, TypeStack>();
Set<Instruction> visitedInstructions = new HashSet<Instruction>();
List<Instruction> changedInstructions = new ArrayList<Instruction>();
TypeStack initialTypeStack;
// Build up initial type stack and initial local array (for the first instruction)
{
initialTypeStack = TypeStack.v();
// the empty stack with nothing on it.
}
// Get the loop cranked up.
{
instructionToTypeStack.put(firstInstruction, initialTypeStack);
visitedInstructions.add(firstInstruction);
changedInstructions.add(firstInstruction);
}
{
while (!changedInstructions.isEmpty()) {
Instruction ins = changedInstructions.get(0);
changedInstructions.remove(0);
OutFlow ret = processFlow(ins, instructionToTypeStack.get(ins), constant_pool);
instructionToPostTypeStack.put(ins, ret.typeStack);
Instruction[] successors = ins.succs;
for (Instruction s : successors) {
if (!visitedInstructions.contains(s)) {
if (handlerInstructions.contains(s)) {
TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
instructionToTypeStack.put(s, exceptionTypeStack);
} else {
instructionToTypeStack.put(s, ret.typeStack);
}
visitedInstructions.add(s);
changedInstructions.add(s);
// logger.debug("adding successor: " + s);
} else {
// logger.debug("considering successor: " + s);
TypeStack newTypeStack, oldTypeStack = instructionToTypeStack.get(s);
if (handlerInstructions.contains(s)) {
// The type stack for an instruction handler should always be that of
// single object on the stack.
TypeStack exceptionTypeStack = (TypeStack.v()).push(RefType.v(handlerInstructionToException.get(s).getName()));
newTypeStack = exceptionTypeStack;
} else {
try {
newTypeStack = ret.typeStack.merge(oldTypeStack);
} catch (RuntimeException re) {
logger.debug("Considering " + s);
throw re;
}
}
if (!newTypeStack.equals(oldTypeStack)) {
changedInstructions.add(s);
// logger.debug("requires a revisit: " + s);
}
instructionToTypeStack.put(s, newTypeStack);
}
}
}
}
}
// logger.debug("Producing Jimple code...");
// Jimplify each statement
{
BasicBlock b = cfg;
while (b != null) {
Instruction ins = b.head;
b.statements = new ArrayList<Stmt>();
List<Stmt> blockStatements = b.statements;
for (; ; ) {
List<Stmt> statementsForIns = new ArrayList<Stmt>();
if (reachableInstructions.contains(ins))
generateJimple(ins, instructionToTypeStack.get(ins), instructionToPostTypeStack.get(ins), constant_pool, statementsForIns, b);
else
statementsForIns.add(Jimple.v().newNopStmt());
if (!statementsForIns.isEmpty()) {
for (int i = 0; i < statementsForIns.size(); i++) {
units.add(statementsForIns.get(i));
blockStatements.add(statementsForIns.get(i));
}
instructionToFirstStmt.put(ins, statementsForIns.get(0));
instructionToLastStmt.put(ins, statementsForIns.get(statementsForIns.size() - 1));
}
if (ins == b.tail)
break;
ins = ins.next;
}
b = b.next;
}
}
// fix up jump targets
jimpleTargetFixup();
/*
// Print out basic blocks
{
BasicBlock b = cfg;
logger.debug("Basic blocks for: " + jmethod.getName());
while(b != null)
{
Instruction ins = b.head;
while(ins != null)
{
logger.debug(""+ins.toString());
ins = ins.next;
}
b = b.next;
}
}
*/
// Insert beginCatch/endCatch statements for exception handling
{
Map<Stmt, Stmt> targetToHandler = new HashMap<Stmt, Stmt>();
for (int i = 0; i < codeAttribute.exception_table_length; i++) {
Instruction startIns = codeAttribute.exception_table[i].start_inst;
Instruction endIns = codeAttribute.exception_table[i].end_inst;
Instruction targetIns = codeAttribute.exception_table[i].handler_inst;
if (!instructionToFirstStmt.containsKey(startIns) || (endIns != null && (!instructionToLastStmt.containsKey(endIns)))) {
throw new RuntimeException("Exception range does not coincide with jimple instructions");
}
if (!instructionToFirstStmt.containsKey(targetIns)) {
throw new RuntimeException("Exception handler does not coincide with jimple instruction");
}
SootClass exception;
// Determine exception to catch
{
int catchType = codeAttribute.exception_table[i].catch_type;
if (catchType != 0) {
CONSTANT_Class_info classinfo = (CONSTANT_Class_info) constant_pool[catchType];
String name = ((CONSTANT_Utf8_info) (constant_pool[classinfo.name_index])).convert();
name = name.replace('/', '.');
exception = cm.getSootClass(name);
} else
exception = cm.getSootClass("java.lang.Throwable");
}
Stmt newTarget;
// Insert assignment of exception
{
Stmt firstTargetStmt = instructionToFirstStmt.get(targetIns);
if (targetToHandler.containsKey(firstTargetStmt))
newTarget = targetToHandler.get(firstTargetStmt);
else {
Local local = Util.v().getLocalCreatingIfNecessary(listBody, "$stack0", UnknownType.v());
newTarget = Jimple.v().newIdentityStmt(local, Jimple.v().newCaughtExceptionRef());
// changed to account for catch blocks which are also part of normal control flow
// units.insertBefore(newTarget, firstTargetStmt);
((PatchingChain<Unit>) units).insertBeforeNoRedirect(newTarget, firstTargetStmt);
targetToHandler.put(firstTargetStmt, newTarget);
if (units.getFirst() != newTarget) {
Unit prev = (Unit) units.getPredOf(newTarget);
if (prev != null && prev.fallsThrough())
units.insertAfter(Jimple.v().newGotoStmt(firstTargetStmt), prev);
}
}
}
// Insert trap
{
Stmt firstStmt = instructionToFirstStmt.get(startIns);
Stmt afterEndStmt;
if (endIns == null) {
// A kludge which isn't really correct, but
// gets us closer to correctness (until we
// clean up the rest of Soot to properly
// represent Traps which extend to the end
// of a method): if the protected code extends
// to the end of the method, use the last Stmt
// as the endUnit of the Trap, even though
// that will leave the last unit outside
// the protected area.
afterEndStmt = (Stmt) units.getLast();
} else {
afterEndStmt = instructionToLastStmt.get(endIns);
IdentityStmt catchStart = (IdentityStmt) targetToHandler.get(afterEndStmt);
// (Cast to IdentityStmt as an assertion check.)
if (catchStart != null) {
// before the old afterEndStmt.
if (catchStart != units.getPredOf(afterEndStmt)) {
throw new IllegalStateException("Assertion failure: catchStart != pred of afterEndStmt");
}
afterEndStmt = catchStart;
}
}
Trap trap = Jimple.v().newTrap(exception, firstStmt, afterEndStmt, newTarget);
listBody.getTraps().add(trap);
}
}
}
/* convert line number table to tags attached to statements */
if (Options.v().keep_line_number()) {
HashMap<Stmt, Tag> stmtstags = new HashMap<Stmt, Tag>();
LinkedList<Stmt> startstmts = new LinkedList<Stmt>();
attribute_info[] attrs = codeAttribute.attributes;
for (attribute_info element : attrs) {
if (element instanceof LineNumberTable_attribute) {
LineNumberTable_attribute lntattr = (LineNumberTable_attribute) element;
for (line_number_table_entry element0 : lntattr.line_number_table) {
Stmt start_stmt = instructionToFirstStmt.get(element0.start_inst);
if (start_stmt != null) {
LineNumberTag lntag = new LineNumberTag(element0.line_number);
stmtstags.put(start_stmt, lntag);
startstmts.add(start_stmt);
}
}
}
}
/* if the predecessor of a statement is a caughtexcetionref,
* give it the tag of its successor */
for (Iterator<Stmt> stmtIt = new ArrayList<Stmt>(stmtstags.keySet()).iterator(); stmtIt.hasNext(); ) {
final Stmt stmt = stmtIt.next();
Stmt pred = stmt;
Tag tag = stmtstags.get(stmt);
while (true) {
pred = (Stmt) units.getPredOf(pred);
if (pred == null)
break;
if (!(pred instanceof IdentityStmt))
break;
stmtstags.put(pred, tag);
pred.addTag(tag);
}
}
/* attach line number tag to each statement. */
for (int i = 0; i < startstmts.size(); i++) {
Stmt stmt = startstmts.get(i);
Tag tag = stmtstags.get(stmt);
stmt.addTag(tag);
stmt = (Stmt) units.getSuccOf(stmt);
while (stmt != null && !stmtstags.containsKey(stmt)) {
stmt.addTag(tag);
stmt = (Stmt) units.getSuccOf(stmt);
}
}
}
}
use of soot.util.ArraySet in project soot by Sable.
the class ExceptionalUnitGraph method buildExceptionalEdges.
/**
* Method to compute the edges corresponding to exceptional control flow.
*
* @param throwAnalysis
* the source of information about the exceptions which each
* {@link Unit} may throw.
*
* @param unitToExceptionDests
* A <code>Map</code> from {@link Unit}s to {@link Collection}s
* of {@link ExceptionalUnitGraph.ExceptionDest ExceptionDest}s
* which represent the handlers that might catch exceptions
* thrown by the <code>Unit</code>. This is an ``in parameter''.
*
* @param unitToSuccs
* A <code>Map</code> from <code>Unit</code>s to {@link List}s of
* <code>Unit</code>s. This is an ``out parameter'';
* <code>buildExceptionalEdges</code> will add a mapping from
* every <code>Unit</code> in the body that may throw an
* exception that could be caught by a {@link Trap} in the body
* to a list of its exceptional successors.
*
* @param unitToPreds
* A <code>Map</code> from <code>Unit</code>s to
* <code>List</code>s of <code>Unit</code>s. This is an ``out
* parameter''; <code>buildExceptionalEdges</code> will add a
* mapping from each handler unit that may catch an exception to
* the list of <code>Unit</code>s whose exceptions it may catch.
* @param omitExceptingUnitEdges
* Indicates whether to omit exceptional edges from excepting
* units which lack side effects
*
* @return a {@link Set} of trap <code>Unit</code>s that might catch
* exceptions thrown by the first <code>Unit</code> in the
* {@link Body} associated with the graph being constructed. Such
* trap <code>Unit</code>s may need to be added to the list of heads
* (depending on your definition of heads), since they can be the
* first <code>Unit</code> in the <code>Body</code> which actually
* completes execution.
*/
protected Set<Unit> buildExceptionalEdges(ThrowAnalysis throwAnalysis, Map<Unit, Collection<ExceptionDest>> unitToExceptionDests, Map<Unit, List<Unit>> unitToSuccs, Map<Unit, List<Unit>> unitToPreds, boolean omitExceptingUnitEdges) {
Set<Unit> trapsThatAreHeads = new ArraySet<Unit>();
Unit entryPoint = unitChain.getFirst();
for (Entry<Unit, Collection<ExceptionDest>> entry : unitToExceptionDests.entrySet()) {
Unit thrower = entry.getKey();
List<Unit> throwersPreds = getUnexceptionalPredsOf(thrower);
Collection<ExceptionDest> dests = entry.getValue();
// We need to recognize:
// - caught exceptions for which we must add edges from the
// thrower's predecessors to the catcher:
// - all exceptions of non-throw instructions;
// - implicit exceptions of throw instructions.
//
// - caught exceptions where we must add edges from the
// thrower itself to the catcher:
// - any exception of non-throw instructions if
// omitExceptingUnitEdges is not set.
// - any exception of non-throw instructions with side effects.
// - explicit exceptions of throw instructions
// - implicit exceptions of throw instructions if
// omitExceptingUnitEdges is not set.
// - implicit exceptions of throw instructions with possible
// side effects (this is only possible for the grimp
// IR, where the throw's argument may be an
// expression---probably a NewInvokeExpr---which
// might have executed partially before the
// exception arose).
//
// Note that a throw instruction may be capable of throwing a given
// Throwable type both implicitly and explicitly.
//
// We track these situations using predThrowables and
// selfThrowables. Essentially predThrowables is the set
// of Throwable types to whose catchers there should be
// edges from predecessors of the thrower, while
// selfThrowables is the set of Throwable types to whose
// catchers there should be edges from the thrower itself,
// but we we take some short cuts to avoid calling
// ThrowableSet.catchableAs() when we can avoid it.
boolean alwaysAddSelfEdges = ((!omitExceptingUnitEdges) || mightHaveSideEffects(thrower));
ThrowableSet predThrowables = null;
ThrowableSet selfThrowables = null;
if (thrower instanceof ThrowInst) {
ThrowInst throwInst = (ThrowInst) thrower;
predThrowables = throwAnalysis.mightThrowImplicitly(throwInst);
selfThrowables = throwAnalysis.mightThrowExplicitly(throwInst);
} else if (thrower instanceof ThrowStmt) {
ThrowStmt throwStmt = (ThrowStmt) thrower;
predThrowables = throwAnalysis.mightThrowImplicitly(throwStmt);
selfThrowables = throwAnalysis.mightThrowExplicitly(throwStmt);
}
for (ExceptionDest dest : dests) {
if (dest.getTrap() != null) {
Unit catcher = dest.getTrap().getHandlerUnit();
RefType trapsType = dest.getTrap().getException().getType();
if (predThrowables == null || predThrowables.catchableAs(trapsType)) {
// catcher.
if (thrower == entryPoint) {
trapsThatAreHeads.add(catcher);
}
for (Unit pred : throwersPreds) {
addEdge(unitToSuccs, unitToPreds, pred, catcher);
}
}
if (alwaysAddSelfEdges || (selfThrowables != null && selfThrowables.catchableAs(trapsType))) {
addEdge(unitToSuccs, unitToPreds, thrower, catcher);
}
}
}
}
// worklist containing CFG edges that lead to such a handler.
class CFGEdge {
// If null, represents an edge to the handler
Unit head;
// from the fictitious "predecessor" of the
// very first unit in the chain. I.e., tail
// is a handler which might be reached as a
// result of an exception thrown by the
// first Unit in the Body.
Unit tail;
CFGEdge(Unit head, Unit tail) {
if (tail == null)
throw new RuntimeException("invalid CFGEdge(" + (head == null ? "null" : head.toString()) + ',' + "null" + ')');
this.head = head;
this.tail = tail;
}
@Override
public boolean equals(Object rhs) {
if (rhs == this) {
return true;
}
if (!(rhs instanceof CFGEdge)) {
return false;
}
CFGEdge rhsEdge = (CFGEdge) rhs;
return ((this.head == rhsEdge.head) && (this.tail == rhsEdge.tail));
}
@Override
public int hashCode() {
// Following Joshua Bloch's recipe in "Effective Java", Item 8:
int result = 17;
result = 37 * result + this.head.hashCode();
result = 37 * result + this.tail.hashCode();
return result;
}
}
LinkedList<CFGEdge> workList = new LinkedList<CFGEdge>();
for (Trap trap : body.getTraps()) {
Unit handlerStart = trap.getHandlerUnit();
if (mightThrowToIntraproceduralCatcher(handlerStart)) {
List<Unit> handlerPreds = getUnexceptionalPredsOf(handlerStart);
for (Unit pred : handlerPreds) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
handlerPreds = getExceptionalPredsOf(handlerStart);
for (Unit pred : handlerPreds) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
if (trapsThatAreHeads.contains(handlerStart)) {
workList.addLast(new CFGEdge(null, handlerStart));
}
}
}
// the handler's exception.
while (workList.size() > 0) {
CFGEdge edgeToThrower = workList.removeFirst();
Unit pred = edgeToThrower.head;
Unit thrower = edgeToThrower.tail;
Collection<ExceptionDest> throwerDests = getExceptionDests(thrower);
for (ExceptionDest dest : throwerDests) {
if (dest.getTrap() != null) {
Unit handlerStart = dest.getTrap().getHandlerUnit();
boolean edgeAdded = false;
if (pred == null) {
if (!trapsThatAreHeads.contains(handlerStart)) {
trapsThatAreHeads.add(handlerStart);
edgeAdded = true;
}
} else {
if (!getExceptionalSuccsOf(pred).contains(handlerStart)) {
addEdge(unitToSuccs, unitToPreds, pred, handlerStart);
edgeAdded = true;
}
}
if (edgeAdded && mightThrowToIntraproceduralCatcher(handlerStart)) {
workList.addLast(new CFGEdge(pred, handlerStart));
}
}
}
}
return trapsThatAreHeads;
}
use of soot.util.ArraySet in project soot by Sable.
the class OutFlow method jimplify.
/**
* Main.v() entry point for converting list of Instructions to Jimple statements;
* performs flow analysis, constructs Jimple statements, and fixes jumps.
* @param constant_pool constant pool of ClassFile.
* @param this_class constant pool index of the CONSTANT_Class_info object for
* this' class.
* @param bootstrap_methods_attribute
* @return <i>true</i> if all ok, <i>false</i> if there was an error.
* @see Stmt
*/
public boolean jimplify(cp_info[] constant_pool, int this_class, BootstrapMethods_attribute bootstrap_methods_attribute, JimpleBody listBody) {
this.bootstrap_methods_attribute = bootstrap_methods_attribute;
Chain<Unit> units = listBody.getUnits();
this.listBody = listBody;
this.units = units;
instructionToFirstStmt = new HashMap<Instruction, Stmt>();
instructionToLastStmt = new HashMap<Instruction, Stmt>();
jmethod = listBody.getMethod();
cm = Scene.v();
// TypeArray.setClassManager(cm);
// TypeStack.setClassManager(cm);
Set<Local> initialLocals = new ArraySet<Local>();
List<Type> parameterTypes = jmethod.getParameterTypes();
// Initialize nameToLocal which is an index*Type->Local map, which is used
// to determine local in bytecode references.
{
Code_attribute ca = method.locate_code_attribute();
LocalVariableTable_attribute la = ca.findLocalVariableTable();
LocalVariableTypeTable_attribute lt = ca.findLocalVariableTypeTable();
Util.v().bodySetup(la, lt, constant_pool);
boolean isStatic = Modifier.isStatic(jmethod.getModifiers());
int currentLocalIndex = 0;
// Initialize the 'this' variable
{
if (!isStatic) {
Local local = Util.v().getLocalForParameter(listBody, currentLocalIndex);
currentLocalIndex++;
units.add(Jimple.v().newIdentityStmt(local, Jimple.v().newThisRef(jmethod.getDeclaringClass().getType())));
}
}
// Initialize parameters
{
Iterator<Type> typeIt = parameterTypes.iterator();
int argCount = 0;
while (typeIt.hasNext()) {
Local local = Util.v().getLocalForParameter(listBody, currentLocalIndex);
Type type = typeIt.next();
initialLocals.add(local);
units.add(Jimple.v().newIdentityStmt(local, Jimple.v().newParameterRef(type, argCount)));
if (type.equals(DoubleType.v()) || type.equals(LongType.v())) {
currentLocalIndex += 2;
} else {
currentLocalIndex += 1;
}
argCount++;
}
}
Util.v().resetEasyNames();
}
jimplify(constant_pool, this_class);
return true;
}
use of soot.util.ArraySet in project soot by Sable.
the class GroupIntPair method emitMethodBody.
@Override
protected void emitMethodBody(SootMethod method) {
if (Options.v().time())
Timers.v().buildJasminTimer.end();
Body activeBody = method.getActiveBody();
if (!(activeBody instanceof BafBody)) {
if (activeBody instanceof JimpleBody) {
if (Options.v().verbose()) {
logger.debug("Was expecting Baf body for " + method + " but found a Jimple body. Will convert body to Baf on the fly.");
}
activeBody = PackManager.v().convertJimpleBodyToBaf(method);
} else
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<Unit> instList = body.getUnits();
int stackLimitIndex = -1;
subroutineToReturnAddressSlot = new HashMap<Unit, Integer>(10, 0.7f);
// Determine the unitToLabel map
{
unitToLabel = new HashMap<Unit, String>(instList.size() * 2 + 1, 0.7f);
labelCount = 0;
for (UnitBox uBox : body.getUnitBoxes(true)) {
// Assign a label for each statement reference
{
InstBox box = (InstBox) uBox;
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<Unit>(body.getTraps().size());
{
for (Trap trap : body.getTraps()) {
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>();
localToSlot = new HashMap<Local, Integer>(body.getLocalCount() * 2 + 1, 0.7f);
// assignColorsToLocals(body);
// Determine slots for 'this' and parameters
{
if (!method.isStatic()) {
thisSlot = 0;
localCount++;
}
for (int i = 0; i < method.getParameterCount(); i++) {
paramSlots[i] = localCount;
localCount += sizeOfType(method.getParameterType(i));
}
}
// Handle identity statements
{
for (Unit u : instList) {
Inst s = (Inst) u;
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
{
for (Local local : body.getLocals()) {
if (assignedLocals.add(local)) {
localToSlot.put(local, new Integer(localCount));
localCount += sizeOfType(local.getType());
}
}
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
{
isEmittingMethodCode = true;
maxStackHeight = 0;
isNextGotoAJsr = false;
for (Unit u : instList) {
Inst s = (Inst) u;
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<Block> blocks = blockGraph.getBlocks();
if (blocks.size() != 0) {
// set the stack height of the entry points
List<Block> entryPoints = ((DirectedGraph<Block>) blockGraph).getHeads();
for (Block entryBlock : entryPoints) {
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);
}
// entryPoints list as roots
for (Block nextBlock : entryPoints) {
calculateStackHeight(nextBlock);
calculateLogicalStackHeightCheck(nextBlock);
}
}
}
}
if (!Modifier.isNative(method.getModifiers()) && !Modifier.isAbstract(method.getModifiers()))
code.set(stackLimitIndex, " .limit stack " + maxStackHeight);
}
// emit code attributes
{
for (Tag t : body.getTags()) {
if (t instanceof JasminAttribute) {
emit(".code_attribute " + t.getName() + " \"" + ((JasminAttribute) t).getJasminValue(unitToLabel) + "\"");
}
}
}
}
Aggregations