diff --git a/microbat/lib/instrumentator.jar b/microbat/lib/instrumentator.jar index 3ac7f73e2..0bb2ce739 100644 Binary files a/microbat/lib/instrumentator.jar and b/microbat/lib/instrumentator.jar differ diff --git a/microbat_instrumentator/.classpath b/microbat_instrumentator/.classpath index 75ac85ffd..8f8c6a924 100644 --- a/microbat_instrumentator/.classpath +++ b/microbat_instrumentator/.classpath @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/microbat_instrumentator/.settings/org.eclipse.jdt.core.prefs b/microbat_instrumentator/.settings/org.eclipse.jdt.core.prefs index 980b98c1d..ace45ceef 100644 --- a/microbat_instrumentator/.settings/org.eclipse.jdt.core.prefs +++ b/microbat_instrumentator/.settings/org.eclipse.jdt.core.prefs @@ -1,12 +1,12 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/microbat_instrumentator/lib/instrumentator_agent_v02.jar b/microbat_instrumentator/lib/instrumentator_agent_v02.jar index b56267093..18e8694fd 100644 Binary files a/microbat_instrumentator/lib/instrumentator_agent_v02.jar and b/microbat_instrumentator/lib/instrumentator_agent_v02.jar differ diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/Agent.java b/microbat_instrumentator/src/main/microbat/instrumentation/Agent.java index cdfab4f53..942c73d65 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/Agent.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/Agent.java @@ -10,6 +10,7 @@ import microbat.instrumentation.cfgcoverage.CoverageAgentParams; import microbat.instrumentation.filter.GlobalFilterChecker; import microbat.instrumentation.runtime.ExecutionTracer; +import microbat.instrumentation.runtime.ExecutionTrace; import microbat.instrumentation.runtime.IExecutionTracer; /** @@ -59,7 +60,7 @@ public void run() { */ public static void _exitProgram(String programMsg) { if(Thread.currentThread().getName().equals("main")) { - ExecutionTracer.getMainThreadStore().lock(); + ExecutionTrace.getMainThreadStore().lock(); Agent.programMsg = programMsg; boolean allInterestedThreadsStop = false; @@ -72,7 +73,7 @@ public static void _exitProgram(String programMsg) { boolean needToConitnue = false; - for(IExecutionTracer tracer: ExecutionTracer.getAllThreadStore()) { + for(IExecutionTracer tracer: ExecutionTrace.getAllThreadStore()) { if(tracer instanceof ExecutionTracer) { ExecutionTracer eTracer = (ExecutionTracer)tracer; @@ -80,7 +81,7 @@ public static void _exitProgram(String programMsg) { continue; } - if(!ExecutionTracer.stoppedThreads.contains(eTracer.getThreadId())) { + if(!ExecutionTrace.stoppedThreads.contains(eTracer.getThreadId())) { needToConitnue = true; break; @@ -92,7 +93,7 @@ public static void _exitProgram(String programMsg) { } stop(); - ExecutionTracer.getMainThreadStore().unLock(); + ExecutionTrace.getMainThreadStore().unLock(); Runtime.getRuntime().exit(1); // force program to exit to avoid getting stuck by background running threads. } else { @@ -100,7 +101,7 @@ public static void _exitProgram(String programMsg) { * we do not record the thread any more */ // long threadId = Thread.currentThread().getId(); - ExecutionTracer.stopRecordingCurrendThread(); + ExecutionTrace.stopRecordingCurrendThread(); } } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/AgentLogger.java b/microbat_instrumentator/src/main/microbat/instrumentation/AgentLogger.java index ae249a217..c41e6b24f 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/AgentLogger.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/AgentLogger.java @@ -3,7 +3,7 @@ import java.util.List; import microbat.instrumentation.AgentParams.LogType; -import microbat.instrumentation.runtime.ExecutionTracer; +import microbat.instrumentation.runtime.ExecutionTrace; public class AgentLogger { private static boolean enableDebug; @@ -50,7 +50,7 @@ public static void info(String msg) { public static void printProgress(int curStep) { if (printProgress) { - int totalSteps = ExecutionTracer.expectedSteps == Integer.MAX_VALUE? ExecutionTracer.stepLimit : ExecutionTracer.expectedSteps; + int totalSteps = ExecutionTrace.getExpectedSteps() == Integer.MAX_VALUE? ExecutionTrace.getStepLimit() : ExecutionTrace.getExpectedSteps(); System.out.println(new StringBuffer().append(AgentConstants.PROGRESS_HEADER) .append(curStep).append(" ").append(totalSteps).append(" ").toString()); } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/TraceAgent.java b/microbat_instrumentator/src/main/microbat/instrumentation/TraceAgent.java index d23bcfccc..af86833cf 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/TraceAgent.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/TraceAgent.java @@ -8,7 +8,7 @@ import microbat.instrumentation.filter.GlobalFilterChecker; import microbat.instrumentation.filter.OverLongMethodFilter; import microbat.instrumentation.instr.TraceTransformer; -import microbat.instrumentation.runtime.ExecutionTracer; +import microbat.instrumentation.runtime.ExecutionTrace; import microbat.instrumentation.runtime.IExecutionTracer; import microbat.model.trace.Trace; import microbat.model.trace.TraceNode; @@ -31,9 +31,9 @@ public void startup(long vmStartupTime, long agentPreStartup) { /* init filter */ AppJavaClassPath appPath = agentParams.initAppClassPath(); GlobalFilterChecker.setup(appPath, agentParams.getIncludesExpression(), agentParams.getExcludesExpression()); - ExecutionTracer.appJavaClassPath = appPath; - ExecutionTracer.variableLayer = agentParams.getVariableLayer(); - ExecutionTracer.setStepLimit(agentParams.getStepLimit()); + ExecutionTrace.setAppJavaClassPath(appPath); + ExecutionTrace.setVariableLayer(agentParams.getVariableLayer()); + ExecutionTrace.setStepLimit(agentParams.getStepLimit()); if (!agentParams.isRequireMethodSplit()) { agentParams.getUserFilters().register(new OverLongMethodFilter(agentParams.getOverlongMethods())); } @@ -42,32 +42,26 @@ public void startup(long vmStartupTime, long agentPreStartup) { agentParams.getUserFilters().register(new CodeRangeUserFilter(agentParams.getCodeRanges())); } - ExecutionTracer.setExpectedSteps(agentParams.getExpectedSteps()); - ExecutionTracer.avoidProxyToString = agentParams.isAvoidProxyToString(); + ExecutionTrace.setExpectedSteps(agentParams.getExpectedSteps()); + ExecutionTrace.setAvoidProxyToString(agentParams.isAvoidProxyToString()); } public void shutdown() throws Exception { - ExecutionTracer.shutdown(); + ExecutionTrace.shutdown(); /* collect trace & store */ AgentLogger.debug("Building trace dependencies ..."); timer.newPoint("Building trace dependencies"); // FIXME -mutithread LINYUN [3] // LLT: only trace of main thread is recorded. - List tracers = ExecutionTracer.getAllThreadStore(); - - int size = tracers.size(); - List traceList = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - - ExecutionTracer tracer = (ExecutionTracer) tracers.get(i); - - Trace trace = tracer.getTrace(); - trace.setThreadId(tracer.getThreadId()); - trace.setThreadName(tracer.getThreadName()); - trace.setMain(ExecutionTracer.getMainThreadStore().equals(tracer)); - + List tracers = ExecutionTrace.getAllThreadStore(); + + List traceList = ExecutionTrace.getTraceList(); + for (Trace trace : traceList) { + // TODO: check for name and Id and main to be initialized in tracer +// trace.setThreadId(tracer.getThreadId()); +// trace.setThreadName(tracer.getThreadName()); +// trace.setMain(ExecutionTrace.getMainThreadStore().equals(tracer)); constructTrace(trace); - traceList.add(trace); } timer.newPoint("Saving trace"); @@ -80,7 +74,7 @@ public void constructTrace(Trace trace) { GlobalFilterChecker.addFilterInfo(trace); StepMismatchChecker.logNormalSteps(trace); - ExecutionTracer.dispose(); // clear cache + ExecutionTrace.dispose(); // clear cache long t1 = System.currentTimeMillis(); AgentLogger.debug("create VirtualDataRelation...."); createVirtualDataRelation(trace); @@ -182,14 +176,14 @@ public AgentParams getAgentParams() { @Override public void startTest(String junitClass, String junitMethod) { - ExecutionTracer._start(); - ExecutionTracer.appJavaClassPath.setOptionalTestClass(junitClass); - ExecutionTracer.appJavaClassPath.setOptionalTestMethod(junitMethod); + ExecutionTrace._start(); + ExecutionTrace.setAppJavaClassPathOptionalTestClass(junitClass); + ExecutionTrace.setAppJavaClassPathOptionalTestMethod(junitMethod); } @Override public void finishTest(String junitClass, String junitMethod) { - ExecutionTracer.shutdown(); + ExecutionTrace.shutdown(); } @Override @@ -210,6 +204,6 @@ public void exitTest(String testResultMsg, String junitClass, String junitMethod @Override public boolean isInstrumentationActive() { - return !ExecutionTracer.isShutdown(); + return !ExecutionTrace.isShutdown(); } } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/filter/GlobalFilterChecker.java b/microbat_instrumentator/src/main/microbat/instrumentation/filter/GlobalFilterChecker.java index 6c265a8ba..0e76d6367 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/filter/GlobalFilterChecker.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/filter/GlobalFilterChecker.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; +import microbat.instrumentation.runtime.ExecutionTrace; import microbat.instrumentation.runtime.ExecutionTracer; import microbat.model.trace.Trace; import sav.common.core.utils.StringUtils; @@ -31,7 +32,7 @@ public static GlobalFilterChecker getInstance() { public void startup(AppJavaClassPath appClasspath, String includeExpression, String excludeExpression) { extLibs = new ArrayList<>(); appBinFolders = new ArrayList<>(); - ExecutionTracer.appJavaClassPath = appClasspath; + ExecutionTrace.setAppJavaClassPath(appClasspath); String workingDir = getPath(appClasspath.getWorkingDirectory()); for (String cp : appClasspath.getClasspaths()) { String path = getPath(cp); diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/instr/AbstractTransformer.java b/microbat_instrumentator/src/main/microbat/instrumentation/instr/AbstractTransformer.java index 8df949617..42e5e8bd3 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/instr/AbstractTransformer.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/instr/AbstractTransformer.java @@ -7,7 +7,7 @@ import java.security.ProtectionDomain; import microbat.instrumentation.AgentLogger; -import microbat.instrumentation.runtime.ExecutionTracer; +import microbat.instrumentation.runtime.ExecutionTrace; import microbat.instrumentation.runtime.IExecutionTracer; import sav.common.core.utils.FileUtils; @@ -16,10 +16,10 @@ public abstract class AbstractTransformer implements ClassFileTransformer { @Override public final byte[] transform(ClassLoader loader, String classFName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - if (ExecutionTracer.isShutdown()) { + if (ExecutionTrace.isShutdown()) { return null; } - IExecutionTracer tracer = ExecutionTracer.getCurrentThreadStore(); + IExecutionTracer tracer = ExecutionTrace.getCurrentThreadStore(); /* * The reason we need to lock and unlock the tracer: * when a method which is being traced invoke a another method which class is required to be loaded, diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/EmptyExecutionTracer.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/EmptyExecutionTracer.java index e6d7a45ad..f1fe68020 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/EmptyExecutionTracer.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/EmptyExecutionTracer.java @@ -1,5 +1,7 @@ package microbat.instrumentation.runtime; +import microbat.model.trace.Trace; + public class EmptyExecutionTracer implements IExecutionTracer { private static final IExecutionTracer instance = new EmptyExecutionTracer(); @@ -119,4 +121,9 @@ public void setThreadName(String threadName) { } + @Override + public Trace getTrace() { + return null; + } + } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTrace.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTrace.java new file mode 100644 index 000000000..9b160313a --- /dev/null +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTrace.java @@ -0,0 +1,158 @@ +package microbat.instrumentation.runtime; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import microbat.instrumentation.AgentConstants; +import microbat.model.trace.Trace; +import sav.strategies.dto.AppJavaClassPath; + +public class ExecutionTrace { + public static List stoppedThreads = new ArrayList(); + private static TracingContext ctx = new TracingContext(); + private static ExecutionTracerStore rtStore = new ExecutionTracerStore(ctx); + + public static void setExpectedSteps(int expectedSteps) { + if (expectedSteps != AgentConstants.UNSPECIFIED_INT_VALUE) { + ctx.expectedSteps = expectedSteps; +// tolerantExpectedSteps = expectedSteps * 2; + } + } + + public static void setStepLimit(int stepLimit) { + if (stepLimit != AgentConstants.UNSPECIFIED_INT_VALUE) { + ctx.stepLimit = stepLimit; + } + } + + /** + * BE VERY CAREFUL WHEN MODIFYING THIS FUNCTION! TO AVOID CREATING A LOOP, DO + * KEEP THIS ATMOST SIMPLE, AVOID INVOKE ANY EXTERNAL LIBRARY FUNCTION, EVEN JDK + * INSIDE THIS BLOCK OF CODE AND ITS INVOKED METHODS.! (ONLY + * Thread.currentThread().getId() is exceptional used) IF NEED TO USE A LIST,MAP + * -> USE AN ARRAY INSTEAD! + */ + public synchronized static IExecutionTracer _getTracer(boolean isAppClass, String className, String methodSig, + int methodStartLine, int methodEndLine, String paramNamesCode, String paramTypeSignsCode, Object[] params) { + try { + if (ctx.stateEquals(TracingState.TEST_STARTED) && isAppClass) { + ctx.recording(); + rtStore.setMainThreadId(Thread.currentThread().getId()); + } + if (!ctx.stateEquals(TracingState.RECORDING)) { + return EmptyExecutionTracer.getInstance(); + } + long threadId = Thread.currentThread().getId(); + if (ctx.lockedThreads.isUntracking(threadId)) { + return EmptyExecutionTracer.getInstance(); + } + ctx.lockedThreads.untrack(threadId); + // FIXME -mutithread LINYUN [1] + /* + * LLT: the corresponding tracer for a thread will be load by threadId, + * currently we always return null if not main thread. + */ + ExecutionTracer tracer = rtStore.get(threadId); + if (tracer == null) { + tracer = rtStore.get(threadId); + // lockedThreads.remove(threadId); + // return EmptyExecutionTracer.getInstance(); + } + tracer.enterMethod(className, methodSig, methodStartLine, methodEndLine, paramTypeSignsCode, paramNamesCode, + params); + ctx.lockedThreads.track(threadId); + return tracer; + } catch (Throwable t) { + t.printStackTrace(); + throw t; + } + } + + public static IExecutionTracer getMainThreadStore() { + return rtStore.getMainThreadTracer(); + } + + public static List getAllThreadStore() { + return rtStore.getAllThreadTracer(); + } + + public static synchronized IExecutionTracer getCurrentThreadStore() { + synchronized (rtStore) { + long threadId = Thread.currentThread().getId(); + // String threadName = Thread.currentThread().getName(); + if (ctx.lockedThreads.isUntracking(threadId)) { + return EmptyExecutionTracer.getInstance(); + } + IExecutionTracer tracer = rtStore.get(threadId); + // store.setThreadName(threadName); + + if (tracer == null) { + tracer = EmptyExecutionTracer.getInstance(); + } + return tracer; + } + } + + public static synchronized void stopRecordingCurrendThread() { + synchronized (rtStore) { + long threadId = Thread.currentThread().getId(); + ctx.lockedThreads.untrack(threadId); + stoppedThreads.add(threadId); + } + } + + public static void dispose() { + ctx = new TracingContext(); + rtStore = new ExecutionTracerStore(ctx); + // FIXME: move adjustVarMap to ctx if required. +// adjustVarMap = new HashMap<>(); + HeuristicIgnoringFieldRule.clearCache(); + } + + public static void _start() { + ctx.start(); + } + + public static boolean isShutdown() { + return ctx.stateEquals(TracingState.SHUTDOWN); + } + + public static void setAppJavaClassPath(AppJavaClassPath appPath) { + ctx.setAppJavaClassPath(appPath); + } + + public static void shutdown() { + ctx.shutdown(); + } + + public static void setVariableLayer(int variableLayer) { + ctx.setVariableLayer(variableLayer); + } + + public static void setAvoidProxyToString(boolean avoidProxy) { + ctx.setAvoidProxyToString(avoidProxy); + } + + public static void setAppJavaClassPathOptionalTestClass(String junitClass) { + ctx.appJavaClassPath.setOptionalTestClass(junitClass); + } + + public static void setAppJavaClassPathOptionalTestMethod(String junitMethod) { + ctx.appJavaClassPath.setOptionalTestMethod(junitMethod); + } + + public static int getExpectedSteps() { + return ctx.expectedSteps; + } + + public static int getStepLimit() { + return ctx.stepLimit; + } + + public static List getTraceList() { + return rtStore.getAllThreadTracer().stream().map(tracer -> tracer.getTrace()).collect(Collectors.toList()); + } +} diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracer.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracer.java index 55728081d..5fe5f1373 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracer.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracer.java @@ -43,39 +43,16 @@ import sav.strategies.dto.AppJavaClassPath; public class ExecutionTracer implements IExecutionTracer, ITracer { - private static ExecutionTracerStore rtStore = new ExecutionTracerStore(); - - public static AppJavaClassPath appJavaClassPath; - public static int variableLayer = 2; - public static int stepLimit = Integer.MAX_VALUE; - public static int expectedSteps = Integer.MAX_VALUE; -// private static int tolerantExpectedSteps = expectedSteps; - public static boolean avoidProxyToString = false; private long threadId; - private Trace trace; - private MethodCallStack methodCallStack; - private TrackingDelegate trackingDelegate; - - public static void setExpectedSteps(int expectedSteps) { - if (expectedSteps != AgentConstants.UNSPECIFIED_INT_VALUE) { - ExecutionTracer.expectedSteps = expectedSteps; -// tolerantExpectedSteps = expectedSteps * 2; - } - } + private TracingContext ctx; - public static void setStepLimit(int stepLimit) { - if (stepLimit != AgentConstants.UNSPECIFIED_INT_VALUE) { - ExecutionTracer.stepLimit = stepLimit; - } - } - - public ExecutionTracer(long threadId) { + public ExecutionTracer(long threadId, TracingContext ctx) { this.threadId = threadId; - trackingDelegate = new TrackingDelegate(threadId); - methodCallStack = new MethodCallStack(); - trace = new Trace(appJavaClassPath); + this.methodCallStack = new MethodCallStack(); + this.trace = new Trace(ctx.appJavaClassPath); + this.ctx = ctx; } // private void buildDataRelation(TraceNode currentNode, VarValue value, String @@ -126,7 +103,7 @@ public ExecutionTracer(long threadId) { // } private VarValue appendVarValue(Object value, Variable var, VarValue parent) { - return appendVarValue(value, var, parent, variableLayer); + return appendVarValue(value, var, parent, ctx.variableLayer); } private VarValue appendVarValue(Object value, Variable var, VarValue parent, int retrieveLayer) { @@ -250,7 +227,7 @@ private String getStringValue(final Object obj, String type) { // } // } - if (avoidProxyToString && isProxyClass(obj.getClass())) { + if (ctx.avoidProxyToString && isProxyClass(obj.getClass())) { return obj.getClass().getName(); } @@ -289,7 +266,7 @@ private boolean isProxyClass(Class clazz) { */ public void enterMethod(String className, String methodSignature, int methodStartLine, int methodEndLine, String paramTypeSignsCode, String paramNamesCode, Object[] params) { - trackingDelegate.untrack(); + this.untrack(); TraceNode caller = trace.getLatestNode(); if (caller != null && caller.getMethodSign().contains("")) { caller = caller.getInvocationParent(); @@ -335,10 +312,10 @@ public void enterMethod(String className, String methodSignature, int methodStar } hitLine(methodStartLine, className, methodSignature); } else { - trackingDelegate.track(); + this.track(); return; } - trackingDelegate.track(); + this.track(); } private static Map adjustVarMap = new HashMap<>(); @@ -350,7 +327,7 @@ private int adjustVariableStartScope(String fullSign, String className) { } String shortSign = fullSign.substring(fullSign.indexOf("#") + 1, fullSign.length()); MethodFinderBySignature finder = new MethodFinderBySignature(shortSign); - ByteCodeParser.parse(className, finder, appJavaClassPath); + ByteCodeParser.parse(className, finder, ctx.appJavaClassPath); Method method = finder.getMethod(); if(method == null) { @@ -377,19 +354,19 @@ private int adjustVariableStartScope(String fullSign, String className) { } public void exitMethod(int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); if (!exclusive) { methodCallStack.safePop(); } - trackingDelegate.track(); + this.track(); } @Override public void _hitInvoke(Object invokeObj, String invokeTypeSign, String methodSig, Object[] params, String paramTypeSignsCode, String returnTypeSign, int line, String residingClassName, String residingMethodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { hitLine(line, residingClassName, residingMethodSignature); TraceNode latestNode = trace.getLatestNode(); @@ -419,7 +396,7 @@ public void _hitInvoke(Object invokeObj, String invokeTypeSign, String methodSig handleException(t); } - trackingDelegate.track(); + this.track(); } private void initInvokingDetail(Object invokeObj, String invokeTypeSign, String methodSig, Object[] params, @@ -476,7 +453,7 @@ public void buildWriteRelationForArrayCopy(Object targetArray, int startPosition @Override public void _hitInvokeStatic(String invokeTypeSign, String methodSig, Object[] params, String paramTypeSignsCode, String returnTypeSign, int line, String className, String residingMethodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { hitLine(line, className, residingMethodSignature); @@ -499,18 +476,18 @@ public void _hitInvokeStatic(String invokeTypeSign, String methodSig, Object[] p } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } @Override public void _hitMethodEnd(int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { exitMethod(line, className, methodSignature); } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -519,7 +496,7 @@ public void _hitMethodEnd(int line, String className, String methodSignature) { @Override public void _afterInvoke(Object returnedValue, Object invokeObj, String invokeMethodSig, int line, String residingClassName, String residingMethodSignature, boolean needRevisiting) { - trackingDelegate.untrack(); + this.untrack(); try { boolean exclusive = GlobalFilterChecker.isExclusive(residingClassName, residingMethodSignature); if (!exclusive) { @@ -555,7 +532,7 @@ public void _afterInvoke(Object returnedValue, Object invokeObj, String invokeMe } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } private TraceNode findInvokingMatchNode(TraceNode latestNode, String invokingMethodSig) { @@ -591,7 +568,7 @@ private TraceNode findInvokingMatchNode(TraceNode latestNode, String invokingMet @Override public void _hitReturn(Object returnObj, String returnGeneralTypeSign, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { hitLine(line, className, methodSignature); String returnGeneralType = SignatureUtils.signatureToName(returnGeneralTypeSign); @@ -618,7 +595,7 @@ public void _hitReturn(Object returnObj, String returnGeneralTypeSign, int line, handleException(t); } - trackingDelegate.track(); + this.track(); } private void handleException(Throwable t) { @@ -643,24 +620,24 @@ public void hitLine(int line, String className, String methodSignature) { @Override public void _hitLine(int line, String className, String methodSignature, int numOfReadVars, int numOfWrittenVars) { - boolean isLocked = trackingDelegate.isUntrack(); - trackingDelegate.untrack(); + boolean isLocked = this.ctx.lockedThreads.isUntracking(this.threadId); + this.untrack(); try { boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); if (exclusive) { - trackingDelegate.track(isLocked); + this.track(isLocked); return; } TraceNode latestNode = trace.getLatestNode(); if (latestNode != null && latestNode.getBreakPoint().getClassCanonicalName().equals(className) && latestNode.getBreakPoint().getLineNumber() == line) { - trackingDelegate.track(isLocked); + this.track(isLocked); return; } int order = trace.size() + 1; - if (order > stepLimit) { - shutdown(); + if (order > ctx.stepLimit) { + this.ctx.shutdown(); Agent._exitProgram("fail;Trace is over long!"); } // if (order > tolerantExpectedSteps) { @@ -683,18 +660,18 @@ public void _hitLine(int line, String className, String methodSignature, int num handleException(t); } - trackingDelegate.track(isLocked); + this.track(isLocked); } @Override public void _hitExeptionTarget(int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { hitLine(line, className, methodSignature); TraceNode latestNode = trace.getLatestNode(); if(latestNode == null) return; latestNode.setException(true); - boolean invocationLayerChanged = this.methodCallStack.popForException(methodSignature, appJavaClassPath); + boolean invocationLayerChanged = this.methodCallStack.popForException(methodSignature, ctx.appJavaClassPath); if (invocationLayerChanged) { TraceNode caller = null; @@ -711,7 +688,7 @@ public void _hitExeptionTarget(int line, String className, String methodSignatur } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -723,7 +700,7 @@ public void _hitExeptionTarget(int line, String className, String methodSignatur @Override public void _writeField(Object refValue, Object fieldValue, String fieldName, String fieldType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { hitLine(line, className, methodSignature); boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); @@ -733,11 +710,11 @@ public void _writeField(Object refValue, Object fieldValue, String fieldName, St InvokingDetail invokingDetail = latestNode.getInvokingDetail(); boolean relevant = invokingDetail.updateRelevantVar(refValue, fieldValue, fieldType); if (!relevant) { - trackingDelegate.track(); + this.track(); return; } } else { - trackingDelegate.track(); + this.track(); return; } } @@ -761,7 +738,7 @@ public void _writeField(Object refValue, Object fieldValue, String fieldName, St } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } private void addRWriteValue(TraceNode currentNode, List value, boolean isWrittenVar) { @@ -806,7 +783,7 @@ private void addSingleRWriteValue(TraceNode currentNode, VarValue value, boolean @Override public void _writeStaticField(Object fieldValue, String refType, String fieldName, String fieldType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { // boolean exclusive = FilterChecker.isExclusive(className, methodSignature); // if (exclusive) { @@ -824,7 +801,7 @@ public void _writeStaticField(Object fieldValue, String refType, String fieldNam } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -836,7 +813,7 @@ public void _writeStaticField(Object fieldValue, String refType, String fieldNam @Override public void _readField(Object refValue, Object fieldValue, String fieldName, String fieldType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); if (exclusive) { @@ -847,7 +824,7 @@ public void _readField(Object refValue, Object fieldValue, String fieldName, Str relevant = invokingDetail.updateRelevantVar(refValue, fieldValue, fieldType); } if (!relevant) { - trackingDelegate.track(); + this.track(); return; } } @@ -875,13 +852,13 @@ public void _readField(Object refValue, Object fieldValue, String fieldName, Str } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } @Override public void _readStaticField(Object fieldValue, String refType, String fieldName, String fieldType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { // boolean exclusive = FilterChecker.isExclusive(className, methodSignature); // if (exclusive) { @@ -902,7 +879,7 @@ public void _readStaticField(Object fieldValue, String refType, String fieldName } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -912,7 +889,7 @@ public void _readStaticField(Object fieldValue, String refType, String fieldName @Override public void _writeLocalVar(Object varValue, String varName, String varType, int line, int bcLocalVarIdx, int varScopeStartLine, int varScopeEndLine, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { // boolean exclusive = FilterChecker.isExclusive(className, methodSignature); // if (exclusive) { @@ -936,7 +913,7 @@ public void _writeLocalVar(Object varValue, String varName, String varType, int } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -945,7 +922,7 @@ public void _writeLocalVar(Object varValue, String varName, String varType, int @Override public void _readLocalVar(Object varValue, String varName, String varType, int line, int bcLocalVarIdx, int varScopeStartLine, int varScopeEndLine, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { // boolean exclusive = FilterChecker.isExclusive(className, methodSignature); // if (exclusive) { @@ -1004,7 +981,7 @@ public void _readLocalVar(Object varValue, String varName, String varType, int l } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } private boolean isParameter(int varScopeStartLine, int varScopeEndLine, String className) { @@ -1012,7 +989,7 @@ private boolean isParameter(int varScopeStartLine, int varScopeEndLine, String c String fullSign = point.getMethodSign(); String shortSign = fullSign.substring(fullSign.indexOf("#") + 1, fullSign.length()); MethodFinderBySignature finder = new MethodFinderBySignature(shortSign); - ByteCodeParser.parse(className, finder, appJavaClassPath); + ByteCodeParser.parse(className, finder, ctx.appJavaClassPath); Method method = finder.getMethod(); if (method != null && method.getCode() != null) { @@ -1037,7 +1014,7 @@ private boolean isParameter(int varScopeStartLine, int varScopeEndLine, String c @Override public void _iincLocalVar(Object varValue, Object varValueAfter, String varName, String varType, int line, int bcLocalVarIdx, int varScopeStartLine, int varScopeEndLine, String className, String methodSignature) { - trackingDelegate.untrack(); + this.untrack(); try { // boolean exclusive = FilterChecker.isExclusive(className, methodSignature); // if (exclusive) { @@ -1064,7 +1041,7 @@ public void _iincLocalVar(Object varValue, Object varValueAfter, String varName, } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } /** @@ -1077,7 +1054,7 @@ public void _iincLocalVar(Object varValue, Object varValueAfter, String varName, @Override public void _readArrayElementVar(Object arrayRef, int index, Object eleValue, String elementType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.ctx.lockedThreads.untrack(this.threadId); try { boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); if (exclusive) { @@ -1088,7 +1065,7 @@ public void _readArrayElementVar(Object arrayRef, int index, Object eleValue, St relevant = invokingDetail.updateRelevantVar(arrayRef, eleValue, elementType); } if (!relevant) { - trackingDelegate.track(); + this.track(); return; } } @@ -1107,7 +1084,7 @@ public void _readArrayElementVar(Object arrayRef, int index, Object eleValue, St } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } private void addHeuristicVarChildren(TraceNode latestNode, VarValue value, boolean isWritten) { @@ -1170,7 +1147,7 @@ private void addHeuristicVarChildren(TraceNode latestNode, VarValue value, boole @Override public void _writeArrayElementVar(Object arrayRef, int index, Object eleValue, String elementType, int line, String className, String methodSignature) { - trackingDelegate.untrack(); + this.ctx.lockedThreads.untrack(this.threadId); try { boolean exclusive = GlobalFilterChecker.isExclusive(className, methodSignature); if (exclusive) { @@ -1181,7 +1158,7 @@ public void _writeArrayElementVar(Object arrayRef, int index, Object eleValue, S relevant = invokingDetail.updateRelevantVar(arrayRef, eleValue, elementType); } if (!relevant) { - trackingDelegate.track(); + this.track(); return; } } @@ -1198,7 +1175,7 @@ public void _writeArrayElementVar(Object arrayRef, int index, Object eleValue, S } catch (Throwable t) { handleException(t); } - trackingDelegate.track(); + this.track(); } private VarValue addArrayElementVarValue(Object arrayRef, int index, Object eleValue, String elementType, int line) { @@ -1217,172 +1194,53 @@ private VarValue addArrayElementVarValue(Object arrayRef, int index, Object eleV return value; } - /** - * BE VERY CAREFUL WHEN MODIFYING THIS FUNCTION! TO AVOID CREATING A LOOP, DO - * KEEP THIS ATMOST SIMPLE, AVOID INVOKE ANY EXTERNAL LIBRARY FUNCTION, EVEN JDK - * INSIDE THIS BLOCK OF CODE AND ITS INVOKED METHODS.! (ONLY - * Thread.currentThread().getId() is exceptional used) IF NEED TO USE A LIST,MAP - * -> USE AN ARRAY INSTEAD! - */ - public synchronized static IExecutionTracer _getTracer(boolean isAppClass, String className, String methodSig, - int methodStartLine, int methodEndLine, String paramNamesCode, String paramTypeSignsCode, Object[] params) { - try { - if (state == TracingState.TEST_STARTED && isAppClass) { - state = TracingState.RECORDING; - rtStore.setMainThreadId(Thread.currentThread().getId()); - } - if (state != TracingState.RECORDING) { - return EmptyExecutionTracer.getInstance(); - } - long threadId = Thread.currentThread().getId(); - if (lockedThreads.isUntracking(threadId)) { - return EmptyExecutionTracer.getInstance(); - } - lockedThreads.untrack(threadId); - // FIXME -mutithread LINYUN [1] - /* - * LLT: the corresponding tracer for a thread will be load by threadId, - * currently we always return null if not main thread. - */ - ExecutionTracer tracer = rtStore.get(threadId); - if (tracer == null) { - tracer = rtStore.get(threadId); - // lockedThreads.remove(threadId); - // return EmptyExecutionTracer.getInstance(); - } - tracer.enterMethod(className, methodSig, methodStartLine, methodEndLine, paramTypeSignsCode, paramNamesCode, - params); - lockedThreads.track(threadId); - return tracer; - } catch (Throwable t) { - t.printStackTrace(); - throw t; - } - } - - public static IExecutionTracer getMainThreadStore() { - return rtStore.getMainThreadTracer(); - } - - public static List getAllThreadStore() { - return rtStore.getAllThreadTracer(); - } - - public static synchronized IExecutionTracer getCurrentThreadStore() { - synchronized (rtStore) { - long threadId = Thread.currentThread().getId(); - // String threadName = Thread.currentThread().getName(); - if (lockedThreads.isUntracking(threadId)) { - return EmptyExecutionTracer.getInstance(); - } - IExecutionTracer tracer = rtStore.get(threadId); - // store.setThreadName(threadName); - - if (tracer == null) { - tracer = EmptyExecutionTracer.getInstance(); - } - return tracer; - } - } - - public static List stoppedThreads = new ArrayList(); - - public static synchronized void stopRecordingCurrendThread() { - synchronized (rtStore) { - long threadId = Thread.currentThread().getId(); - lockedThreads.untrack(threadId); - stoppedThreads.add(threadId); - } - } - - private static TracingState state = TracingState.INIT; - - public static void shutdown() { - state = TracingState.SHUTDOWN; - } - - public static void dispose() { - adjustVarMap = new HashMap<>(); - lockedThreads = new LockedThreads(); - HeuristicIgnoringFieldRule.clearCache(); - } - - public static void _start() { - state = TracingState.TEST_STARTED; - } - - public static boolean isShutdown() { - return state == TracingState.SHUTDOWN; + public long getThreadId() { + return threadId; } - public Trace getTrace() { - return trace; + @Override + public void setThreadName(String threadName) { + this.trace.setThreadName(threadName); } - private static volatile LockedThreads lockedThreads = new LockedThreads(); - - static class TrackingDelegate { -// boolean tracing; - long threadId; - - public TrackingDelegate(long threadId) { - this.threadId = threadId; - } - - public void untrack() { -// if (!tracing) { -// lockedThreads.untrack(threadId); -// tracing = true; -// } - lockedThreads.untrack(threadId); - } - - public void track(boolean preserveLock) { - if (!preserveLock) { - track(); - } - } - - public void track() { -// tracing = false; - lockedThreads.track(threadId); - } - - public boolean isUntrack() { - return lockedThreads.isUntracking(threadId); - } + public String getThreadName() { + return this.trace.getThreadName(); } @Override public boolean lock() { - boolean isLock = trackingDelegate.isUntrack(); + boolean isLock = this.ctx.lockedThreads.isUntracking(this.threadId); if (!isLock) { - trackingDelegate.untrack(); + this.untrack(); } return isLock; } - public boolean isLock() { - return trackingDelegate.isUntrack(); - } - @Override public void unLock() { - trackingDelegate.track(); + this.track(); } - public long getThreadId() { - return threadId; + private void untrack() { + this.ctx.lockedThreads.untrack(this.threadId); } - @Override - public void setThreadName(String threadName) { - this.trace.setThreadName(threadName); + private void track() { + this.ctx.lockedThreads.track(this.threadId); } - public String getThreadName() { - return this.trace.getThreadName(); + private void track(boolean preserveLock) { + if (!preserveLock) { + this.track(); + } } + @Override + public Trace getTrace() { + return this.trace; + } + public void setMain(boolean isMain) { + this.trace.setMain(isMain); + } } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracerStore.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracerStore.java index f6c240a26..48412b6e8 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracerStore.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/ExecutionTracerStore.java @@ -2,9 +2,15 @@ public class ExecutionTracerStore extends TracerStore { + private TracingContext ctx; + + public ExecutionTracerStore(TracingContext ctx) { + this.ctx = ctx; + } + @Override protected ExecutionTracer initTracer(long threadId) { - return new ExecutionTracer(threadId); + return new ExecutionTracer(threadId, this.ctx); } } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/IExecutionTracer.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/IExecutionTracer.java index c57586644..6045410a0 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/IExecutionTracer.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/IExecutionTracer.java @@ -1,5 +1,7 @@ package microbat.instrumentation.runtime; +import microbat.model.trace.Trace; + public interface IExecutionTracer { public void _hitInvoke(Object invokeObj, String invokeTypeSign, String methodName, Object[] params, @@ -52,4 +54,6 @@ void _afterInvoke(Object returnedValue, Object invokeObj, String invokeMethodSig public void setThreadName(String threadName); + public Trace getTrace(); + } diff --git a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/TracerStore.java b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/TracerStore.java index 71a08426b..1c1f0e07f 100644 --- a/microbat_instrumentator/src/main/microbat/instrumentation/runtime/TracerStore.java +++ b/microbat_instrumentator/src/main/microbat/instrumentation/runtime/TracerStore.java @@ -14,29 +14,11 @@ public abstract class TracerStore { public static final int INVALID_THREAD_ID = -1; private Map rtStore = new HashMap<>(); -// protected ITracer[] rtStore = new ITracer[10]; protected long mainThreadId = INVALID_THREAD_ID; protected transient int lastUsedIdx = INVALID_THREAD_ID; /* threadId must be valid */ - @SuppressWarnings("unchecked") public synchronized T get(long threadId) { - // FIXME -mutithread LINYUN [2] - // LLT: this is where we disable recording other threads not the main one -// if (threadId != mainThreadId) { -// return null; // for now, only recording trace for main thread. -// } - -// int i = 0; -// while(i <= lastUsedIdx) { -// ITracer tracer = rtStore[i]; -// if (tracer.getThreadId() == threadId) { -// return (T) tracer; -// } -// i++; -// } -// T tracer = initTracer(threadId); -// rtStore[++lastUsedIdx] = tracer; if (rtStore.containsKey(threadId)) { return rtStore.get(threadId); } @@ -49,6 +31,7 @@ public synchronized T get(long threadId) { public void setMainThreadId(long mainThreadId) { this.mainThreadId = mainThreadId; + get(mainThreadId).setMain(true); } public T getMainThreadTracer() { @@ -61,13 +44,5 @@ public long getMainThreadId() { public List getAllThreadTracer() { return new ArrayList(rtStore.values()); -// List traces = new ArrayList<>(); -// for(int i=0; i ls = new ArrayList<>(); ls.add("Good Day"); tracer._hitInvoke(null, null, "methodname", null, "paramTypeSignsCode", "returnTypeSign", 17, "", ""); diff --git a/microbat_instrumentator/src/test/java/microbat/tools/JarPackageTool.java b/microbat_instrumentator/src/test/java/microbat/tools/JarPackageTool.java index 627d6a18c..fbf9eb378 100644 --- a/microbat_instrumentator/src/test/java/microbat/tools/JarPackageTool.java +++ b/microbat_instrumentator/src/test/java/microbat/tools/JarPackageTool.java @@ -91,6 +91,35 @@ public static void main(String[] args) throws Exception { .append("-C").append(BASE_DIR) .append("lib/slf4j-api-1.7.12.jar"); vmRunner.startAndWaitUntilStop(cmd.toCollection()); + cmd.clear(); + + DEPLOY_JAR_PATH = "/home/dingyuchen/eclipse/committers-2021-03/eclipse/dropins/junit_lib"; + cmd.append(TestConfiguration.getJavaHome() + "/bin/jar") + .append("cfm") + .append(DEPLOY_JAR_PATH) + .append(BASE_DIR + "/META-INF/MANIFEST.MF") + .append("-C") + .append(BASE_DIR + "bin") + .append("microbat") + .append("-C").append(BASE_DIR) + .append("lib/" + agentJar) + .append("-C").append(BASE_DIR) + .append("lib/bcel-6.0.jar") + .append("-C").append(BASE_DIR) + .append("lib/javassist.jar") + .append("-C").append(BASE_DIR) + .append("lib/commons-lang-2.6.jar") + .append("-C").append(BASE_DIR) + .append("lib/sav.commons.simplified.jar") + .append("-C").append(BASE_DIR) + .append("lib/commons-io-1.3.2.jar") + .append("-C").append(BASE_DIR) + .append("lib/mysql-connector-java-5.1.44-bin.jar") + .append("-C").append(BASE_DIR) + .append("lib/sqlite-jdbc-3.32.3.2.jar") + .append("-C").append(BASE_DIR) + .append("lib/slf4j-api-1.7.12.jar"); + vmRunner.startAndWaitUntilStop(cmd.toCollection()); System.out.println("Deploy instrumentator.jar to " + DEPLOY_JAR_PATH); System.out.println("Done!");