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

org.evosuite.instrumentation.coverage.DefUseInstrumentation 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.instrumentation.coverage;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.evosuite.PackageInfo;
import org.evosuite.Properties;
import org.evosuite.Properties.Criterion;
import org.evosuite.coverage.dataflow.DefUsePool;
import org.evosuite.graphs.GraphPool;
import org.evosuite.graphs.cfg.BytecodeInstruction;
import org.evosuite.graphs.cfg.RawControlFlowGraph;
import org.evosuite.testcase.execution.ExecutionTrace;
import org.evosuite.testcase.execution.ExecutionTracer;
import org.evosuite.utils.ArrayUtil;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* DefUseInstrumentation class. *

* * @author Andre Mis */ public class DefUseInstrumentation implements MethodInstrumentation { private static Logger logger = LoggerFactory.getLogger(DefUseInstrumentation.class); /* * (non-Javadoc) * * @see org.evosuite.cfg.MethodInstrumentation#analyze(org.objectweb * .asm.tree.MethodNode, org.jgrapht.Graph, java.lang.String, * java.lang.String) */ /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public void analyze(ClassLoader classLoader, MethodNode mn, String className, String methodName, int access) { RawControlFlowGraph completeCFG = GraphPool.getInstance(classLoader).getRawCFG(className, methodName); logger.info("Applying DefUse instrumentation on CFG with "+completeCFG.vertexCount() +" nodes"); Iterator j = mn.instructions.iterator(); while (j.hasNext()) { AbstractInsnNode in = j.next(); for (BytecodeInstruction v : completeCFG.vertexSet()) { if ((ArrayUtil.contains(Properties.CRITERION, Criterion.DEFUSE) || ArrayUtil.contains(Properties.CRITERION, Criterion.ALLDEFS)) && in.equals(v.getASMNode()) && v.isDefUse()) { boolean isValidDU = false; // if(v.isLocalArrayDefinition()) { // LoggingUtils.getEvoLogger().info( // "LOCAL ARRAY VAR DEF " + v.toString()+" loaded by "+v.getSourceOfStackInstruction(2).toString()); // } if (v.isMethodCallOfField()) { // keep track of field method calls, though we do not // know // how to handle them at this point during the analysis // (need complete CCFGs first) isValidDU = DefUsePool.addAsFieldMethodCall(v); } else { // keep track of uses if (v.isUse()) isValidDU = DefUsePool.addAsUse(v); // keep track of definitions if (v.isDefinition()) isValidDU = DefUsePool.addAsDefinition(v) || isValidDU; } if (isValidDU) { boolean staticContext = v.isStaticDefUse() || ((access & Opcodes.ACC_STATIC) > 0); // adding instrumentation for defuse-coverage InsnList instrumentation = getInstrumentation(v, staticContext, className, methodName, mn); if (instrumentation == null) throw new IllegalStateException("error instrumenting node " + v.toString()); if (v.isMethodCallOfField()) mn.instructions.insertBefore(v.getASMNode(), instrumentation); else if(v.isArrayStoreInstruction()) mn.instructions.insertBefore(v.getSourceOfArrayReference().getASMNode(), instrumentation); // Loading of an array is already handled by ALOAD // AILOAD would only be needed if we define DU pairs on // array indices // else if(v.isArrayLoadInstruction()) // mn.instructions.insertBefore(v.getSourceOfArrayReference().getASMNode(), instrumentation); else if(v.isUse()) mn.instructions.insert(v.getASMNode(), instrumentation); else mn.instructions.insertBefore(v.getASMNode(), instrumentation); } } } } } /** * Creates the instrumentation needed to track defs and uses * */ private InsnList getInstrumentation(BytecodeInstruction v, boolean staticContext, String className, String methodName, MethodNode mn) { InsnList instrumentation = new InsnList(); if (!v.isDefUse()) { logger.warn("unexpected DefUseInstrumentation call for a non-DU-instruction"); return instrumentation; } if (DefUsePool.isKnownAsFieldMethodCall(v)) { return getMethodInstrumentation(v, staticContext, instrumentation, mn); } if (DefUsePool.isKnownAsUse(v)) { // The actual object that is defined is on the stack _after_ the load instruction addObjectInstrumentation(v, instrumentation, mn); addCallingObjectInstrumentation(staticContext, instrumentation); instrumentation.add(new LdcInsnNode(DefUsePool.getUseCounter())); instrumentation.add(new MethodInsnNode(Opcodes.INVOKESTATIC, PackageInfo.getNameWithSlash(ExecutionTracer.class), "passedUse", "(Ljava/lang/Object;Ljava/lang/Object;I)V")); } if (DefUsePool.isKnownAsDefinition(v)) { // The actual object that is defined is on the stack _before_ the store instruction addObjectInstrumentation(v, instrumentation, mn); addCallingObjectInstrumentation(staticContext, instrumentation); instrumentation.add(new LdcInsnNode(DefUsePool.getDefCounter())); instrumentation.add(new MethodInsnNode(Opcodes.INVOKESTATIC, PackageInfo.getNameWithSlash(org.evosuite.testcase.execution.ExecutionTracer.class), "passedDefinition", "(Ljava/lang/Object;Ljava/lang/Object;I)V")); } return instrumentation; } private void addCallingObjectInstrumentation(boolean staticContext, InsnList instrumentation) { // the object on which the DU is covered is passed by the // instrumentation. // If we are in a static context, null is passed instead if (staticContext) { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } else { instrumentation.add(new VarInsnNode(Opcodes.ALOAD, 0)); // "this" } } @SuppressWarnings({ "unchecked", "unused" }) private int getNextLocalVariable(MethodNode mn) { int var = 1; List nodes = mn.localVariables; for(LocalVariableNode varNode : nodes) { if(varNode.index >= var) { var = varNode.index + 1; } } return var; } private void addObjectInstrumentation(BytecodeInstruction instruction, InsnList instrumentation, MethodNode mn) { if(instruction.isLocalVariableDefinition()) { if(instruction.getASMNode().getOpcode() == Opcodes.ALOAD) { instrumentation.add(new InsnNode(Opcodes.DUP)); } else { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } } else if(instruction.isLocalVariableUse()){ if(instruction.getASMNode().getOpcode() == Opcodes.ASTORE) { instrumentation.add(new InsnNode(Opcodes.DUP)); } else { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } } else if(instruction.isArrayStoreInstruction()) { // Object, index, value instrumentation.add(new InsnNode(Opcodes.DUP)); } else if(instruction.isArrayLoadInstruction()) { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } else if(instruction.isFieldNodeDU()) { // TODO: FieldNodeDU takes care of ArrayStore - why? Type type = Type.getType(instruction.getFieldType()); if(type.getSort() == Type.OBJECT) { instrumentation.add(new InsnNode(Opcodes.DUP)); } else { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } } else if(instruction.isMethodCall()) { Type type = Type.getReturnType(instruction.getMethodCallDescriptor()); if(type.getSort() == Type.OBJECT) { instrumentation.add(new InsnNode(Opcodes.DUP)); } else { instrumentation.add(new InsnNode(Opcodes.ACONST_NULL)); } } else { assert false : "Unknown instruction"; } } @SuppressWarnings("unchecked") private int getNextLocalNum(MethodNode mn) { List variables = mn.localVariables; int max = 0; for(LocalVariableNode node : variables) { if(node.index > max) max = node.index; } return max + 1; } private InsnList getMethodInstrumentation(BytecodeInstruction call, boolean staticContext, InsnList instrumentation, MethodNode mn) { String descriptor = call.getMethodCallDescriptor(); Type[] args = Type.getArgumentTypes(descriptor); int loc = getNextLocalNum(mn); Map to = new HashMap(); for (int i = args.length - 1; i >= 0; i--) { Type type = args[i]; instrumentation.add(new VarInsnNode(type.getOpcode(Opcodes.ISTORE), loc)); to.put(i, loc); loc++; } // instrumentation.add(new InsnNode(Opcodes.DUP));//callee addObjectInstrumentation(call, instrumentation, mn); addCallingObjectInstrumentation(staticContext, instrumentation); // field method calls get special treatment: // during instrumentation it is not clear whether a field method // call constitutes a definition or a use. So the instrumentation // will call a special function of the ExecutionTracer which will // redirect the call to either passedUse() or passedDefinition() // using the information available during runtime (the CCFGs) instrumentation.add(new LdcInsnNode(DefUsePool.getDefUseCounter())); instrumentation.add(new MethodInsnNode(Opcodes.INVOKESTATIC, PackageInfo.getNameWithSlash(ExecutionTracer.class), "passedFieldMethodCall", "(Ljava/lang/Object;Ljava/lang/Object;I)V")); for (int i = 0; i < args.length; i++) { Type type = args[i]; instrumentation.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), to.get(i))); } return instrumentation; } /* * (non-Javadoc) * * @see org.evosuite.cfg.MethodInstrumentation#executeOnExcludedMethods () */ /** {@inheritDoc} */ @Override public boolean executeOnExcludedMethods() { return false; } /* * (non-Javadoc) * * @see org.evosuite.cfg.MethodInstrumentation#executeOnMainMethod() */ /** {@inheritDoc} */ @Override public boolean executeOnMainMethod() { return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy