org.evosuite.testcase.execution.ExecutionTracer.java Source code

Java tutorial

Introduction

Here is the source code for org.evosuite.testcase.execution.ExecutionTracer.java

Source

/**
 * Copyright (C) 2010-2016 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 <http://www.gnu.org/licenses/>.
 */
package org.evosuite.testcase.execution;

import java.util.Map;

import org.evosuite.coverage.dataflow.DefUsePool;
import org.evosuite.coverage.dataflow.Definition;
import org.evosuite.coverage.dataflow.Use;
import org.evosuite.instrumentation.testability.BooleanHelper;
import org.evosuite.seeding.ConstantPoolManager;
import org.objectweb.asm.Opcodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class collects information about chosen branches/paths at runtime
 * 
 * @author Gordon Fraser
 */
public class ExecutionTracer {

    private static final Logger logger = LoggerFactory.getLogger(ExecutionTracer.class);

    private static ExecutionTracer instance = null;

    /**
     * We need to disable the execution tracer sometimes, e.g. when calling
     * equals in the branch distance function
     */
    private boolean disabled = true;

    /** Flag that is used to kill threads that are stuck in endless loops */
    private boolean killSwitch = false;

    private int num_statements = 0;

    private ExecutionTrace trace;

    private static boolean checkCallerThread = true;

    /**
     * If a thread of a test case survives for some reason (e.g. long call to
     * external library), then we don't want its data in the current trace
     */
    private static volatile Thread currentThread = null;

    /**
     * <p>
     * setThread
     * </p>
     * 
     * @param thread
     *            a {@link java.lang.Thread} object.
     */
    public static void setThread(Thread thread) {
        currentThread = thread;
    }

    /**
     * <p>
     * disable
     * </p>
     */
    public static void disable() {
        ExecutionTracer tracer = ExecutionTracer.getExecutionTracer();
        tracer.disabled = true;
    }

    /**
     * <p>
     * enable
     * </p>
     */
    public static void enable() {
        ExecutionTracer tracer = ExecutionTracer.getExecutionTracer();
        tracer.disabled = false;
    }

    /**
     * <p>
     * isEnabled
     * </p>
     * 
     * @return a boolean.
     */
    public static boolean isEnabled() {
        ExecutionTracer tracer = ExecutionTracer.getExecutionTracer();
        return !tracer.disabled;
    }

    /**
     * <p>
     * Setter for the field <code>killSwitch</code>.
     * </p>
     * 
     * @param value
     *            a boolean.
     */
    public static void setKillSwitch(boolean value) {
        ExecutionTracer tracer = ExecutionTracer.getExecutionTracer();
        tracer.killSwitch = value;
    }

    /**
     * <p>
     * Setter for the field <code>checkCallerThread</code>.
     * </p>
     * 
     * @param checkCallerThread
     *            a boolean.
     */
    public static void setCheckCallerThread(boolean checkCallerThread) {
        ExecutionTracer.checkCallerThread = checkCallerThread;
    }

    /**
     * <p>
     * enable context instrumentation
     * </p>
     */
    public static void enableContext() {
        logger.info("enable context and trace instrumentation");
        ExecutionTraceImpl.enableContext();
    }

    /**
     * <p>
     * disable context instrumentation
     * </p>
     */
    public static void disableContext() {
        logger.info("disable context and trace instrumentation");
        ExecutionTraceImpl.disableContext();
    }

    /**
     * <p>
     * disableTraceCalls
     * </p>
     */
    public static void disableTraceCalls() {
        ExecutionTraceImpl.disableTraceCalls();
    }

    /**
     * <p>
     * enableTraceCalls
     * </p>
     */
    public static void enableTraceCalls() {
        ExecutionTraceImpl.enableTraceCalls();
    }

    public static boolean isTraceCallsEnabled() {
        return ExecutionTraceImpl.isTraceCallsEnabled();
    }

    /**
     * <p>
     * getExecutionTracer
     * </p>
     * 
     * @return a {@link org.evosuite.testcase.execution.ExecutionTracer} object.
     */
    public static ExecutionTracer getExecutionTracer() {
        if (instance == null) {
            instance = new ExecutionTracer();
        }
        return instance;
    }

    /**
     * Reset for new execution
     */
    public void clear() {
        trace = new ExecutionTraceProxy();
        BooleanHelper.clearStack();
        num_statements = 0;
    }

    /**
     * Obviously more than one thread is executing during the creation of
     * concurrent TestCases. #TODO steenbuck we should test if
     * Thread.currentThread() is in the set of currently executing threads
     * 
     * @return
     */
    public static boolean isThreadNeqCurrentThread() {
        if (!checkCallerThread) {
            return false;
        }
        if (currentThread == null) {
            logger.error("CurrentThread has not been set!");
            Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
            for (Thread t : map.keySet()) {
                String msg = "Thread: " + t + "\n";
                for (StackTraceElement e : map.get(t)) {
                    msg += " -> " + e + "\n";
                }
                logger.error(msg);
            }
            currentThread = Thread.currentThread();
        }
        return Thread.currentThread() != currentThread;
    }

    /**
     * Return trace of current execution
     * 
     * @return a {@link org.evosuite.testcase.execution.ExecutionTrace} object.
     */
    public ExecutionTrace getTrace() {
        trace.finishCalls();
        return trace;

        // ExecutionTrace copy = trace.clone();
        // // copy.finishCalls();
        // return copy;
    }

    /**
     * Return the last explicitly thrown exception
     * 
     * @return a {@link java.lang.Throwable} object.
     */
    public Throwable getLastException() {
        return trace.getExplicitException();
    }

    /**
     * Called by instrumented code whenever a new method is called
     * 
     * @param classname
     *            a {@link java.lang.String} object.
     * @param methodname
     *            a {@link java.lang.String} object.
     * @param caller
     *            a {@link java.lang.Object} object.
     * @throws org.evosuite.testcase.TestCaseExecutor$TimeoutExceeded
     *             if any.
     */
    public static void enteredMethod(String classname, String methodname, Object caller)
            throws TestCaseExecutor.TimeoutExceeded {
        ExecutionTracer tracer = getExecutionTracer();

        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        //logger.trace("Entering method " + classname + "." + methodname);
        tracer.trace.enteredMethod(classname, methodname, caller);
    }

