private void make(byte[] code, TypedBlock tb) throws BadBytecode { copyTypeData(tb.stackTop, tb.stackTypes, stackTypes); stackTop = tb.stackTop; copyTypeData(tb.localsTypes.length, tb.localsTypes, localsTypes); traceException(code, tb.toCatch); int pos = tb.position; int end = pos + tb.length; while (pos < end) { pos += doOpcode(pos, code); traceException(code, tb.toCatch); } if (tb.exit != null) { for (int i = 0; i < tb.exit.length; i++) { TypedBlock e = (TypedBlock)tb.exit[i]; if (e.alreadySet()) mergeMap(e, true); else { recordStackMap(e); MapMaker maker = new MapMaker(this); maker.make(code, e); } } } }
private static int stackMapDiff(int oldTdLen, TypeData[] oldTd, int newTdLen, TypeData[] newTd) { int diff = newTdLen - oldTdLen; int len; if (diff > 0) len = oldTdLen; else len = newTdLen; if (stackMapEq(oldTd, newTd, len)) if (diff > 0) return diffSize(newTd, len, newTdLen); else return -diffSize(oldTd, len, oldTdLen); else return -100; }
public StackMapTable toStackMap(TypedBlock[] blocks) { StackMapTable.Writer writer = new StackMapTable.Writer(32); int n = blocks.length; TypedBlock prev = blocks[0]; int offsetDelta = prev.length; if (prev.incoming > 0) { // the first instruction is a branch target. writer.sameFrame(0); offsetDelta--; } for (int i = 1; i < n; i++) { TypedBlock bb = blocks[i]; if (isTarget(bb, blocks[i - 1])) { bb.resetNumLocals(); int diffL = stackMapDiff(prev.numLocals, prev.localsTypes, bb.numLocals, bb.localsTypes); toStackMapBody(writer, bb, diffL, offsetDelta, prev); offsetDelta = bb.length - 1; prev = bb; } else if (bb.incoming == 0) { // dead code. writer.sameFrame(offsetDelta); offsetDelta = bb.length - 1; prev = bb; } else offsetDelta += bb.length; } return writer.toStackMapTable(cpool); }
private void mergeMap(TypedBlock dest, boolean mergeStack) throws BadBytecode { int n = localsTypes.length; for (int i = 0; i < n; i++) dest.localsTypes[i] = merge(validateTypeData(localsTypes, n, i), dest.localsTypes[i]); if (mergeStack) { n = stackTop; for (int i = 0; i < n; i++) dest.stackTypes[i] = merge(stackTypes[i], dest.stackTypes[i]); } }
/** * Runs an analyzer (Phase 1 and 2). */ void make(TypedBlock[] blocks, byte[] code) throws BadBytecode { make(code, blocks[0]); findDeadCatchers(code, blocks); try { fixTypes(code, blocks); } catch (NotFoundException e) { throw new BadBytecode("failed to resolve types", e); } }
private void traceException(byte[] code, TypedBlock.Catch handler) throws BadBytecode { while (handler != null) { TypedBlock tb = (TypedBlock)handler.body; if (tb.alreadySet()) { mergeMap(tb, false); if (tb.stackTop < 1) throw new BadBytecode("bad catch clause: " + handler.typeIndex); tb.stackTypes[0] = merge(toExceptionType(handler.typeIndex), tb.stackTypes[0]); } else { recordStackMap(tb, handler.typeIndex); MapMaker maker = new MapMaker(this); maker.make(code, tb); } handler = handler.next; } }
/** * Computes the stack map table of the given method and returns it. * It returns null if the given method does not have to have a * stack map table or it includes JSR. */ public static StackMapTable make(ClassPool classes, MethodInfo minfo) throws BadBytecode { CodeAttribute ca = minfo.getCodeAttribute(); if (ca == null) return null; TypedBlock[] blocks; try { blocks = TypedBlock.makeBlocks(minfo, ca, true); } catch (BasicBlock.JsrBytecode e) { return null; } if (blocks == null) return null; MapMaker mm = new MapMaker(classes, minfo, ca); try { mm.make(blocks, ca.getCode()); } catch (BadBytecode bb) { throw new BadBytecode(minfo, bb); } return mm.toStackMap(blocks); }
/** * Computes the stack map table for J2ME. * It returns null if the given method does not have to have a * stack map table or it includes JSR. */ public static StackMap make2(ClassPool classes, MethodInfo minfo) throws BadBytecode { CodeAttribute ca = minfo.getCodeAttribute(); if (ca == null) return null; TypedBlock[] blocks; try { blocks = TypedBlock.makeBlocks(minfo, ca, true); } catch (BasicBlock.JsrBytecode e) { return null; } if (blocks == null) return null; MapMaker mm = new MapMaker(classes, minfo, ca); try { mm.make(blocks, ca.getCode()); } catch (BadBytecode bb) { throw new BadBytecode(minfo, bb); } return mm.toStackMap2(minfo.getConstPool(), blocks); }
private void traceException(byte[] code, TypedBlock.Catch handler) throws BadBytecode { TypedBlock tb = (TypedBlock)handler.body; if (tb.alreadySet()) mergeMap(tb, false); else { recordStackMap(tb, handler.typeIndex); MapMaker maker = new MapMaker(this, false); /* the following code is equivalent to maker.copyFrom(this) * except stackTypes are not copied. */ maker.stackTypes[0] = tb.stackTypes[0].getSelf(); maker.stackTop = 1; maker.make(code, tb); } }
public StackMap toStackMap2(ConstPool cp, TypedBlock[] blocks) { StackMap.Writer writer = new StackMap.Writer(); int n = blocks.length; // should be > 0 boolean[] effective = new boolean[n]; TypedBlock prev = blocks[0]; // Is the first instruction a branch target? effective[0] = prev.incoming > 0; int num = effective[0] ? 1 : 0; for (int i = 1; i < n; i++) { TypedBlock bb = blocks[i]; if (effective[i] = isTarget(bb, blocks[i - 1])) { bb.resetNumLocals(); prev = bb; num++; } } if (num == 0) return null; writer.write16bit(num); for (int i = 0; i < n; i++) if (effective[i]) writeStackFrame(writer, cp, blocks[i].position, blocks[i]); return writer.toStackMap(cp); }
private void recordStackMap(TypedBlock target) throws BadBytecode { TypeData[] tStackTypes = TypeData.make(stackTypes.length); int st = stackTop; recordTypeData(st, stackTypes, tStackTypes); recordStackMap0(target, st, tStackTypes); }
private void recordStackMap(TypedBlock target, int exceptionType) throws BadBytecode { TypeData[] tStackTypes = TypeData.make(stackTypes.length); tStackTypes[0] = toExceptionType(exceptionType).join(); recordStackMap0(target, 1, tStackTypes); }
private void findDeadCatchers(byte[] code, TypedBlock[] blocks) throws BadBytecode { int len = blocks.length; for (int i = 0; i < len; i++) { TypedBlock block = blocks[i]; if (!block.alreadySet()) { fixDeadcode(code, block); BasicBlock.Catch handler = block.toCatch; if (handler != null) { TypedBlock tb = (TypedBlock)handler.body; if (!tb.alreadySet()) { // tb is a handler that catches only the exceptions // thrown from dead code. recordStackMap(tb, handler.typeIndex); fixDeadcode(code, tb); tb.incoming = 1; } } } } }
/** * Rebuilds a stack map table. If no stack map table is included, * a new one is created. If this <code>MethodInfo</code> does not * include a code attribute, nothing happens. * * @param pool used for making type hierarchy. * @see StackMapTable * @since 3.6 */ public void rebuildStackMap(ClassPool pool) throws BadBytecode { CodeAttribute ca = getCodeAttribute(); if (ca != null) { StackMapTable smt = MapMaker.make(pool, this); ca.setAttribute(smt); } }
/** * Runs an analyzer (Phase 1 and 2). */ void make(TypedBlock[] blocks, byte[] code) throws BadBytecode { TypedBlock first = blocks[0]; fixParamTypes(first); TypeData[] srcTypes = first.localsTypes; copyFrom(srcTypes.length, srcTypes, this.localsTypes); make(code, first); int n = blocks.length; for (int i = 0; i < n; i++) evalExpected(blocks[i]); }
private int[] fillStackMap(int num, int offset, int[] data, TypeData[] types) { int realNum = diffSize(types, offset, offset + num); ConstPool cp = cpool; int[] tags = new int[realNum]; int j = 0; for (int i = 0; i < num; i++) { TypeData td = types[offset + i]; tags[j] = td.getTypeTag(); data[j] = td.getTypeData(cp); if (td.is2WordType()) i++; j++; } return tags; }
int[] tags = fillStackMap(bb.numLocals - prev.numLocals, prev.numLocals, data, bb.localsTypes); int[] stags = fillStackMap(stackTop, 0, sdata, bb.stackTypes); int[] ldata = new int[bb.numLocals]; int[] ltags = fillStackMap(bb.numLocals, 0, ldata, bb.localsTypes); writer.fullFrame(offsetDelta, ltags, ldata, stags, sdata);
private void fixDeadcode(byte[] code, TypedBlock block) throws BadBytecode { int pos = block.position; int len = block.length - 3; if (len < 0) { // if the dead-code length is shorter than 3 bytes. if (len == -1) code[pos] = Bytecode.NOP; code[pos + block.length - 1] = (byte)Bytecode.ATHROW; block.incoming = 1; recordStackMap(block, 0); return; } // if block.incomping > 0, all the incoming edges are from // other dead code blocks. So set block.incoming to 0. block.incoming = 0; for (int k = 0; k < len; k++) code[pos + k] = Bytecode.NOP; code[pos + len] = (byte)Bytecode.GOTO; ByteArray.write16bit(-len, code, pos + len + 1); }
private void recordStackMap(TypedBlock target) throws BadBytecode { TypeData[] tStackTypes = new TypeData[stackTypes.length]; int st = stackTop; copyFrom(st, stackTypes, tStackTypes); recordStackMap0(target, st, tStackTypes); }
private void recordStackMap(TypedBlock target, int exceptionType) throws BadBytecode { String type; if (exceptionType == 0) type = "java.lang.Throwable"; else type = cpool.getClassInfo(exceptionType); TypeData[] tStackTypes = new TypeData[stackTypes.length]; tStackTypes[0] = new TypeData.ClassName(type); recordStackMap0(target, 1, tStackTypes); }