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

org.evosuite.graphs.cfg.BytecodeInstructionPool 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 java.util.*;

import org.evosuite.coverage.branch.BranchPool;
import org.evosuite.runtime.instrumentation.AnnotatedLabel;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* BytecodeInstructionPool class. *

* * @author Andre Mis */ public class BytecodeInstructionPool { private static Logger logger = LoggerFactory.getLogger(BytecodeInstructionPool.class); private static Map instanceMap = new LinkedHashMap<>(); private final ClassLoader classLoader; private BytecodeInstructionPool(ClassLoader classLoader) { this.classLoader = classLoader; } public static BytecodeInstructionPool getInstance(ClassLoader classLoader) { if (!instanceMap.containsKey(classLoader)) { instanceMap.put(classLoader, new BytecodeInstructionPool(classLoader)); } return instanceMap.get(classLoader); } // maps className -> method inside that class -> list of // BytecodeInstructions private final Map>> instructionMap = new LinkedHashMap<>(); private final List knownMethodNodes = new ArrayList<>(); // fill the pool /** * Called by each CFGGenerator for it's corresponding method. * * The MethodNode contains all instructions within a method. A call to * registerMethodNode() fills the instructionMap of the * BytecodeInstructionPool with the instructions in that method and returns * a List containing the BytecodeInstructions within that method. * * While registering all instructions the lineNumber of each * BytecodeInstruction is set. * * @param node * a {@link org.objectweb.asm.tree.MethodNode} object. * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @return a {@link java.util.List} object. */ public List registerMethodNode(MethodNode node, String className, String methodName) { registerMethodNode(node); int lastLineNumber = -1; int bytecodeOffset = 0; for (int instructionId = 0; instructionId < node.instructions.size(); instructionId++) { AbstractInsnNode instructionNode = node.instructions.get(instructionId); BytecodeInstruction instruction = BytecodeInstructionFactory.createBytecodeInstruction(classLoader, className, methodName, instructionId, bytecodeOffset, instructionNode); if (instruction.isLineNumber()) lastLineNumber = instruction.getLineNumber(); else if (lastLineNumber != -1) instruction.setLineNumber(lastLineNumber); bytecodeOffset += getBytecodeIncrement(instructionNode); if (!instruction.isLabel() && !instruction.isLineNumber() && !instruction.isFrame()) { bytecodeOffset++; } registerInstruction(instruction); } List r = getInstructionsIn(className, methodName); if (r == null || r.size() == 0) throw new IllegalStateException( "expect instruction pool to return non-null non-empty list of instructions for a previously registered method " + methodName); return r; } /** * Determine how many bytes the current instruction occupies together with * its operands * * @return */ private int getBytecodeIncrement(AbstractInsnNode instructionNode) { int opcode = instructionNode.getOpcode(); switch (opcode) { case Opcodes.ALOAD: // index case Opcodes.ASTORE: // index case Opcodes.DLOAD: case Opcodes.DSTORE: case Opcodes.FLOAD: case Opcodes.FSTORE: case Opcodes.ILOAD: case Opcodes.ISTORE: case Opcodes.LLOAD: case Opcodes.LSTORE: VarInsnNode varNode = (VarInsnNode) instructionNode; if (varNode.var > 3) return 1; else return 0; case Opcodes.BIPUSH: // byte case Opcodes.NEWARRAY: case Opcodes.RET: return 1; case Opcodes.LDC: LdcInsnNode ldcNode = (LdcInsnNode)instructionNode; if(ldcNode.cst instanceof Double || ldcNode.cst instanceof Long) return 2; // LDC2_W else return 1; case 19: //LDC_W case 20: //LDC2_W return 2; case Opcodes.ANEWARRAY: // indexbyte1, indexbyte2 case Opcodes.CHECKCAST: // indexbyte1, indexbyte2 case Opcodes.GETFIELD: case Opcodes.GETSTATIC: case Opcodes.GOTO: case Opcodes.IF_ACMPEQ: case Opcodes.IF_ACMPNE: case Opcodes.IF_ICMPEQ: case Opcodes.IF_ICMPNE: case Opcodes.IF_ICMPGE: case Opcodes.IF_ICMPGT: case Opcodes.IF_ICMPLE: case Opcodes.IF_ICMPLT: case Opcodes.IFLE: case Opcodes.IFLT: case Opcodes.IFGE: case Opcodes.IFGT: case Opcodes.IFNE: case Opcodes.IFEQ: case Opcodes.IFNONNULL: case Opcodes.IFNULL: case Opcodes.IINC: case Opcodes.INSTANCEOF: case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESTATIC: case Opcodes.INVOKEVIRTUAL: case Opcodes.JSR: case Opcodes.NEW: case Opcodes.PUTFIELD: case Opcodes.PUTSTATIC: case Opcodes.SIPUSH: // case Opcodes.LDC_W // case Opcodes.LDC2_W return 2; case Opcodes.MULTIANEWARRAY: return 3; case Opcodes.INVOKEDYNAMIC: case Opcodes.INVOKEINTERFACE: return 4; case Opcodes.LOOKUPSWITCH: case Opcodes.TABLESWITCH: // TODO: Could be more return 4; // case Opcodes.GOTO_W // case Opcodes.JSR_W } return 0; } private void registerMethodNode(MethodNode node) { for (MethodNode mn : knownMethodNodes) if (mn == node) logger.debug("CFGGenerator.analyze() apparently got called for the same MethodNode twice"); knownMethodNodes.add(node); } /** *

* registerInstruction *

* * @param instruction * a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. */ public void registerInstruction(BytecodeInstruction instruction) { String className = instruction.getClassName(); String methodName = instruction.getMethodName(); if (!instructionMap.containsKey(className)) instructionMap.put(className, new LinkedHashMap<>()); if (!instructionMap.get(className).containsKey(methodName)) instructionMap.get(className).put(methodName, new ArrayList<>()); instructionMap.get(className).get(methodName).add(instruction); logger.debug("Registering instruction "+instruction); List instructions = instructionMap.get(className).get(methodName); if(instructions.size() > 1) { BytecodeInstruction previous = instructions.get(instructions.size() - 2); if(previous.isLabel()) { LabelNode ln = (LabelNode)previous.asmNode; if (ln.getLabel() instanceof AnnotatedLabel) { AnnotatedLabel aLabel = (AnnotatedLabel) ln.getLabel(); if(aLabel.isStartTag()) { if(aLabel.shouldIgnore()) { logger.debug("Ignoring artificial branch: "+instruction); return; } } } } } if (instruction.isActualBranch()) { BranchPool.getInstance(classLoader).registerAsBranch(instruction); } } // retrieve data from the pool /** *

* getInstruction *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @param instructionId * a int. * @param asmNode * a {@link org.objectweb.asm.tree.AbstractInsnNode} object. * @return a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. */ public BytecodeInstruction getInstruction(String className, String methodName, int instructionId, AbstractInsnNode asmNode) { BytecodeInstruction r = getInstruction(className, methodName, instructionId); if (r != null) assert (r.sanityCheckAbstractInsnNode(asmNode)); return r; } /** *

* getInstruction *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @param instructionId * a int. * @return a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. */ public BytecodeInstruction getInstruction(String className, String methodName, int instructionId) { if (instructionMap.get(className) == null) { logger.debug("unknown class: " + className); logger.debug(instructionMap.keySet().toString()); return null; } if (instructionMap.get(className).get(methodName) == null) { logger.debug("unknown method: " + methodName); logger.debug(instructionMap.get(className).keySet().toString()); return null; } for (BytecodeInstruction instruction : instructionMap.get(className).get(methodName)) { if (instruction.getInstructionId() == instructionId) return instruction; } logger.debug("unknown instruction " + instructionId + ", have " + instructionMap.get(className).get(methodName).size()); for (int i = 0; i < instructionMap.get(className).get(methodName).size(); i++) { logger.info(instructionMap.get(className).get(methodName).get(i).toString()); } return null; } /** *

* getInstruction *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @param node * a {@link org.objectweb.asm.tree.AbstractInsnNode} object. * @return a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. */ public BytecodeInstruction getInstruction(String className, String methodName, AbstractInsnNode node) { if (instructionMap.get(className) == null) { logger.debug("unknown class: " + className); logger.debug(instructionMap.keySet().toString()); return null; } if (instructionMap.get(className).get(methodName) == null) { logger.debug("unknown method: " + methodName); logger.debug(instructionMap.get(className).keySet().toString()); return null; } for (BytecodeInstruction instruction : instructionMap.get(className).get(methodName)) { if (instruction.asmNode == node) return instruction; } logger.debug("unknown instruction: " + node + ", have " + instructionMap.get(className).get(methodName).size() + " instructions for this method"); logger.debug(instructionMap.get(className).get(methodName).toString()); return null; } /** *

* knownClasses *

* * @return a {@link java.util.Set} object. */ public Set knownClasses() { return new LinkedHashSet<>(instructionMap.keySet()); } /** *

* knownMethods *

* * @param className * a {@link java.lang.String} object. * @return a {@link java.util.Set} object. */ public Set knownMethods(String className) { Set r = new LinkedHashSet<>(); if (instructionMap.get(className) != null) r.addAll(instructionMap.get(className).keySet()); return r; } public boolean hasMethod(String className, String methodName) { if (instructionMap.get(className) != null) return instructionMap.get(className).containsKey(methodName); return false; } /** *

* getInstructionsIn *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @return a {@link java.util.List} object. */ public List getInstructionsIn(String className, String methodName) { if (instructionMap.get(className) == null || instructionMap.get(className).get(methodName) == null) return null; List r = new ArrayList<>(); r.addAll(instructionMap.get(className).get(methodName)); return r; } public List getInstructionsIn(String className) { if (instructionMap.get(className) == null) return null; List r = new ArrayList<>(); Map> methodMap = instructionMap.get(className); for(List methodInstructions : methodMap.values()) { r.addAll(methodInstructions); } return r; } public List getAllInstructions() { List r = new ArrayList<>(); for(String className : instructionMap.keySet()) { Map> methodMap = instructionMap.get(className); for(List methodInstructions : methodMap.values()) { r.addAll(methodInstructions); } } return r; } /** *

* logInstructionsIn *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. */ public void logInstructionsIn(String className, String methodName) { logger.debug("Printing instructions in " + className + "." + methodName + ":"); List instructions = getInstructionsIn(className, methodName); if (instructions == null) { logger.debug("..unknown method"); } else { for (BytecodeInstruction instruction : instructions) { logger.debug("\t" + instruction); } } } /** *

* createFakeInstruction *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. * @return a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. */ public BytecodeInstruction createFakeInstruction(String className, String methodName) { AbstractInsnNode fakeNode = new InsnNode(Opcodes.NOP); int instructionId = getInstructionsIn(className, methodName).size(); BytecodeInstruction instruction = new BytecodeInstruction(classLoader, className, methodName, instructionId, -1, fakeNode); registerInstruction(instruction); return instruction; } /** *

* clear *

*/ public void clear() { instructionMap.clear(); knownMethodNodes.clear(); } public static void clearAll() { BytecodeInstructionPool.instanceMap.clear(); } /** *

* clear *

* * @param className * a {@link java.lang.String} object. */ public void clear(String className) { instructionMap.remove(className); } public static void clearAll(String className) { for (BytecodeInstructionPool pool : instanceMap.values()) { pool.clear(className); } } /** *

* clear *

* * @param className * a {@link java.lang.String} object. * @param methodName * a {@link java.lang.String} object. */ public void clear(String className, String methodName) { if (instructionMap.containsKey(className)) instructionMap.get(className).remove(methodName); } public static void clearAll(String className, String methodName) { for (BytecodeInstructionPool pool : instanceMap.values()) { pool.clear(className, methodName); } } /** *

* forgetInstruction *

* * @param ins * a {@link org.evosuite.graphs.cfg.BytecodeInstruction} object. * @return a boolean. */ public boolean forgetInstruction(BytecodeInstruction ins) { if (!instructionMap.containsKey(ins.getClassName())) return false; if (!instructionMap.get(ins.getClassName()).containsKey(ins.getMethodName())) return false; return instructionMap.get(ins.getClassName()).get(ins.getMethodName()).remove(ins); } public int getFirstLineNumberOfMethod(String className, String methodName) { if (instructionMap.get(className) == null) throw new IllegalArgumentException("unknown class " + className); if (instructionMap.get(className).get(methodName) == null) throw new IllegalArgumentException("unknown method " + methodName + " in class " + className); if (instructionMap.get(className).get(methodName).isEmpty()) throw new IllegalArgumentException("no instructions in method " + methodName + " in class " + className); int r = Integer.MAX_VALUE; for (BytecodeInstruction ins : instructionMap.get(className).get(methodName)) { if (ins.getLineNumber() < r) r = ins.getLineNumber(); } return r; } public BytecodeInstruction getFirstInstructionAtLineNumber(String className, String methodName, int lineNumber) { // TODO if (instructionMap.get(className) == null) return null; if (instructionMap.get(className).get(methodName) == null) return null; if (instructionMap.get(className).get(methodName).isEmpty()) return null; for (BytecodeInstruction ins : instructionMap.get(className).get(methodName)) { if (ins.getLineNumber() == lineNumber) return ins; } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy