use of com.android.dx.rop.code.SourcePosition in project J2ME-Loader by nikita36078.
the class DebugInfoEncoder method emitPosition.
/**
* Emits the necessary byte sequences to emit the given position table
* entry. This will typically be a single special opcode, although
* it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
*
* @param entry position entry to emit.
* @throws IOException
*/
private void emitPosition(PositionList.Entry entry) throws IOException {
SourcePosition pos = entry.getPosition();
int newLine = pos.getLine();
int newAddress = entry.getAddress();
int opcode;
int deltaLines = newLine - line;
int deltaAddress = newAddress - address;
if (deltaAddress < 0) {
throw new RuntimeException("Position entries must be in ascending address order");
}
if ((deltaLines < DBG_LINE_BASE) || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE - 1))) {
emitAdvanceLine(deltaLines);
deltaLines = 0;
}
opcode = computeOpcode(deltaLines, deltaAddress);
if ((opcode & ~0xff) > 0) {
emitAdvancePc(deltaAddress);
deltaAddress = 0;
opcode = computeOpcode(deltaLines, deltaAddress);
if ((opcode & ~0xff) > 0) {
emitAdvanceLine(deltaLines);
deltaLines = 0;
opcode = computeOpcode(deltaLines, deltaAddress);
}
}
output.writeByte(opcode);
line += deltaLines;
address += deltaAddress;
if (annotateTo != null || debugPrint != null) {
annotate(1, String.format("%04x: line %d", address, line));
}
}
use of com.android.dx.rop.code.SourcePosition in project buck by facebook.
the class Ropper method addExceptionSetupBlocks.
/**
* Creates the exception handler setup blocks. "maxLocals"
* below is because that's the register number corresponding
* to the sole element on a one-deep stack (which is the
* situation at the start of an exception handler block).
*/
private void addExceptionSetupBlocks() {
int len = catchInfos.length;
for (int i = 0; i < len; i++) {
CatchInfo catches = catchInfos[i];
if (catches != null) {
for (ExceptionHandlerSetup one : catches.getSetups()) {
Insn proto = labelToBlock(i).getFirstInsn();
SourcePosition pos = proto.getPosition();
InsnList il = new InsnList(2);
Insn insn = new PlainInsn(Rops.opMoveException(one.getCaughtType()), pos, RegisterSpec.make(maxLocals, one.getCaughtType()), RegisterSpecList.EMPTY);
il.set(0, insn);
insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
il.set(1, insn);
il.setImmutable();
BasicBlock bb = new BasicBlock(one.getLabel(), il, IntList.makeImmutable(i), i);
addBlock(bb, startFrames[i].getSubroutines());
}
}
}
}
use of com.android.dx.rop.code.SourcePosition in project buck by facebook.
the class Ropper method processBlock.
/**
* Processes the given block.
*
* @param block {@code non-null;} block to process
* @param frame {@code non-null;} start frame for the block
* @param workSet {@code non-null;} bits representing work to do,
* which this method may add to
*/
private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
// Prepare the list of caught exceptions for this block.
ByteCatchList catches = block.getCatches();
machine.startBlock(catches.toRopCatchList());
/*
* Using a copy of the given frame, simulate each instruction,
* calling into machine for each.
*/
frame = frame.copy();
sim.simulate(block, frame);
frame.setImmutable();
int extraBlockCount = machine.getExtraBlockCount();
ArrayList<Insn> insns = machine.getInsns();
int insnSz = insns.size();
/*
* Merge the frame into each possible non-exceptional
* successor.
*/
int catchSz = catches.size();
IntList successors = block.getSuccessors();
int startSuccessorIndex;
Subroutine calledSubroutine = null;
if (machine.hasJsr()) {
/*
* If this frame ends in a JSR, only merge our frame with
* the subroutine start, not the subroutine's return target.
*/
startSuccessorIndex = 1;
int subroutineLabel = successors.get(1);
if (subroutines[subroutineLabel] == null) {
subroutines[subroutineLabel] = new Subroutine(subroutineLabel);
}
subroutines[subroutineLabel].addCallerBlock(block.getLabel());
calledSubroutine = subroutines[subroutineLabel];
} else if (machine.hasRet()) {
/*
* This block ends in a ret, which means it's the final block
* in some subroutine. Ultimately, this block will be copied
* and inlined for each call and then disposed of.
*/
ReturnAddress ra = machine.getReturnAddress();
int subroutineLabel = ra.getSubroutineAddress();
if (subroutines[subroutineLabel] == null) {
subroutines[subroutineLabel] = new Subroutine(subroutineLabel, block.getLabel());
} else {
subroutines[subroutineLabel].addRetBlock(block.getLabel());
}
successors = subroutines[subroutineLabel].getSuccessors();
subroutines[subroutineLabel].mergeToSuccessors(frame, workSet);
// Skip processing below since we just did it.
startSuccessorIndex = successors.size();
} else if (machine.wereCatchesUsed()) {
/*
* If there are catches, then the first successors
* (which will either be all of them or all but the last one)
* are catch targets.
*/
startSuccessorIndex = catchSz;
} else {
startSuccessorIndex = 0;
}
int succSz = successors.size();
for (int i = startSuccessorIndex; i < succSz; i++) {
int succ = successors.get(i);
try {
mergeAndWorkAsNecessary(succ, block.getLabel(), calledSubroutine, frame, workSet);
} catch (SimException ex) {
ex.addContext("...while merging to block " + Hex.u2(succ));
throw ex;
}
}
if ((succSz == 0) && machine.returns()) {
/*
* The block originally contained a return, but it has
* been made to instead end with a goto, and we need to
* tell it at this point that its sole successor is the
* return block. This has to happen after the merge loop
* above, since, at this point, the return block doesn't
* actually exist; it gets synthesized at the end of
* processing the original blocks.
*/
successors = IntList.makeImmutable(getSpecialLabel(RETURN));
succSz = 1;
}
int primarySucc;
if (succSz == 0) {
primarySucc = -1;
} else {
primarySucc = machine.getPrimarySuccessorIndex();
if (primarySucc >= 0) {
primarySucc = successors.get(primarySucc);
}
}
/*
* This variable is true only when the method is synchronized and
* the block being processed can possibly throw an exception.
*/
boolean synch = isSynchronized() && machine.canThrow();
if (synch || (catchSz != 0)) {
/*
* Deal with exception handlers: Merge an exception-catch
* frame into each possible exception handler, and
* construct a new set of successors to point at the
* exception handler setup blocks (which get synthesized
* at the very end of processing).
*/
boolean catchesAny = false;
IntList newSucc = new IntList(succSz);
for (int i = 0; i < catchSz; i++) {
ByteCatchList.Item one = catches.get(i);
CstType exceptionClass = one.getExceptionClass();
int targ = one.getHandlerPc();
catchesAny |= (exceptionClass == CstType.OBJECT);
Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
try {
mergeAndWorkAsNecessary(targ, block.getLabel(), null, f, workSet);
} catch (SimException ex) {
ex.addContext("...while merging exception to block " + Hex.u2(targ));
throw ex;
}
/*
* Set up the exception handler type.
*/
CatchInfo handlers = catchInfos[targ];
if (handlers == null) {
handlers = new CatchInfo();
catchInfos[targ] = handlers;
}
ExceptionHandlerSetup handler = handlers.getSetup(exceptionClass.getClassType());
/*
* The synthesized exception setup block will have the label given by handler.
*/
newSucc.add(handler.getLabel());
}
if (synch && !catchesAny) {
/*
* The method is synchronized and this block doesn't
* already have a catch-all handler, so add one to the
* end, both in the successors and in the throwing
* instruction(s) at the end of the block (which is where
* the caught classes live).
*/
newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
synchNeedsExceptionHandler = true;
for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
Insn insn = insns.get(i);
if (insn.canThrow()) {
insn = insn.withAddedCatch(Type.OBJECT);
insns.set(i, insn);
}
}
}
if (primarySucc >= 0) {
newSucc.add(primarySucc);
}
newSucc.setImmutable();
successors = newSucc;
}
// Construct the final resulting block(s), and store it (them).
int primarySuccListIndex = successors.indexOf(primarySucc);
/*
* If there are any extra blocks, work backwards through the
* list of instructions, adding single-instruction blocks, and
* resetting the successors variables as appropriate.
*/
for (; /*extraBlockCount*/
extraBlockCount > 0; extraBlockCount--) {
/*
* Some of the blocks that the RopperMachine wants added
* are for move-result insns, and these need goto insns as well.
*/
Insn extraInsn = insns.get(--insnSz);
boolean needsGoto = extraInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE;
InsnList il = new InsnList(needsGoto ? 2 : 1);
IntList extraBlockSuccessors = successors;
il.set(0, extraInsn);
if (needsGoto) {
il.set(1, new PlainInsn(Rops.GOTO, extraInsn.getPosition(), null, RegisterSpecList.EMPTY));
/*
* Obviously, this block won't be throwing an exception
* so it should only have one successor.
*/
extraBlockSuccessors = IntList.makeImmutable(primarySucc);
}
il.setImmutable();
int label = getAvailableLabel();
BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors, primarySucc);
// All of these extra blocks will be in the same subroutine
addBlock(bb, frame.getSubroutines());
successors = successors.mutableCopy();
successors.set(primarySuccListIndex, label);
successors.setImmutable();
primarySucc = label;
}
Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
/*
* Add a goto to the end of the block if it doesn't already
* end with a branch, to maintain the invariant that all
* blocks end with a branch of some sort or other. Note that
* it is possible for there to be blocks for which no
* instructions were ever output (e.g., only consist of pop*
* in the original Java bytecode).
*/
if ((lastInsn == null) || (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO : lastInsn.getPosition();
insns.add(new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY));
insnSz++;
}
/*
* Construct a block for the remaining instructions (which in
* the usual case is all of them).
*/
InsnList il = new InsnList(insnSz);
for (int i = 0; i < insnSz; i++) {
il.set(i, insns.get(i));
}
il.setImmutable();
BasicBlock bb = new BasicBlock(block.getLabel(), il, successors, primarySucc);
addOrReplaceBlock(bb, frame.getSubroutines());
}
use of com.android.dx.rop.code.SourcePosition in project buck by facebook.
the class DebugInfoEncoder method emitPosition.
/**
* Emits the necessary byte sequences to emit the given position table
* entry. This will typically be a single special opcode, although
* it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE.
*
* @param entry position entry to emit.
* @throws IOException
*/
private void emitPosition(PositionList.Entry entry) throws IOException {
SourcePosition pos = entry.getPosition();
int newLine = pos.getLine();
int newAddress = entry.getAddress();
int opcode;
int deltaLines = newLine - line;
int deltaAddress = newAddress - address;
if (deltaAddress < 0) {
throw new RuntimeException("Position entries must be in ascending address order");
}
if ((deltaLines < DBG_LINE_BASE) || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE - 1))) {
emitAdvanceLine(deltaLines);
deltaLines = 0;
}
opcode = computeOpcode(deltaLines, deltaAddress);
if ((opcode & ~0xff) > 0) {
emitAdvancePc(deltaAddress);
deltaAddress = 0;
opcode = computeOpcode(deltaLines, deltaAddress);
if ((opcode & ~0xff) > 0) {
emitAdvanceLine(deltaLines);
deltaLines = 0;
opcode = computeOpcode(deltaLines, deltaAddress);
}
}
output.writeByte(opcode);
line += deltaLines;
address += deltaAddress;
if (annotateTo != null || debugPrint != null) {
annotate(1, String.format("%04x: line %d", address, line));
}
}
use of com.android.dx.rop.code.SourcePosition in project J2ME-Loader by nikita36078.
the class RopperMachine method run.
/**
* {@inheritDoc}
*/
@Override
public void run(Frame frame, int offset, int opcode) {
/*
* This is the stack pointer after the opcode's arguments have been
* popped.
*/
int stackPointer = maxLocals + frame.getStack().size();
// The sources have to be retrieved before super.run() gets called.
RegisterSpecList sources = getSources(opcode, stackPointer);
int sourceCount = sources.size();
super.run(frame, offset, opcode);
SourcePosition pos = method.makeSourcePosistion(offset);
RegisterSpec localTarget = getLocalTarget(opcode == ByteOps.ISTORE);
int destCount = resultCount();
RegisterSpec dest;
if (destCount == 0) {
dest = null;
switch(opcode) {
case ByteOps.POP:
case ByteOps.POP2:
{
// These simply don't appear in the rop form.
return;
}
}
} else if (localTarget != null) {
dest = localTarget;
} else if (destCount == 1) {
dest = RegisterSpec.make(stackPointer, result(0));
} else {
/*
* This clause only ever applies to the stack manipulation
* ops that have results (that is, dup* and swap but not
* pop*).
*
* What we do is first move all the source registers into
* the "temporary stack" area defined for the method, and
* then move stuff back down onto the main "stack" in the
* arrangement specified by the stack op pattern.
*
* Note: This code ends up emitting a lot of what will
* turn out to be superfluous moves (e.g., moving back and
* forth to the same local when doing a dup); however,
* that makes this code a bit easier (and goodness knows
* it doesn't need any extra complexity), and all the SSA
* stuff is going to want to deal with this sort of
* superfluous assignment anyway, so it should be a wash
* in the end.
*/
int scratchAt = ropper.getFirstTempStackReg();
RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount];
for (int i = 0; i < sourceCount; i++) {
RegisterSpec src = sources.get(i);
TypeBearer type = src.getTypeBearer();
RegisterSpec scratch = src.withReg(scratchAt);
insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src));
scratchRegs[i] = scratch;
scratchAt += src.getCategory();
}
for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) {
int which = (pattern & 0x0f) - 1;
RegisterSpec scratch = scratchRegs[which];
TypeBearer type = scratch.getTypeBearer();
insns.add(new PlainInsn(Rops.opMove(type), pos, scratch.withReg(stackPointer), scratch));
stackPointer += type.getType().getCategory();
}
return;
}
TypeBearer destType = (dest != null) ? dest : Type.VOID;
Constant cst = getAuxCst();
int ropOpcode;
Rop rop;
Insn insn;
if (opcode == ByteOps.MULTIANEWARRAY) {
blockCanThrow = true;
// Add the extra instructions for handling multianewarray.
extraBlockCount = 6;
/*
* Add an array constructor for the int[] containing all the
* dimensions.
*/
RegisterSpec dimsReg = RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY);
rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount);
insn = new ThrowingCstInsn(rop, pos, sources, catches, CstType.INT_ARRAY);
insns.add(insn);
// Add a move-result for the new-filled-array
rop = Rops.opMoveResult(Type.INT_ARRAY);
insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* Add a const-class instruction for the specified array
* class.
*/
/*
* Remove as many dimensions from the originally specified
* class as are given in the explicit list of dimensions,
* so as to pass the right component class to the standard
* Java library array constructor.
*/
Type componentType = ((CstType) cst).getClassType();
for (int i = 0; i < sourceCount; i++) {
componentType = componentType.getComponentType();
}
RegisterSpec classReg = RegisterSpec.make(dest.getReg(), Type.CLASS);
if (componentType.isPrimitive()) {
/*
* The component type is primitive (e.g., int as opposed
* to Integer), so we have to fetch the corresponding
* TYPE class.
*/
CstFieldRef typeField = CstFieldRef.forPrimitiveType(componentType);
insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos, RegisterSpecList.EMPTY, catches, typeField);
} else {
/*
* The component type is an object type, so just make a
* normal class reference.
*/
insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, RegisterSpecList.EMPTY, catches, new CstType(componentType));
}
insns.add(insn);
// Add a move-result-pseudo for the get-static or const
rop = Rops.opMoveResultPseudo(classReg.getType());
insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* Add a call to the "multianewarray method," that is,
* Array.newInstance(class, dims). Note: The result type
* of newInstance() is Object, which is why the last
* instruction in this sequence is a cast to the right
* type for the original instruction.
*/
RegisterSpec objectReg = RegisterSpec.make(dest.getReg(), Type.OBJECT);
insn = new ThrowingCstInsn(Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()), pos, RegisterSpecList.make(classReg, dimsReg), catches, MULTIANEWARRAY_METHOD);
insns.add(insn);
// Add a move-result.
rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype().getReturnType());
insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY);
insns.add(insn);
/*
* And finally, set up for the remainder of this method to
* add an appropriate cast.
*/
opcode = ByteOps.CHECKCAST;
sources = RegisterSpecList.make(objectReg);
} else if (opcode == ByteOps.JSR) {
// JSR has no Rop instruction
hasJsr = true;
return;
} else if (opcode == ByteOps.RET) {
try {
returnAddress = (ReturnAddress) arg(0);
} catch (ClassCastException ex) {
throw new RuntimeException("Argument to RET was not a ReturnAddress", ex);
}
// RET has no Rop instruction.
return;
}
ropOpcode = jopToRopOpcode(opcode, cst);
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
Insn moveResult = null;
if (dest != null && rop.isCallLike()) {
/*
* We're going to want to have a move-result in the next
* basic block.
*/
extraBlockCount++;
moveResult = new PlainInsn(Rops.opMoveResult(((CstMethodRef) cst).getPrototype().getReturnType()), pos, dest, RegisterSpecList.EMPTY);
dest = null;
} else if (dest != null && rop.canThrow()) {
/*
* We're going to want to have a move-result-pseudo in the
* next basic block.
*/
extraBlockCount++;
moveResult = new PlainInsn(Rops.opMoveResultPseudo(dest.getTypeBearer()), pos, dest, RegisterSpecList.EMPTY);
dest = null;
}
if (ropOpcode == RegOps.NEW_ARRAY) {
/*
* In the original bytecode, this was either a primitive
* array constructor "newarray" or an object array
* constructor "anewarray". In the former case, there is
* no explicit constant, and in the latter, the constant
* is for the element type and not the array type. The rop
* instruction form for both of these is supposed to be
* the resulting array type, so we initialize / alter
* "cst" here, accordingly. Conveniently enough, the rop
* opcode already gets constructed with the proper array
* type.
*/
cst = CstType.intern(rop.getResult());
} else if ((cst == null) && (sourceCount == 2)) {
TypeBearer firstType = sources.get(0).getTypeBearer();
TypeBearer lastType = sources.get(1).getTypeBearer();
if ((lastType.isConstant() || firstType.isConstant()) && advice.hasConstantOperation(rop, sources.get(0), sources.get(1))) {
if (lastType.isConstant()) {
/*
* The target architecture has an instruction that can
* build in the constant found in the second argument,
* so pull it out of the sources and just use it as a
* constant here.
*/
cst = (Constant) lastType;
sources = sources.withoutLast();
// For subtraction, change to addition and invert constant
if (rop.getOpcode() == RegOps.SUB) {
ropOpcode = RegOps.ADD;
CstInteger cstInt = (CstInteger) lastType;
cst = CstInteger.make(-cstInt.getValue());
}
} else {
/*
* The target architecture has an instruction that can
* build in the constant found in the first argument,
* so pull it out of the sources and just use it as a
* constant here.
*/
cst = (Constant) firstType;
sources = sources.withoutFirst();
}
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
}
}
SwitchList cases = getAuxCases();
ArrayList<Constant> initValues = getInitValues();
boolean canThrow = rop.canThrow();
blockCanThrow |= canThrow;
if (cases != null) {
if (cases.size() == 0) {
// It's a default-only switch statement. It can happen!
insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
primarySuccessorIndex = 0;
} else {
IntList values = cases.getValues();
insn = new SwitchInsn(rop, pos, dest, sources, values);
primarySuccessorIndex = values.size();
}
} else if (ropOpcode == RegOps.RETURN) {
/*
* Returns get turned into the combination of a move (if
* non-void and if the return doesn't already mention
* register 0) and a goto (to the return block).
*/
if (sources.size() != 0) {
RegisterSpec source = sources.get(0);
TypeBearer type = source.getTypeBearer();
if (source.getReg() != 0) {
insns.add(new PlainInsn(Rops.opMove(type), pos, RegisterSpec.make(0, type), source));
}
}
insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY);
primarySuccessorIndex = 0;
updateReturnOp(rop, pos);
returns = true;
} else if (cst != null) {
if (canThrow) {
if (rop.getOpcode() == RegOps.INVOKE_POLYMORPHIC) {
insn = makeInvokePolymorphicInsn(rop, pos, sources, catches, cst);
} else {
insn = new ThrowingCstInsn(rop, pos, sources, catches, cst);
}
catchesUsed = true;
primarySuccessorIndex = catches.size();
} else {
insn = new PlainCstInsn(rop, pos, dest, sources, cst);
}
} else if (canThrow) {
insn = new ThrowingInsn(rop, pos, sources, catches);
catchesUsed = true;
if (opcode == ByteOps.ATHROW) {
/*
* The op athrow is the only one where it's possible
* to have non-empty successors and yet not have a
* primary successor.
*/
primarySuccessorIndex = -1;
} else {
primarySuccessorIndex = catches.size();
}
} else {
insn = new PlainInsn(rop, pos, dest, sources);
}
insns.add(insn);
if (moveResult != null) {
insns.add(moveResult);
}
/*
* If initValues is non-null, it means that the parser has
* seen a group of compatible constant initialization
* bytecodes that are applied to the current newarray. The
* action we take here is to convert these initialization
* bytecodes into a single fill-array-data ROP which lays out
* all the constant values in a table.
*/
if (initValues != null) {
extraBlockCount++;
insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos, RegisterSpecList.make(moveResult.getResult()), initValues, cst);
insns.add(insn);
}
}
Aggregations