All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.graphs.cfg.ASMWrapper Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.graphs.cfg;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LineNumberNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.objectweb.asm.util.Printer;

// TODO: the following methods about control dependence are flawed right now:
// - the BytecodeInstruction of a Branch does not have it's control dependent
// branchId
// but it's own branchId set
// - this seems to be OK for ChromosomeRecycling as it stands, but
// especially getControlDependentBranch() will fail hard when called on a Branch
// the same may hold for the other ones as well.
// - look at BranchCoverageGoal and Branch for more information

/**
 * Wrapper class for the underlying byteCode instruction library ASM
 * 
 * Gives access to a lot of methods that interpret the raw information in
 * AbstractInsnNode to usable chunks of information, inside EvoSuite
 * 
 * This class is supposed to hide the ASM library from the rest of EvoSuite as
 * much as possible
 * 
 * After initialization, all information about byteCode instructions should be
 * accessible via the BytecodeInstruction-, DefUse- and BranchPool. Each of
 * those has data structures holding all BytecodeInstruction, DefUse and Branch
 * objects respectively created during initialization.
 * 
 * BytecodeInstruction directly extends ASMWrapper and is the first way to
 * instantiate an ASMWrapper. Branch and DefUse extend BytecodeInstruction,
 * where DefUse is abstract and Branch is not ("concrete"?) DefUse is further
 * extended by Definition and Use
 * 
 * @author Andre Mis
 */
public abstract class ASMWrapper {

	// from ASM library
	protected AbstractInsnNode asmNode;
	protected CFGFrame frame;

