下面列出了怎么用org.objectweb.asm.tree.LineNumberNode的API类实例代码及写法,或者点击链接到github查看源代码。
public static List<LineNumberNodeWrapper> collectLineNumberNodeList(InsnList instructions) {
List<LineNumberNodeWrapper> list = new ArrayList<>();
AbstractInsnNode node = instructions.getFirst();
while (node != instructions.getLast()) {
if (node instanceof LineNumberNode) {
if (CollectionUtils.isNotEmpty(list)) {
list.get(list.size() - 1).setNext(node);
}
list.add(new LineNumberNodeWrapper(LineNumberNode.class.cast(node)));
}
node = node.getNext();
}
if (CollectionUtils.isNotEmpty(list)) {
list.get(list.size() - 1).setNext(instructions.getLast());
}
return list;
}
@Override
public void visit(Map<String, ClassNode> classMap) {
classMap.values().forEach(classNode -> classNode.methods.forEach(methodNode ->
Arrays.stream(methodNode.instructions.toArray()).forEachOrdered(ain -> {
try {
final AbstractInsnNode current = ain.getNext();
if (current == null)
return;
if (!(current instanceof LineNumberNode))
return;
methodNode.instructions.iterator().set(new LineNumberNode(RandomUtil.nextInt(), ((LineNumberNode) current).start));
} catch (Exception ignored) {
}
})));
}
@Override
public void transform() {
AtomicInteger counter = new AtomicInteger();
getClassWrappers().stream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper ->
classWrapper.getMethods().stream().filter(methodWrapper -> !excluded(methodWrapper)
&& methodWrapper.hasInstructions()).forEach(methodWrapper -> {
MethodNode methodNode = methodWrapper.getMethodNode();
Stream.of(methodNode.instructions.toArray()).filter(insn -> insn instanceof LineNumberNode)
.forEach(insn -> {
methodNode.instructions.remove(insn);
counter.incrementAndGet();
});
}));
Main.info(String.format("Removed %d line numbers.", counter.get()));
}
/**
* Finds the line number closest to the given node
*
* @param node the instruction node to get a line number for
* @return the closest line number, or -1 if not known
*/
public static int findLineNumber(@NonNull AbstractInsnNode node) {
AbstractInsnNode curr = node;
// First search backwards
while (curr != null) {
if (curr.getType() == AbstractInsnNode.LINE) {
return ((LineNumberNode) curr).line;
}
curr = curr.getPrevious();
}
// Then search forwards
curr = node;
while (curr != null) {
if (curr.getType() == AbstractInsnNode.LINE) {
return ((LineNumberNode) curr).line;
}
curr = curr.getNext();
}
return -1;
}
public static InsnList getImportantList(InsnList list) {
if (list.size() == 0) {
return list;
}
HashMap<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode) {
labels.put((LabelNode) insn, (LabelNode) insn);
}
}
InsnList importantNodeList = new InsnList();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode || insn instanceof LineNumberNode) {
continue;
}
importantNodeList.add(insn.clone(labels));
}
return importantNodeList;
}
public static InsnList getImportantList(InsnList list) {
if (list.size() == 0) {
return list;
}
HashMap<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode) {
labels.put((LabelNode) insn, (LabelNode) insn);
}
}
InsnList importantNodeList = new InsnList();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode || insn instanceof LineNumberNode) {
continue;
}
importantNodeList.add(insn.clone(labels));
}
return importantNodeList;
}
public static InsnList getImportantList(InsnList list) {
if (list.size() == 0) {
return list;
}
HashMap<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode) {
labels.put((LabelNode) insn, (LabelNode) insn);
}
}
InsnList importantNodeList = new InsnList();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode || insn instanceof LineNumberNode) {
continue;
}
importantNodeList.add(insn.clone(labels));
}
return importantNodeList;
}
/**
* Find line number associated with an instruction.
* @param insnList instruction list for method
* @param insnNode instruction within method being searched against
* @throws NullPointerException if any argument is {@code null} or contains {@code null}
* @throws IllegalArgumentException if arguments aren't all from the same method
* @return line number node associated with the instruction, or {@code null} if no line number exists
*/
public static LineNumberNode findLineNumberForInstruction(InsnList insnList, AbstractInsnNode insnNode) {
Validate.notNull(insnList);
Validate.notNull(insnNode);
int idx = insnList.indexOf(insnNode);
Validate.isTrue(idx != -1);
// Get index of labels and insnNode within method
ListIterator<AbstractInsnNode> insnIt = insnList.iterator(idx);
while (insnIt.hasPrevious()) {
AbstractInsnNode node = insnIt.previous();
if (node instanceof LineNumberNode) {
return (LineNumberNode) node;
}
}
return null;
}
/**
* <p>
* This method scans the instructions for 'else' and returns the node
* </p>
*
* @param ifTargetIndex
* Index of the target instruction of 'if'
* @param endIndex
* Index of the end instruction upto which scanner will work
* @param nestingLevel
* nesting level
* @return Node
*/
private AbstractInsnNode scanForElse(int ifTargetIndex, int endIndex) {
boolean lineNumberFound = false;
LabelNode ln = (LabelNode) this.insnArr[ifTargetIndex];
for (int i = ifTargetIndex + 1; i <= endIndex; i++) {
AbstractInsnNode ain = this.insnArr[i];
if (ain instanceof JumpInsnNode
&& InstrumentUtil.getJumpInsnOpcodesMap().containsKey(
ain.getOpcode())) {
if (!lineNumberFound) {
return ain;
}
} else if (ain instanceof LineNumberNode) {
LineNumberNode lnn = (LineNumberNode) ain;
// if the line does not belong to the label
if (lnn.start != ln) {
lineNumberFound = true;
return null;
}
}
}
return null;
}
@Override
public void write(DoStmtToken token) {
expr.writeDefineVariables(token.getLocal());
LabelNode start = expr.writeLabel(node, token.getMeta().getStartLine());
LabelNode end = new LabelNode();
method.pushJump(end, start);
expr.write(token.getBody());
method.popJump();
expr.writeConditional(token.getCondition(), end);
add(new JumpInsnNode(GOTO, start));
add(end);
add(new LineNumberNode(token.getMeta().getEndLine(), end));
expr.writeUndefineVariables(token.getLocal());
}
private void writeBody(IfStmtToken token) {
LabelNode end = new LabelNode();
LabelNode elseL = new LabelNode();
expr.writePopBoolean();
add(new JumpInsnNode(IFEQ, token.getElseBody() != null ? elseL : end));
expr.stackPop();
if (token.getBody() != null) {
expr.write(token.getBody());
}
if (token.getElseBody() != null){
add(new JumpInsnNode(GOTO, end));
add(elseL);
expr.write(token.getElseBody());
}
add(end);
add(new LineNumberNode(token.getMeta().getEndLine(), end));
}
@Override
public void write(WhileStmtToken token) {
expr.writeDefineVariables(token.getLocal());
LabelNode start = expr.writeLabel(node, token.getMeta().getStartLine());
LabelNode end = new LabelNode();
expr.writeConditional(token.getCondition(), end);
method.pushJump(end, start);
expr.write(BodyStmtToken.class, token.getBody());
method.popJump();
add(new JumpInsnNode(GOTO, start));
add(end);
add(new LineNumberNode(token.getMeta().getEndLine(), end));
expr.writeUndefineVariables(token.getLocal());
}
void addError(AbstractInsnNode node, String error) {
// try to find a line number to report
int line = -1;
AbstractInsnNode prev = node;
while (prev != null) {
if (prev instanceof LineNumberNode) {
line = ((LineNumberNode) prev).line;
break;
}
prev = prev.getPrevious();
}
String message = "line " + line + ": " + error;
errors.add(new Error(node, message));
}
@Override
public LineNumberNode deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = (JsonObject) json;
int line = jsonObject.get("line").getAsInt();
LabelNode start = context.deserialize(jsonObject.get("start"), LabelNode.class);
return new LineNumberNode(line, start);
}
@Override
public JsonElement serialize(LineNumberNode src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
object.add("line", context.serialize(src.line));
object.add("start", context.serialize(src.start));
return object;
}
@Test
public void testIsInstruction() {
Assert.assertFalse(ASMUtils.isInstruction(
PowerMockito.mock(FrameNode.class)));
Assert.assertFalse(ASMUtils.isInstruction(
PowerMockito.mock(LabelNode.class)));
Assert.assertFalse(ASMUtils.isInstruction(
PowerMockito.mock(LineNumberNode.class)));
Assert.assertTrue(ASMUtils.isInstruction(
PowerMockito.mock(InsnNode.class)));
}
public InsnPattern test(AbstractInsnNode start) {
return ASMHelper.findPattern(
start,
insnPredicates.size(),
// isValidNode
(node) ->
!testFlag(node, FrameNode.class, IGNORE_FRAMES)
&& !testFlag(node, LabelNode.class, IGNORE_LABELS)
&& !testFlag(node, LineNumberNode.class, IGNORE_LINENUMBERS),
// nodePredicate
(found, node) -> insnPredicates.get(found).test(node),
InsnPattern::new);
}
public static void removeLines(MethodNode mn) {
int i = 0;
for (AbstractInsnNode ain : mn.instructions.toArray()) {
if (ain instanceof LineNumberNode) {
mn.instructions.remove(ain);
i++;
}
}
JByteMod.LOGGER.log("Removed " + i + " nodes!");
}
@Override
public boolean transform() throws Throwable {
classNodes().forEach(classNode -> {
classNode.methods.forEach(methodNode -> {
Iterator<AbstractInsnNode> it = methodNode.instructions.iterator();
while (it.hasNext()) {
if (it.next() instanceof LineNumberNode) {
it.remove();
}
}
});
});
return true;
}
/**
* Generates instructions for line numbers. This is useful for debugging. For example, you can put a line number of 99999 or some other
* special number to denote that the code being executed is instrumented code. Then if a stacktrace happens, you'll know that if
* instrumented code was immediately involved.
* @param num line number
* @return instructions for a line number
* @throws IllegalArgumentException if {@code num < 0}
*/
public static InsnList lineNumber(int num) {
Validate.isTrue(num >= 0);
InsnList ret = new InsnList();
LabelNode labelNode = new LabelNode();
ret.add(labelNode);
ret.add(new LineNumberNode(num, labelNode));
return ret;
}
/**
* Offset the line numbers in the target method node by the base
* lineoffset for this stratum
*
* @param method method to operate upon
*/
public void applyOffset(MethodNode method) {
for (Iterator<AbstractInsnNode> iter = method.instructions.iterator(); iter.hasNext();) {
AbstractInsnNode node = iter.next();
if (node instanceof LineNumberNode) {
((LineNumberNode)node).line += this.lineOffset - 1;
}
}
}
/**
* This will return an InsnList which would be reading all instructions from
* beginning of statement till it reaches LineNumberNode
*
* @param node
* - the node from which instruction list is read till starting
* @return
*/
public static List<AbstractInsnNode> getInstructionListFromBeginingofStatement(
AbstractInsnNode node, List<AbstractInsnNode> nodeList) {
if (node instanceof LineNumberNode) {
return nodeList;
}
getInstructionListFromBeginingofStatement(node.getPrevious(), nodeList);
nodeList.add(node);
return nodeList;
}
/**
* <p>
* This method finds whether the if block represents a ternary operator or
* not. It also injects necessary instructions to inject logging before and
* after ternary operator usage.
* </p>
*
* @param ifStartIndex
* index of if block start
* @param endIndex
* index of else end
* @param ainIfBlock
* Instructions where logging to be injected
* @param nestingLevel
* nesting level
*/
private boolean processTernaryOperator(int ifStartIndex, int endIndex,
int nestingLevel) {
boolean ternaryOperatorFound = true;
for (int g = ifStartIndex; g < endIndex; g++) {
if (this.insnArr[g] instanceof LineNumberNode) {
ternaryOperatorFound = false;
break;
}
}
if (ternaryOperatorFound) {
InsnList[] il = new InsnList[2];
String cSymbol = env.getClassSymbol(getLogClazzName());
String mSymbol = env.getMethodSymbol(getLogClazzName(), cSymbol, name);
il[0] = InstrumentUtil.addLogMessage(cSymbol, mSymbol,
InstrumentationMessageLoader
.getMessage(MessageConstants.MSG_BEFORE_TERNARY),
"", "" + this.currentIfCount[nestingLevel]);
il[1] = InstrumentUtil.addLogMessage(cSymbol, mSymbol,
InstrumentationMessageLoader
.getMessage(MessageConstants.MSG_AFTER_TERNARY),
"", "" + this.currentIfCount[nestingLevel]);
}
return ternaryOperatorFound;
}
/**
* <p>
* This method processes loops and add logging
* </p>
*
* @param firstStmtInLoopIndex
* Index of the first statement in the loop.
* @param loopEndIndex
* Index where loop ends.
* @param nestingLevel
* nesting level
*/
private void processLoop(int firstStmtInLoopIndex, int loopEndIndex,
int nestingLevel) {
logger.debug(firstStmtInLoopIndex + " " + loopEndIndex);
this.currentLoopCount[nestingLevel]++;
AbstractInsnNode abstractInsnNode;
// adding loop entry
abstractInsnNode = this.insnArr[firstStmtInLoopIndex];
AbstractInsnNode gotoNode = abstractInsnNode.getPrevious();
AbstractInsnNode lineNode = abstractInsnNode.getNext();
if ((gotoNode instanceof JumpInsnNode && Opcodes.GOTO == gotoNode
.getOpcode()) || (!(lineNode instanceof LineNumberNode))) {
lineNode = getPreviousLineNode(abstractInsnNode);
}
Integer lineNumber = ((LineNumberNode) lineNode).line;
String cSymbol = env.getClassSymbol(getClassName());
String mSymbol = env.getMethodSymbol(getClassName(), cSymbol, name);
InsnList il1 = InstrumentUtil.addLogMessage(cSymbol,mSymbol,
InstrumentationMessageLoader
.getMessage(MessageConstants.ENTERED_LOOP), lineNumber
.toString(), this.currentLoopCount[nestingLevel]
.toString());
instructions.insertBefore(lineNode.getPrevious(), il1);
// handling map reduce output in the loop
handleCtxWrite(firstStmtInLoopIndex, loopEndIndex);
// adding loop exit
abstractInsnNode = this.insnArr[loopEndIndex];
InsnList il2 = InstrumentUtil.addloopCounterLogging(cSymbol,
mSymbol, InstrumentationMessageLoader
.getMessage(MessageConstants.EXITING_LOOP),
this.localVariableSize, this.currentLoopCount[nestingLevel]
.toString());
// resetting the counter to ZERO
il2.add(new LabelNode());
il2.add(new InsnNode(Opcodes.ICONST_0));
il2.add(new VarInsnNode(Opcodes.ISTORE, this.localVariableSize));
instructions.insert(abstractInsnNode.getNext(), il2);
this.addLocalVariable(this.localVariableSize);
}
/**
* <p>
* Finds whether a line node is found in the given range
* </p>
*
* @param startIndex
* start index for the scan
* @param endIndex
* end index for the line
* @return boolean true if line node is found
*/
private boolean scanForLine(int startIndex, int endIndex) {
boolean lineFound = false;
for (int k = startIndex; k <= endIndex; k++) {
AbstractInsnNode ain = insnArr[k];
if (ain instanceof LineNumberNode) {
lineFound = true;
break;
}
}
return lineFound;
}
public int getLineNumber() {
AbstractInsnNode node = this.methodNode.instructions.getFirst();
while (node != null) {
if (node.getType() == AbstractInsnNode.LINE) {
return ((LineNumberNode) node).line;
}
node = node.getNext();
}
return 0;
}
public boolean search() {
for (AbstractInsnNode ain : insns.toArray()) {
if (ain instanceof LineNumberNode || ain instanceof FrameNode)
continue;
if (pattern.accept(ain)) {
matches.add(pattern.getLastMatch());
pattern.resetMatch();
}
}
return size() != 0;
}
public LabelNode writeLabel(MethodNode mv, int lineNumber){
LabelNode node = new LabelNode(new Label());
mv.instructions.add(node);
if (lineNumber != -1)
mv.instructions.add(new LineNumberNode(lineNumber, node));
return node;
}
public LineNumberNodeWrapper(LineNumberNode node) {
this.node = node;
}
public LineNumberNode getNode() {
return node;
}