use of com.android.dx.rop.cst.CstType in project J2ME-Loader by nikita36078.
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.cst.CstType in project J2ME-Loader by nikita36078.
the class ConstantPoolParser method parse0.
/**
* Parses the constant for the given index if it hasn't already been
* parsed, also storing it in the constant pool. This will also
* have the side effect of parsing any entries the indicated one
* depends on.
*
* @param idx which constant
* @return {@code non-null;} the parsed constant
*/
private Constant parse0(int idx, BitSet wasUtf8) {
Constant cst = pool.getOrNull(idx);
if (cst != null) {
return cst;
}
int at = offsets[idx];
try {
int tag = bytes.getUnsignedByte(at);
switch(tag) {
case CONSTANT_Utf8:
{
cst = parseUtf8(at);
wasUtf8.set(idx);
break;
}
case CONSTANT_Integer:
{
int value = bytes.getInt(at + 1);
cst = CstInteger.make(value);
break;
}
case CONSTANT_Float:
{
int bits = bytes.getInt(at + 1);
cst = CstFloat.make(bits);
break;
}
case CONSTANT_Long:
{
long value = bytes.getLong(at + 1);
cst = CstLong.make(value);
break;
}
case CONSTANT_Double:
{
long bits = bytes.getLong(at + 1);
cst = CstDouble.make(bits);
break;
}
case CONSTANT_Class:
{
int nameIndex = bytes.getUnsignedShort(at + 1);
CstString name = (CstString) parse0(nameIndex, wasUtf8);
cst = new CstType(Type.internClassName(name.getString()));
break;
}
case CONSTANT_String:
{
int stringIndex = bytes.getUnsignedShort(at + 1);
cst = parse0(stringIndex, wasUtf8);
break;
}
case CONSTANT_Fieldref:
{
int classIndex = bytes.getUnsignedShort(at + 1);
CstType type = (CstType) parse0(classIndex, wasUtf8);
int natIndex = bytes.getUnsignedShort(at + 3);
CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
cst = new CstFieldRef(type, nat);
break;
}
case CONSTANT_Methodref:
{
int classIndex = bytes.getUnsignedShort(at + 1);
CstType type = (CstType) parse0(classIndex, wasUtf8);
int natIndex = bytes.getUnsignedShort(at + 3);
CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
cst = new CstMethodRef(type, nat);
break;
}
case CONSTANT_InterfaceMethodref:
{
int classIndex = bytes.getUnsignedShort(at + 1);
CstType type = (CstType) parse0(classIndex, wasUtf8);
int natIndex = bytes.getUnsignedShort(at + 3);
CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
cst = new CstInterfaceMethodRef(type, nat);
break;
}
case CONSTANT_NameAndType:
{
int nameIndex = bytes.getUnsignedShort(at + 1);
CstString name = (CstString) parse0(nameIndex, wasUtf8);
int descriptorIndex = bytes.getUnsignedShort(at + 3);
CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
cst = new CstNat(name, descriptor);
break;
}
case CONSTANT_MethodHandle:
{
int kind = bytes.getUnsignedByte(at + 1);
int constantIndex = bytes.getUnsignedShort(at + 2);
Constant ref;
switch(kind) {
case CstMethodHandle.KIND_GETFIELD:
case CstMethodHandle.KIND_GETSTATIC:
case CstMethodHandle.KIND_PUTFIELD:
case CstMethodHandle.KIND_PUTSTATIC:
CstFieldRef field = (CstFieldRef) parse0(constantIndex, wasUtf8);
ref = field;
break;
case CstMethodHandle.KIND_INVOKEVIRTUAL:
case CstMethodHandle.KIND_NEWINVOKESPECIAL:
CstMethodRef method = (CstMethodRef) parse0(constantIndex, wasUtf8);
ref = method;
break;
case CstMethodHandle.KIND_INVOKESTATIC:
case CstMethodHandle.KIND_INVOKESPECIAL:
ref = parse0(constantIndex, wasUtf8);
if (!(ref instanceof CstMethodRef || ref instanceof CstInterfaceMethodRef)) {
throw new ParseException("Unsupported ref constant type for MethodHandle " + ref.getClass());
}
break;
case CstMethodHandle.KIND_INVOKEINTERFACE:
CstInterfaceMethodRef interfaceMethod = (CstInterfaceMethodRef) parse0(constantIndex, wasUtf8);
ref = interfaceMethod;
break;
default:
throw new ParseException("Unsupported MethodHandle kind: " + kind);
}
cst = CstMethodHandle.make(kind, ref);
break;
}
case CONSTANT_MethodType:
{
int descriptorIndex = bytes.getUnsignedShort(at + 1);
CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8);
cst = CstMethodType.make(descriptor);
break;
}
case CONSTANT_InvokeDynamic:
{
int bootstrapMethodIndex = bytes.getUnsignedShort(at + 1);
int natIndex = bytes.getUnsignedShort(at + 3);
CstNat nat = (CstNat) parse0(natIndex, wasUtf8);
cst = CstInvokeDynamic.make(bootstrapMethodIndex, nat);
break;
}
default:
{
throw new ParseException("unknown tag byte: " + Hex.u1(tag));
}
}
} catch (ParseException ex) {
ex.addContext("...while parsing cst " + Hex.u2(idx) + " at offset " + Hex.u4(at));
throw ex;
} catch (RuntimeException ex) {
ParseException pe = new ParseException(ex);
pe.addContext("...while parsing cst " + Hex.u2(idx) + " at offset " + Hex.u4(at));
throw pe;
}
pool.set(idx, cst);
return cst;
}
use of com.android.dx.rop.cst.CstType in project J2ME-Loader by nikita36078.
the class StdAttributeFactory method innerClasses.
/**
* Parses an {@code InnerClasses} attribute.
*/
private Attribute innerClasses(DirectClassFile cf, int offset, int length, ParseObserver observer) {
if (length < 2) {
return throwSeverelyTruncated();
}
ByteArray bytes = cf.getBytes();
ConstantPool pool = cf.getConstantPool();
// number_of_classes
int count = bytes.getUnsignedShort(offset);
if (observer != null) {
observer.parsed(bytes, offset, 2, "number_of_classes: " + Hex.u2(count));
}
offset += 2;
length -= 2;
if (length != (count * 8)) {
throwBadLength((count * 8) + 2);
}
InnerClassList list = new InnerClassList(count);
for (int i = 0; i < count; i++) {
int innerClassIdx = bytes.getUnsignedShort(offset);
int outerClassIdx = bytes.getUnsignedShort(offset + 2);
int nameIdx = bytes.getUnsignedShort(offset + 4);
int accessFlags = bytes.getUnsignedShort(offset + 6);
CstType innerClass = (CstType) pool.get(innerClassIdx);
CstType outerClass = (CstType) pool.get0Ok(outerClassIdx);
CstString name = (CstString) pool.get0Ok(nameIdx);
list.set(i, innerClass, outerClass, name, accessFlags);
if (observer != null) {
observer.parsed(bytes, offset, 2, "inner_class: " + DirectClassFile.stringOrNone(innerClass));
observer.parsed(bytes, offset + 2, 2, " outer_class: " + DirectClassFile.stringOrNone(outerClass));
observer.parsed(bytes, offset + 4, 2, " name: " + DirectClassFile.stringOrNone(name));
observer.parsed(bytes, offset + 6, 2, " access_flags: " + AccessFlags.innerClassString(accessFlags));
}
offset += 8;
}
list.setImmutable();
return new AttInnerClasses(list);
}
use of com.android.dx.rop.cst.CstType in project J2ME-Loader by nikita36078.
the class StdAttributeFactory method code.
/**
* Parses a {@code Code} attribute.
*/
private Attribute code(DirectClassFile cf, int offset, int length, ParseObserver observer) {
if (length < 12) {
return throwSeverelyTruncated();
}
ByteArray bytes = cf.getBytes();
ConstantPool pool = cf.getConstantPool();
// u2 max_stack
int maxStack = bytes.getUnsignedShort(offset);
// u2 max_locals
int maxLocals = bytes.getUnsignedShort(offset + 2);
// u4 code_length
int codeLength = bytes.getInt(offset + 4);
int origOffset = offset;
if (observer != null) {
observer.parsed(bytes, offset, 2, "max_stack: " + Hex.u2(maxStack));
observer.parsed(bytes, offset + 2, 2, "max_locals: " + Hex.u2(maxLocals));
observer.parsed(bytes, offset + 4, 4, "code_length: " + Hex.u4(codeLength));
}
offset += 8;
length -= 8;
if (length < (codeLength + 4)) {
return throwTruncated();
}
int codeOffset = offset;
offset += codeLength;
length -= codeLength;
BytecodeArray code = new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength), pool);
if (observer != null) {
code.forEach(new CodeObserver(code.getBytes(), observer));
}
// u2 exception_table_length
int exceptionTableLength = bytes.getUnsignedShort(offset);
ByteCatchList catches = (exceptionTableLength == 0) ? ByteCatchList.EMPTY : new ByteCatchList(exceptionTableLength);
if (observer != null) {
observer.parsed(bytes, offset, 2, "exception_table_length: " + Hex.u2(exceptionTableLength));
}
offset += 2;
length -= 2;
if (length < (exceptionTableLength * 8 + 2)) {
return throwTruncated();
}
for (int i = 0; i < exceptionTableLength; i++) {
if (observer != null) {
observer.changeIndent(1);
}
int startPc = bytes.getUnsignedShort(offset);
int endPc = bytes.getUnsignedShort(offset + 2);
int handlerPc = bytes.getUnsignedShort(offset + 4);
int catchTypeIdx = bytes.getUnsignedShort(offset + 6);
CstType catchType = (CstType) pool.get0Ok(catchTypeIdx);
catches.set(i, startPc, endPc, handlerPc, catchType);
if (observer != null) {
observer.parsed(bytes, offset, 8, Hex.u2(startPc) + ".." + Hex.u2(endPc) + " -> " + Hex.u2(handlerPc) + " " + ((catchType == null) ? "<any>" : catchType.toHuman()));
}
offset += 8;
length -= 8;
if (observer != null) {
observer.changeIndent(-1);
}
}
catches.setImmutable();
AttributeListParser parser = new AttributeListParser(cf, CTX_CODE, offset, this);
parser.setObserver(observer);
StdAttributeList attributes = parser.getList();
attributes.setImmutable();
int attributeByteCount = parser.getEndOffset() - offset;
if (attributeByteCount != length) {
return throwBadLength(attributeByteCount + (offset - origOffset));
}
return new AttCode(maxStack, maxLocals, code, catches, attributes);
}
use of com.android.dx.rop.cst.CstType in project J2ME-Loader by nikita36078.
the class AttributeTranslator method translateEnclosingMethod.
/**
* Gets the {@code EnclosingMethod} attribute out of a given
* {@link AttributeList}, if any, translating it to an annotation.
* If the class really has an enclosing method, this returns an
* {@code EnclosingMethod} annotation; if not, this returns
* an {@code EnclosingClass} annotation.
*
* @param attribs {@code non-null;} the attributes list to search in
* @return {@code null-ok;} the converted {@code EnclosingMethod} or
* {@code EnclosingClass} annotation, if there was an
* attribute to translate
*/
private static Annotation translateEnclosingMethod(AttributeList attribs) {
AttEnclosingMethod enclosingMethod = (AttEnclosingMethod) attribs.findFirst(AttEnclosingMethod.ATTRIBUTE_NAME);
if (enclosingMethod == null) {
return null;
}
CstType enclosingClass = enclosingMethod.getEnclosingClass();
CstNat nat = enclosingMethod.getMethod();
if (nat == null) {
/*
* Dalvik doesn't use EnclosingMethod annotations unless
* there really is an enclosing method. Anonymous classes
* are unambiguously identified by having an InnerClass
* annotation with an empty name along with an appropriate
* EnclosingClass.
*/
return AnnotationUtils.makeEnclosingClass(enclosingClass);
}
return AnnotationUtils.makeEnclosingMethod(new CstMethodRef(enclosingClass, nat));
}
Aggregations