    /**
     * Called by instrumented code whenever a return values is produced
     * 
     * @param value
     *            a int.
     * @param className
     *            a {@link java.lang.String} object.
     * @param methodName
     *            a {@link java.lang.String} object.
     */
    public static void returnValue(int value, String className, String methodName) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        //logger.trace("Return value: " + value);
        tracer.trace.returnValue(className, methodName, value);
    }

    /**
     * Called by instrumented code whenever a return values is produced
     * 
     * @param value
     *            a {@link java.lang.Object} object.
     * @param className
     *            a {@link java.lang.String} object.
     * @param methodName
     *            a {@link java.lang.String} object.
     */
    public static void returnValue(Object value, String className, String methodName) {
        if (isThreadNeqCurrentThread())
            return;

        if (!ExecutionTracer.isEnabled())
            return;

        if (value == null) {
            returnValue(0, className, methodName);
            return;
        }
        StringBuilder tmp = null;
        try {
            // setLineCoverageDeactivated(true);
            // logger.warn("Disabling tracer: returnValue");
            ExecutionTracer.disable();
            tmp = new StringBuilder(value.toString());
        } catch (Throwable t) {
            return;
        } finally {
            ExecutionTracer.enable();
        }
        int index = 0;
        int position = 0;
        boolean found = false;
        boolean deleteAddresses = true;
        char c = ' ';
        // quite fast method to detect memory addresses in Strings.
        while ((position = tmp.indexOf("@", index)) > 0) {
            for (index = position + 1; index < position + 17 && index < tmp.length(); index++) {
                c = tmp.charAt(index);
                if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                    found = true;
                } else {
                    break;
                }
            }
            if (deleteAddresses && found) {
                tmp.delete(position + 1, index);
            }
        }

        returnValue(tmp.toString().hashCode(), className, methodName);
    }

    /**
     * Called by instrumented code whenever a method is left
     * 
     * @param classname
     *            a {@link java.lang.String} object.
     * @param methodname
     *            a {@link java.lang.String} object.
     */
    public static void leftMethod(String classname, String methodname) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        tracer.trace.exitMethod(classname, methodname);
        // logger.trace("Left method " + classname + "." + methodname);
    }

    /**
     * Called by the instrumented code each time a new source line is executed
     */
    public static void checkTimeout() {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (tracer.killSwitch) {
            // logger.info("Raising TimeoutException as kill switch is active - passedLine");
            if (!isInStaticInit())
                throw new TestCaseExecutor.TimeoutExceeded();
        }
    }

    private static boolean isInStaticInit() {
        for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
            if (elem.getMethodName().equals("<clinit>"))
                return true;
        }
        return false;
    }

    /**
     * Called by the instrumented code each time a new source line is executed
     * 
     * @param line
     *            a int.
     * @param className
     *            a {@link java.lang.String} object.
     * @param methodName
     *            a {@link java.lang.String} object.
     */
    public static void passedLine(String className, String methodName, int line) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.trace.linePassed(className, methodName, line);
    }

    /**
     * Called by the instrumented code each time an unconditional branch is
     * taken. This is not enabled by default, only some coverage criteria (e.g.,
     * LCSAJ) use it.
     * 
     * @param opcode
     *            a int.
     * @param branch
     *            a int.
     * @param bytecode_id
     *            a int.
     */
    public static void passedUnconditionalBranch(int opcode, int branch, int bytecode_id) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        // Add current branch to control trace
        tracer.trace.branchPassed(branch, bytecode_id, 0.0, 0.0);
    }

    /**
     * Called by the instrumented code each time a new branch is taken
     * 
     * @param val
     *            a int.
     * @param opcode
     *            a int.
     * @param branch
     *            a int.
     * @param bytecode_id
     *            a int.
     */
    public static void passedBranch(int val, int opcode, int branch, int bytecode_id) {

        ExecutionTracer tracer = getExecutionTracer();
        // logger.info("passedBranch val="+val+", opcode="+opcode+", branch="+branch+", bytecode_id="+bytecode_id);
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        ConstantPoolManager.getInstance().addDynamicConstant(val);

        // logger.trace("Called passedBranch1 with opcode "+AbstractVisitor.OPCODES[opcode]+" and val "+val+" in branch "+branch);
        double distance_true = 0.0;
        double distance_false = 0.0;
        switch (opcode) {
        case Opcodes.IFEQ:
            distance_true = Math.abs((double) val); // The greater abs is, the
            // further away from 0
            distance_false = distance_true == 0 ? 1.0 : 0.0; // Anything but 0
            // is good
            break;
        case Opcodes.IFNE:
            distance_false = Math.abs((double) val); // The greater abs is, the
            // further away from 0
            distance_true = distance_false == 0 ? 1.0 : 0.0; // Anything but 0
            // leads to NE
            break;
        case Opcodes.IFLT:
            distance_true = val >= 0 ? val + 1.0 : 0.0; // The greater, the
            // further away from < 0
            distance_false = val < 0 ? 0.0 - val + 1.0 : 0.0; // The smaller,
            // the further
            // away from < 0
            break;
        case Opcodes.IFGT:
            distance_true = val <= 0 ? 0.0 - val + 1.0 : 0.0;
            distance_false = val > 0 ? val + 1.0 : 0.0;
            break;
        case Opcodes.IFGE:
            distance_true = val < 0 ? 0.0 - val + 1.0 : 0.0;
            distance_false = val >= 0 ? val + 1.0 : 0.0;
            break;
        case Opcodes.IFLE:
            distance_true = val > 0 ? val + 1.0 : 0.0; // The greater, the
            // further away from < 0
            distance_false = val <= 0 ? 0.0 - val + 1.0 : 0.0; // The smaller,
            // the further
            // away from < 0
            break;
        default:
            logger.error("Unknown opcode: " + opcode);

        }
        // logger.trace("1 Branch distance true : " + distance_true);
        // logger.trace("1 Branch distance false: " + distance_false);

        // Add current branch to control trace
        tracer.trace.branchPassed(branch, bytecode_id, distance_true, distance_false);
    }

    public static void passedPutStatic(String classNameWithDots, String fieldName) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.trace.putStaticPassed(classNameWithDots, fieldName);
    }

    /**
     * This method is added in the transformed bytecode
     *
     * @param className
     */
    public static void exitClassInit(String className) {

        final String classNameWithDots = className.replace('/', '.');

        ExecutionTracer tracer = getExecutionTracer();
        //      if (tracer.disabled)
        //         return;
        //
        //      if (isThreadNeqCurrentThread())
        //         return;
        //
        //      checkTimeout();

        tracer.trace.classInitialized(classNameWithDots);

    }

    /**
     * 
     * @param classNameWithDots
     * @param fieldName
     */
    public static void passedGetStatic(String classNameWithDots, String fieldName) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.trace.getStaticPassed(classNameWithDots, fieldName);
    }

    /**
     * Called by the instrumented code each time a new branch is taken
     * 
     * @param val1
     *            a int.
     * @param val2
     *            a int.
     * @param opcode
     *            a int.
     * @param branch
     *            a int.
     * @param bytecode_id
     *            a int.
     */
    public static void passedBranch(int val1, int val2, int opcode, int branch, int bytecode_id) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        ConstantPoolManager.getInstance().addDynamicConstant(val1);
        ConstantPoolManager.getInstance().addDynamicConstant(val2);

        /* logger.trace("Called passedBranch2 with opcode "
          + AbstractVisitor.OPCODES[opcode] + ", val1=" + val1 + ", val2=" + val2
          + " in branch " + branch); */
        double distance_true = 0;
        double distance_false = 0;
        switch (opcode) {
        // Problem is that the JVM is a stack machine
        // x < 5 gets compiled to a val2 > val1,
        // because operators are on the stack in reverse order
        case Opcodes.IF_ICMPEQ:
            // The greater the difference, the further away
            distance_true = Math.abs((double) val1 - (double) val2);
            // Anything but 0 is good
            distance_false = distance_true == 0 ? 1.0 : 0.0;
            break;
        case Opcodes.IF_ICMPNE:
            // The greater abs is, the further away from 0
            distance_false = Math.abs((double) val1 - (double) val2);
            // Anything but 0 leads to NE
            distance_true = distance_false == 0 ? 1.0 : 0.0;
            break;
        case Opcodes.IF_ICMPLT:
            // val1 >= val2?
            distance_true = val1 >= val2 ? (double) val1 - (double) val2 + 1.0 : 0.0;
            distance_false = val1 < val2 ? (double) val2 - (double) val1 + 1.0 : 0.0;
            break;
        case Opcodes.IF_ICMPGE:
            // val1 < val2?
            distance_true = val1 < val2 ? (double) val2 - (double) val1 + 1.0 : 0.0;
            distance_false = val1 >= val2 ? (double) val1 - (double) val2 + 1.0 : 0.0;
            break;
        case Opcodes.IF_ICMPGT:
            // val1 <= val2?
            distance_true = val1 <= val2 ? (double) val2 - (double) val1 + 1.0 : 0.0;
            distance_false = val1 > val2 ? (double) val1 - (double) val2 + 1.0 : 0.0;
            break;
        case Opcodes.IF_ICMPLE:
            // val1 > val2?
            distance_true = val1 > val2 ? (double) val1 - (double) val2 + 1.0 : 0.0;
            distance_false = val1 <= val2 ? (double) val2 - (double) val1 + 1.0 : 0.0;
            break;
        default:
            logger.error("Unknown opcode: " + opcode);
        }
        // logger.trace("2 Branch distance true: " + distance_true);
        // logger.trace("2 Branch distance false: " + distance_false);

        // Add current branch to control trace
        tracer.trace.branchPassed(branch, bytecode_id, distance_true, distance_false);
        // tracer.trace.branchPassed(branch, distance_true, distance_false);

    }

    /**
     * Called by the instrumented code each time a new branch is taken
     * 
     * @param val1
     *            a {@link java.lang.Object} object.
     * @param val2
     *            a {@link java.lang.Object} object.
     * @param opcode
     *            a int.
     * @param branch
     *            a int.
     * @param bytecode_id
     *            a int.
     */
    public static void passedBranch(Object val1, Object val2, int opcode, int branch, int bytecode_id) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        // logger.trace("Called passedBranch3 with opcode "
        //        + AbstractVisitor.OPCODES[opcode]); // +", val1="+val1+", val2="+val2+" in branch "+branch);
        double distance_true = 0;
        double distance_false = 0;
        // logger.warn("Disabling tracer: passedBranch with 2 Objects");

        switch (opcode) {
        case Opcodes.IF_ACMPEQ:
            if (val1 == null) {
                distance_true = val2 == null ? 0.0 : 1.0;
            } else {
                disable();
                try {
                    distance_true = val1.equals(val2) ? 0.0 : 1.0;
                } catch (Throwable t) {
                    logger.debug("Equality raised exception: " + t);
                    distance_true = 1.0;
                } finally {
                    enable();
                }
            }
            break;
        case Opcodes.IF_ACMPNE:
            if (val1 == null) {
                distance_true = val2 == null ? 1.0 : 0.0;
            } else {
                disable();
                try {
                    distance_true = val1.equals(val2) ? 1.0 : 0.0;
                } catch (Exception e) {
                    logger.debug("Caught exception during comparison: " + e);
                    distance_true = 1.0;
                } finally {
                    enable();
                }
            }
            break;
        }

        distance_false = distance_true == 0 ? 1.0 : 0.0;

        // Add current branch to control trace
        tracer.trace.branchPassed(branch, bytecode_id, distance_true, distance_false);
    }

    /**
     * Called by the instrumented code each time a new branch is taken
     * 
     * @param val
     *            a {@link java.lang.Object} object.
     * @param opcode
     *            a int.
     * @param branch
     *            a int.
     * @param bytecode_id
     *            a int.
     */
    public static void passedBranch(Object val, int opcode, int branch, int bytecode_id) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        double distance_true = 0;
        double distance_false = 0;
        switch (opcode) {
        case Opcodes.IFNULL:
            distance_true = val == null ? 0.0 : 1.0;
            break;
        case Opcodes.IFNONNULL:
            distance_true = val == null ? 1.0 : 0.0;
            break;
        default:
            logger.error("Warning: encountered opcode " + opcode);
        }
        distance_false = distance_true == 0 ? 1.0 : 0.0;
        // enable();

        // logger.trace("Branch distance true: " + distance_true);
        // logger.trace("Branch distance false: " + distance_false);

        // Add current branch to control trace
        tracer.trace.branchPassed(branch, bytecode_id, distance_true, distance_false);
    }

    /**
     * Called by instrumented code each time a variable gets written to (a
     * Definition)
     * 
     * @param caller
     *            a {@link java.lang.Object} object.
     * @param defID
     *            a int.
     */
    public static void passedDefinition(Object object, Object caller, int defID) {
        if (isThreadNeqCurrentThread())
            return;

        ExecutionTracer tracer = getExecutionTracer();
        if (!tracer.disabled)
            tracer.trace.definitionPassed(object, caller, defID);
    }

    /**
     * Called by instrumented code each time a variable is read from (a Use)
     * 
     * @param caller
     *            a {@link java.lang.Object} object.
     * @param useID
     *            a int.
     */
    public static void passedUse(Object object, Object caller, int useID) {

        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        tracer.trace.usePassed(object, caller, useID);
    }

    /**
     * Called by instrumented code each time a field method call is passed
     * 
     * Since it was not clear whether the field method call constitutes a
     * definition or a use when the instrumentation was initially added this
     * method will redirect the call accordingly
     * 
     * @param caller
     * @param defuseId
     */
    public static void passedFieldMethodCall(Object callee, Object caller, int defuseId) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        if (DefUsePool.isKnownAsDefinition(defuseId)) {
            Definition passedDef = DefUsePool.getDefinitionByDefUseId(defuseId);
            passedDefinition(callee, caller, passedDef.getDefId());
        } else if (DefUsePool.isKnownAsUse(defuseId)) {
            Use passedUse = DefUsePool.getUseByDefUseId(defuseId);
            passedUse(callee, caller, passedUse.getUseId());
        } else
            throw new EvosuiteError("instrumentation called passedFieldMethodCall with invalid defuseId: "
                    + defuseId + ", known IDs: " + DefUsePool.getDefUseCounter());
    }

    /**
     * <p>
     * passedMutation
     * </p>
     * 
     * @param distance
     *            a double.
     * @param mutationId
     *            a int.
     */
    public static void passedMutation(double distance, int mutationId) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.trace.mutationPassed(mutationId, distance);
    }

    /**
     * <p>
     * exceptionThrown
     * </p>
     * 
     * @param exception
     *            a {@link java.lang.Object} object.
     * @param className
     *            a {@link java.lang.String} object.
     * @param methodName
     *            a {@link java.lang.String} object.
     */
    public static void exceptionThrown(Object exception, String className, String methodName) {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.trace.setExplicitException((Throwable) exception);

    }

    /**
     * <p>
     * statementExecuted
     * </p>
     */
    public static void statementExecuted() {
        ExecutionTracer tracer = getExecutionTracer();
        if (tracer.disabled)
            return;

        if (isThreadNeqCurrentThread())
            return;

        checkTimeout();

        tracer.num_statements++;
    }

    /**
     * <p>
     * getNumStatementsExecuted
     * </p>
     * 
     * @return a int.
     */
    public int getNumStatementsExecuted() {
        return num_statements;
    }

    private ExecutionTracer() {
        trace = new ExecutionTraceProxy();
    }

}