/** * Identifies and enumerates the basic blocks in the given method, * returning a list of them. The returned list notably omits any * definitely-dead code that is identified in the process. * * @param method {@code non-null;} method to convert * @return {@code non-null;} list of basic blocks */ public static ByteBlockList identifyBlocks(ConcreteMethod method) { BasicBlocker bb = new BasicBlocker(method); bb.doit(); return bb.getBlockList(); }
/** {@inheritDoc} */ @Override public void visitNewarray(int offset, int length, CstType type, ArrayList<Constant> intVals) { visitCommon(offset, length, true); visitThrowing(offset, length, true); }
/** {@inheritDoc} */ public void visitBranch(int opcode, int offset, int length, int target) { switch (opcode) { case ByteOps.GOTO: { visitCommon(offset, length, false); targetLists[offset] = IntList.makeImmutable(target); break; } case ByteOps.JSR: { /* * Each jsr is quarantined into a separate block (containing * only the jsr instruction) but is otherwise treated * as a conditional branch. (That is to say, both its * target and next instruction begin new blocks.) */ addWorkIfNecessary(offset, true); // Fall through to next case... } default: { int next = offset + length; visitCommon(offset, length, true); addWorkIfNecessary(next, true); targetLists[offset] = IntList.makeImmutable(next, target); break; } } addWorkIfNecessary(target, true); }
/** * Helper method used by all the visitor methods. * * @param offset offset to the instruction * @param length length of the instruction, in bytes * @param nextIsLive {@code true} iff the instruction after * the indicated one is possibly-live (because this one isn't an * unconditional branch, a return, or a switch) */ private void visitCommon(int offset, int length, boolean nextIsLive) { Bits.set(liveSet, offset); if (nextIsLive) { /* * If the next instruction is flowed to by this one, just * add it to the work set, and then a subsequent visit*() * will deal with it as appropriate. */ addWorkIfNecessary(offset + length, false); } else { /* * If the next instruction isn't flowed to by this one, * then mark it as a start of a block but *don't* add it * to the work set, so that in the final phase we can know * dead code blocks as those marked as blocks but not also marked * live. */ Bits.set(blockSet, offset + length); } }
/** {@inheritDoc} */ @Override public void visitInvalid(int opcode, int offset, int length) { visitCommon(offset, length, true); }
this.blocks = BasicBlocker.identifyBlocks(method); this.maxLabel = blocks.getMaxLabel(); this.maxLocals = method.getMaxLocals();
/** {@inheritDoc} */ public void visitBranch(int opcode, int offset, int length, int target) { switch (opcode) { case ByteOps.GOTO: { visitCommon(offset, length, false); targetLists[offset] = IntList.makeImmutable(target); break; } case ByteOps.JSR: { /* * Each jsr is quarantined into a separate block (containing * only the jsr instruction) but is otherwise treated * as a conditional branch. (That is to say, both its * target and next instruction begin new blocks.) */ addWorkIfNecessary(offset, true); // Fall through to next case... } default: { int next = offset + length; visitCommon(offset, length, true); addWorkIfNecessary(next, true); targetLists[offset] = IntList.makeImmutable(next, target); break; } } addWorkIfNecessary(target, true); }
/** * Helper method used by all the visitor methods. * * @param offset offset to the instruction * @param length length of the instruction, in bytes * @param nextIsLive {@code true} iff the instruction after * the indicated one is possibly-live (because this one isn't an * unconditional branch, a return, or a switch) */ private void visitCommon(int offset, int length, boolean nextIsLive) { Bits.set(liveSet, offset); if (nextIsLive) { /* * If the next instruction is flowed to by this one, just * add it to the work set, and then a subsequent visit*() * will deal with it as appropriate. */ addWorkIfNecessary(offset + length, false); } else { /* * If the next instruction isn't flowed to by this one, * then mark it as a start of a block but *don't* add it * to the work set, so that in the final phase we can know * dead code blocks as those marked as blocks but not also marked * live. */ Bits.set(blockSet, offset + length); } }
/** {@inheritDoc} */ @Override public void visitLocal(int opcode, int offset, int length, int idx, Type type, int value) { if (opcode == ByteOps.RET) { visitCommon(offset, length, false); targetLists[offset] = IntList.EMPTY; } else { visitCommon(offset, length, true); } }
this.blocks = BasicBlocker.identifyBlocks(method); this.maxLabel = blocks.getMaxLabel(); this.maxLocals = method.getMaxLocals();
/** {@inheritDoc} */ @Override public void visitNewarray(int offset, int length, CstType type, ArrayList<Constant> intVals) { visitCommon(offset, length, true); visitThrowing(offset, length, true); }
/** * Identifies and enumerates the basic blocks in the given method, * returning a list of them. The returned list notably omits any * definitely-dead code that is identified in the process. * * @param method {@code non-null;} method to convert * @return {@code non-null;} list of basic blocks */ public static ByteBlockList identifyBlocks(ConcreteMethod method) { BasicBlocker bb = new BasicBlocker(method); bb.doit(); return bb.getBlockList(); }
/** {@inheritDoc} */ @Override public void visitBranch(int opcode, int offset, int length, int target) { switch (opcode) { case ByteOps.GOTO: { visitCommon(offset, length, false); targetLists[offset] = IntList.makeImmutable(target); break; } case ByteOps.JSR: { /* * Each jsr is quarantined into a separate block (containing * only the jsr instruction) but is otherwise treated * as a conditional branch. (That is to say, both its * target and next instruction begin new blocks.) */ addWorkIfNecessary(offset, true); // Fall through to next case... } default: { int next = offset + length; visitCommon(offset, length, true); addWorkIfNecessary(next, true); targetLists[offset] = IntList.makeImmutable(next, target); break; } } addWorkIfNecessary(target, true); }
/** * Helper method used by all the visitor methods. * * @param offset offset to the instruction * @param length length of the instruction, in bytes * @param nextIsLive {@code true} iff the instruction after * the indicated one is possibly-live (because this one isn't an * unconditional branch, a return, or a switch) */ private void visitCommon(int offset, int length, boolean nextIsLive) { Bits.set(liveSet, offset); if (nextIsLive) { /* * If the next instruction is flowed to by this one, just * add it to the work set, and then a subsequent visit*() * will deal with it as appropriate. */ addWorkIfNecessary(offset + length, false); } else { /* * If the next instruction isn't flowed to by this one, * then mark it as a start of a block but *don't* add it * to the work set, so that in the final phase we can know * dead code blocks as those marked as blocks but not also marked * live. */ Bits.set(blockSet, offset + length); } }
/** {@inheritDoc} */ public void visitLocal(int opcode, int offset, int length, int idx, Type type, int value) { if (opcode == ByteOps.RET) { visitCommon(offset, length, false); targetLists[offset] = IntList.EMPTY; } else { visitCommon(offset, length, true); } }
this.blocks = BasicBlocker.identifyBlocks(method); this.maxLabel = blocks.getMaxLabel(); this.maxLocals = method.getMaxLocals();
/** {@inheritDoc} */ public void visitNewarray(int offset, int length, CstType type, ArrayList<Constant> intVals) { visitCommon(offset, length, true); visitThrowing(offset, length, true); }
/** * Identifies and enumerates the basic blocks in the given method, * returning a list of them. The returned list notably omits any * definitely-dead code that is identified in the process. * * @param method {@code non-null;} method to convert * @return {@code non-null;} list of basic blocks */ public static ByteBlockList identifyBlocks(ConcreteMethod method) { BasicBlocker bb = new BasicBlocker(method); bb.doit(); return bb.getBlockList(); }
/** {@inheritDoc} */ public void visitBranch(int opcode, int offset, int length, int target) { switch (opcode) { case ByteOps.GOTO: { visitCommon(offset, length, false); targetLists[offset] = IntList.makeImmutable(target); break; } case ByteOps.JSR: { /* * Each jsr is quarantined into a separate block (containing * only the jsr instruction) but is otherwise treated * as a conditional branch. (That is to say, both its * target and next instruction begin new blocks.) */ addWorkIfNecessary(offset, true); // Fall through to next case... } default: { int next = offset + length; visitCommon(offset, length, true); addWorkIfNecessary(next, true); targetLists[offset] = IntList.makeImmutable(next, target); break; } } addWorkIfNecessary(target, true); }
/** * Helper method used by all the visitor methods. * * @param offset offset to the instruction * @param length length of the instruction, in bytes * @param nextIsLive {@code true} iff the instruction after * the indicated one is possibly-live (because this one isn't an * unconditional branch, a return, or a switch) */ private void visitCommon(int offset, int length, boolean nextIsLive) { Bits.set(liveSet, offset); if (nextIsLive) { /* * If the next instruction is flowed to by this one, just * add it to the work set, and then a subsequent visit*() * will deal with it as appropriate. */ addWorkIfNecessary(offset + length, false); } else { /* * If the next instruction isn't flowed to by this one, * then mark it as a start of a block but *don't* add it * to the work set, so that in the final phase we can know * dead code blocks as those marked as blocks but not also marked * live. */ Bits.set(blockSet, offset + length); } }