	/**
	 * 

* getASMNode *

* * @return a {@link org.objectweb.asm.tree.AbstractInsnNode} object. */ public AbstractInsnNode getASMNode() { return asmNode; } /** *

* getInstructionType *

* * @return a {@link java.lang.String} object. */ public String getInstructionType() { if (asmNode.getOpcode() >= 0 && asmNode.getOpcode() < Printer.OPCODES.length) return Printer.OPCODES[asmNode.getOpcode()]; if (isLineNumber()) return "LINE " + this.getLineNumber(); return getType(); } public String getMethodCallDescriptor() { if (!isMethodCall()) return null; MethodInsnNode meth = (MethodInsnNode) asmNode; return meth.desc; } /** *

* getType *

* * @return a {@link java.lang.String} object. */ public String getType() { // TODO explain String type = ""; if (asmNode.getType() >= 0 && asmNode.getType() < Printer.TYPES.length) type = Printer.TYPES[asmNode.getType()]; return type; } /** *

* getInstructionId *

* * @return a int. */ public abstract int getInstructionId(); /** *

* getMethodName *

* * @return a {@link java.lang.String} object. */ public abstract String getMethodName(); /** *

* getClassName *

* * @return a {@link java.lang.String} object. */ public abstract String getClassName(); public abstract boolean isMethodCallOfField(); public abstract String getFieldMethodCallName(); // methods for branch analysis /** *

* isActualBranch *

* * @return a boolean. */ public boolean isActualBranch() { return isBranch() || isSwitch(); } /** *

* isSwitch *

* * @return a boolean. */ public boolean isSwitch() { return isLookupSwitch() || isTableSwitch(); } /** *

* canReturnFromMethod *

* * @return a boolean. */ public boolean canReturnFromMethod() { return isReturn() || isThrow(); } /** *

* isReturn *

* * @return a boolean. */ public boolean isReturn() { switch (asmNode.getOpcode()) { case Opcodes.RETURN: case Opcodes.ARETURN: case Opcodes.IRETURN: case Opcodes.LRETURN: case Opcodes.DRETURN: case Opcodes.FRETURN: return true; default: return false; } } /** *

* isThrow *

* * @return a boolean. */ public boolean isThrow() { if (asmNode.getOpcode() == Opcodes.ATHROW) { // TODO: Need to check if this is a caught exception? return true; } return false; } /** *

* isTableSwitch *

* * @return a boolean. */ public boolean isTableSwitch() { return (asmNode instanceof TableSwitchInsnNode); } /** *

* isLookupSwitch *

* * @return a boolean. */ public boolean isLookupSwitch() { return (asmNode instanceof LookupSwitchInsnNode); } /** *

* isBranchLabel *

* * @return a boolean. */ public boolean isBranchLabel() { if (asmNode instanceof LabelNode && ((LabelNode) asmNode).getLabel().info instanceof Integer) { return true; } return false; } /** *

* isJump *

* * @return a boolean. */ public boolean isJump() { return (asmNode instanceof JumpInsnNode); } /** *

* isInvokeStatic *

* * @return a boolean representing whether the instruction is a static method * call. */ public boolean isInvokeStatic() { if (asmNode instanceof MethodInsnNode) { return (asmNode.getOpcode() == Opcodes.INVOKESTATIC); } return false; } /** *

* isGoto *

* * @return a boolean. */ public boolean isGoto() { if (asmNode instanceof JumpInsnNode) { return (asmNode.getOpcode() == Opcodes.GOTO); } return false; } /** *

* isBranch *

* * @return a boolean. */ public boolean isBranch() { return (isJump() && !isGoto()); } // public int getBranchId() { // // return ((Integer)((LabelNode)node).getLabel().info).intValue(); // return line_no; // } /** *

* isIfNull *

* * @return a boolean. */ public boolean isIfNull() { if (asmNode instanceof JumpInsnNode) { return (asmNode.getOpcode() == Opcodes.IFNULL); } return false; } /** *

* isFrame *

* * @return a boolean. */ public boolean isFrame() { return asmNode instanceof FrameNode; } /** *

* isMethodCall *

* * @return a boolean. */ public boolean isMethodCall() { return asmNode instanceof MethodInsnNode; } /** * Returns the conjunction of the name and method descriptor of the method * called by this instruction * * @return a {@link java.lang.String} object. */ public String getCalledMethod() { if (!isMethodCall()) return null; MethodInsnNode meth = (MethodInsnNode) asmNode; return meth.name + meth.desc; } /** * Returns the conjunction of the name of the method called by this * instruction * * @return a {@link java.lang.String} object. */ public String getCalledMethodName() { if (!isMethodCall()) return null; MethodInsnNode meth = (MethodInsnNode) asmNode; return meth.name; } /** * Returns true if and only if the class of the method called by this * instruction is the same as the given className * * @param className * a {@link java.lang.String} object. * @return a boolean. */ public boolean isMethodCallForClass(String className) { if (isMethodCall()) { // System.out.println("in isMethodCallForClass of "+toString()+" for arg "+className+" calledMethodsClass: "+getCalledMethodsClass()+" calledMethod "+getCalledMethod()); return getCalledMethodsClass().equals(className); } return false; } /** * Returns the class of the method called by this instruction * * @return a {@link java.lang.String} object. */ public String getCalledMethodsClass() { if (isMethodCall()) { MethodInsnNode mn = (MethodInsnNode) asmNode; return mn.owner.replaceAll("/", "\\."); } return null; } /** * Returns the number of arguments of the method called by this instruction * * @return a int. */ public int getCalledMethodsArgumentCount() { if (isMethodCall()) { // int r = 0; MethodInsnNode mn = (MethodInsnNode) asmNode; Type[] argTypes = Type.getArgumentTypes(mn.desc); return argTypes.length; // for(Type argType : argTypes) { // r+=argType.getSize(); // } // return r; } return -1; } /** *

* isLoadConstant *

* * @return a boolean. */ public boolean isLoadConstant() { return asmNode.getOpcode() == Opcodes.LDC; } /** *

* isConstant *

* * @return a boolean. */ public boolean isConstant() { switch (asmNode.getOpcode()) { case Opcodes.LDC: case Opcodes.ICONST_0: case Opcodes.ICONST_1: case Opcodes.ICONST_2: case Opcodes.ICONST_3: case Opcodes.ICONST_4: case Opcodes.ICONST_5: case Opcodes.ICONST_M1: case Opcodes.LCONST_0: case Opcodes.LCONST_1: case Opcodes.DCONST_0: case Opcodes.DCONST_1: case Opcodes.FCONST_0: case Opcodes.FCONST_1: case Opcodes.FCONST_2: case Opcodes.BIPUSH: case Opcodes.SIPUSH: return true; default: return false; } } // methods for defUse analysis /** *

* isDefUse *

* * @return a boolean. */ public boolean isDefUse() { return isDefinition() || isUse(); } /** *

* isFieldDU *

* * @return a boolean. */ public boolean isFieldDU() { return isFieldDefinition() || isFieldUse(); } public boolean isFieldNodeDU() { return isFieldNodeDefinition() || isFieldNodeUse(); } /** *

* isLocalDU *

* * @return a boolean. */ public boolean isLocalDU() { return isLocalVariableDefinition() || isLocalVariableUse(); } /** *

* isDefinition *

* * @return a boolean. */ public boolean isDefinition() { return isFieldDefinition() || isLocalVariableDefinition(); } /** *

* isUse *

* * @return a boolean. */ public boolean isUse() { return isFieldUse() || isLocalVariableUse() || isArrayLoadInstruction(); } public abstract boolean isFieldMethodCallDefinition(); public abstract boolean isFieldMethodCallUse(); /** *

* isFieldDefinition *

* * @return a boolean. */ public boolean isFieldDefinition() { return asmNode.getOpcode() == Opcodes.PUTFIELD || asmNode.getOpcode() == Opcodes.PUTSTATIC || isFieldArrayDefinition() || isFieldMethodCallDefinition(); } /** *

* isFieldDefinition *

* * @return a boolean. */ public boolean isFieldNodeDefinition() { return asmNode.getOpcode() == Opcodes.PUTFIELD || asmNode.getOpcode() == Opcodes.PUTSTATIC || isFieldArrayDefinition(); } /** *

* isFieldUse *

* * @return a boolean. */ public boolean isFieldUse() { return asmNode.getOpcode() == Opcodes.GETFIELD || asmNode.getOpcode() == Opcodes.GETSTATIC || isFieldMethodCallUse(); } /** *

* isFieldUse *

* * @return a boolean. */ public boolean isFieldNodeUse() { return asmNode.getOpcode() == Opcodes.GETFIELD || asmNode.getOpcode() == Opcodes.GETSTATIC; } /** *

* isStaticDefUse *

* * @return a boolean. */ public boolean isStaticDefUse() { return asmNode.getOpcode() == Opcodes.PUTSTATIC || asmNode.getOpcode() == Opcodes.GETSTATIC || isStaticArrayUsage(); } // retrieving information about variable names from ASM /** *

* getDUVariableName *

* * @return a {@link java.lang.String} object. */ public String getVariableName() { if (isArrayStoreInstruction()) { return getArrayVariableName(); } else if(isArrayLoadInstruction()) { return getArrayVariableName(); } else if (isLocalDU()) { return getLocalVariableName(); } else if (isMethodCallOfField()) { return getFieldMethodCallName(); } else if (isFieldDU()) { return getFieldName(); } else { return null; } } /** *

* getFieldName *

* * @return a {@link java.lang.String} object. */ protected String getFieldSimpleName() { FieldInsnNode fieldNode = (FieldInsnNode) asmNode; return fieldNode.name; // return fieldNode.name; } /** *

* getFieldName *

* * @return a {@link java.lang.String} object. */ protected String getFieldName() { FieldInsnNode fieldNode = (FieldInsnNode) asmNode; return fieldNode.owner + "." + fieldNode.name; // return fieldNode.name; } /** *

* getFieldName *

* * @return a {@link java.lang.String} object. */ public String getFieldType() { FieldInsnNode fieldNode = (FieldInsnNode) asmNode; return fieldNode.desc; // return fieldNode.name; } /** *

* getLocalVarName *

* * @return a {@link java.lang.String} object. */ protected String getLocalVariableName() { String ret = getMethodName() + "_LV_" + getLocalVariableSlot(); return ret; } // TODO unsafe /** *

* getLocalVar *

* * @return a int. */ public int getLocalVariableSlot() { if (asmNode instanceof VarInsnNode) return ((VarInsnNode) asmNode).var; else if (asmNode instanceof IincInsnNode) return ((IincInsnNode) asmNode).var; else return -1; } /** *

* isLocalVarDefinition *

* * @return a boolean. */ public boolean isLocalVariableDefinition() { return asmNode.getOpcode() == Opcodes.ISTORE || asmNode.getOpcode() == Opcodes.LSTORE || asmNode.getOpcode() == Opcodes.FSTORE || asmNode.getOpcode() == Opcodes.DSTORE || asmNode.getOpcode() == Opcodes.ASTORE || asmNode.getOpcode() == Opcodes.IINC || isLocalArrayDefinition(); } /** *

* isLocalVarUse *

* * @return a boolean. */ public boolean isLocalVariableUse() { return asmNode.getOpcode() == Opcodes.ILOAD || asmNode.getOpcode() == Opcodes.LLOAD || asmNode.getOpcode() == Opcodes.FLOAD || asmNode.getOpcode() == Opcodes.DLOAD || asmNode.getOpcode() == Opcodes.IINC || (asmNode.getOpcode() == Opcodes.ALOAD && !loadsReferenceToThis()); } public boolean isIINC() { return asmNode.getOpcode() == Opcodes.IINC; } /** * Determines whether this is the special ALOAD that pushes 'this' onto the * stack * * In non static methods the variable slot 0 holds the reference to "this". * Loading this reference is not seen as a Use for defuse purposes. This * method checks if this is the case * * @return a boolean. */ public boolean loadsReferenceToThis() { if (getRawCFG().isStaticMethod()) { return false; } return asmNode.getOpcode() == Opcodes.ALOAD && getLocalVariableSlot() == 0; } public abstract RawControlFlowGraph getRawCFG(); public boolean isLocalArrayDefinition() { if (!isArrayStoreInstruction()) return false; // only local var if arrayref on stack is from local var use BytecodeInstruction arrayLoader = getSourceOfArrayReference(); if (arrayLoader == null) return false; return arrayLoader.isLocalVariableUse(); } public boolean isFieldArrayDefinition() { if (!isArrayStoreInstruction()) return false; // only field var if arrayref on stack is from field var use BytecodeInstruction arrayLoader = getSourceOfArrayReference(); if (arrayLoader == null) return false; return arrayLoader.isFieldUse(); } public boolean isStaticArrayUsage() { if (!isArrayStoreInstruction()) return false; BytecodeInstruction arrayLoader = getSourceOfArrayReference(); if (arrayLoader == null) return false; return arrayLoader.isStaticDefUse(); } public boolean isArrayStoreInstruction() { return asmNode.getOpcode() == Opcodes.IASTORE || asmNode.getOpcode() == Opcodes.LASTORE || asmNode.getOpcode() == Opcodes.FASTORE || asmNode.getOpcode() == Opcodes.DASTORE || asmNode.getOpcode() == Opcodes.AASTORE; } public boolean isArrayLoadInstruction() { return asmNode.getOpcode() == Opcodes.IALOAD || asmNode.getOpcode() == Opcodes.LALOAD || asmNode.getOpcode() == Opcodes.FALOAD || asmNode.getOpcode() == Opcodes.DALOAD || asmNode.getOpcode() == Opcodes.AALOAD; } protected String getArrayVariableName() { BytecodeInstruction arrayLoader = getSourceOfArrayReference(); if (arrayLoader == null) return null; return arrayLoader.getVariableName(); } public abstract BytecodeInstruction getSourceOfArrayReference(); /** *

* isDefinitionForVariable *

* * @param var * a {@link java.lang.String} object. * @return a boolean. */ public boolean isDefinitionForVariable(String var) { return (isDefinition() && getVariableName().equals(var)); } /** *

* isInvokeSpecial *

* * @return a boolean. */ public boolean isInvokeSpecial() { return asmNode.getOpcode() == Opcodes.INVOKESPECIAL; } /** * Checks whether this instruction is an INVOKESPECIAL instruction that * calls a constructor. * * @return a boolean. */ public boolean isConstructorInvocation() { if (!isInvokeSpecial()) return false; MethodInsnNode invoke = (MethodInsnNode) asmNode; // if (!invoke.owner.equals(className.replaceAll("\\.", "/"))) // return false; return invoke.name.equals(""); } /** * Checks whether this instruction is an INVOKESPECIAL instruction that * calls a constructor of the given class. * * @param className * a {@link java.lang.String} object. * @return a boolean. */ public boolean isConstructorInvocation(String className) { if (!isInvokeSpecial()) return false; MethodInsnNode invoke = (MethodInsnNode) asmNode; if (!invoke.owner.equals(className.replaceAll("\\.", "/"))) return false; return invoke.name.equals(""); } // other classification methods /** * Determines if this instruction is a line number instruction * * More precisely this method checks if the underlying asmNode is a * LineNumberNode * * @return a boolean. */ public boolean isLineNumber() { return (asmNode instanceof LineNumberNode); } /** *

* getLineNumber *

* * @return a int. */ public int getLineNumber() { if (!isLineNumber()) return -1; return ((LineNumberNode) asmNode).line; } /** *

* isLabel *

* * @return a boolean. */ public boolean isLabel() { return asmNode instanceof LabelNode; } // sanity checks /** *

* sanityCheckAbstractInsnNode *

* * @param node * a {@link org.objectweb.asm.tree.AbstractInsnNode} object. */ public boolean sanityCheckAbstractInsnNode(AbstractInsnNode node) { if (node == null) return false; //throw new IllegalArgumentException("null given"); if (!node.equals(this.asmNode)) return false; // // throw new IllegalStateException("sanity check failed for " // + node.toString() + " on " + getMethodName() + toString()); return true; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy