diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 5724c65..7308a9f 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -77,6 +77,7 @@
+
diff --git a/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ITraceProvider.java b/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ITraceProvider.java
index db030f0..46de233 100644
--- a/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ITraceProvider.java
+++ b/agent-api/src/main/java/com/intergral/deep/agent/api/plugin/ITraceProvider.java
@@ -47,5 +47,7 @@ interface ISpan extends AutoCloseable {
String traceId();
String spanId();
+
+ void addAttribute(String key, String value);
}
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java b/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java
index 4425501..4215178 100644
--- a/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java
+++ b/agent/src/main/java/com/intergral/deep/agent/DeepAgent.java
@@ -62,7 +62,7 @@ public DeepAgent(final Settings settings,
this.grpcService = new GrpcService(settings);
this.pollService = new LongPollService(settings, this.grpcService);
this.tracepointConfig = new TracepointConfigService(tracepointInstrumentationService);
- final PushService pushService = new PushService(settings, grpcService);
+ final PushService pushService = new PushService(grpcService);
Callback.init(settings, tracepointConfig, pushService);
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/push/PushService.java b/agent/src/main/java/com/intergral/deep/agent/push/PushService.java
index ecfb34d..786a22f 100644
--- a/agent/src/main/java/com/intergral/deep/agent/push/PushService.java
+++ b/agent/src/main/java/com/intergral/deep/agent/push/PushService.java
@@ -17,16 +17,11 @@
package com.intergral.deep.agent.push;
-import com.intergral.deep.agent.api.plugin.ISnapshotContext;
-import com.intergral.deep.agent.api.plugin.ISnapshotDecorator;
-import com.intergral.deep.agent.api.resource.Resource;
import com.intergral.deep.agent.grpc.GrpcService;
-import com.intergral.deep.agent.settings.Settings;
import com.intergral.deep.agent.types.snapshot.EventSnapshot;
import com.intergral.deep.proto.tracepoint.v1.Snapshot;
import com.intergral.deep.proto.tracepoint.v1.SnapshotResponse;
import io.grpc.stub.StreamObserver;
-import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,12 +31,10 @@
public class PushService {
private static final Logger LOGGER = LoggerFactory.getLogger(PushService.class);
- private final Settings settings;
private final GrpcService grpcService;
- public PushService(final Settings settings, final GrpcService grpcService) {
- this.settings = settings;
+ public PushService(final GrpcService grpcService) {
this.grpcService = grpcService;
}
@@ -49,29 +42,12 @@ public PushService(final Settings settings, final GrpcService grpcService) {
* Decorate and push the provided snapshot.
*
* @param snapshot the snapshot to push
- * @param context the context of where the snapshot is collected
*/
- public void pushSnapshot(final EventSnapshot snapshot, final ISnapshotContext context) {
- decorate(snapshot, context);
+ public void pushSnapshot(final EventSnapshot snapshot) {
final Snapshot grpcSnapshot = PushUtils.convertToGrpc(snapshot);
this.grpcService.snapshotService().send(grpcSnapshot, new LoggingObserver(snapshot.getID()));
}
- private void decorate(final EventSnapshot snapshot, final ISnapshotContext context) {
- final Collection plugins = this.settings.getPlugins(ISnapshotDecorator.class);
- for (ISnapshotDecorator plugin : plugins) {
- try {
- final Resource decorate = plugin.decorate(this.settings, context);
- if (decorate != null) {
- snapshot.mergeAttributes(decorate);
- }
- } catch (Throwable t) {
- LOGGER.error("Error processing plugin {}", plugin.getClass().getName());
- }
- }
- snapshot.close();
- }
-
static class LoggingObserver implements StreamObserver {
private final String id;
diff --git a/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java b/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java
index 653eee4..5f0f3b0 100644
--- a/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java
+++ b/agent/src/main/java/com/intergral/deep/agent/settings/Settings.java
@@ -23,6 +23,7 @@
import com.intergral.deep.agent.api.resource.Resource;
import com.intergral.deep.agent.api.settings.ISettings;
import com.intergral.deep.agent.api.spi.IDeepPlugin;
+import com.intergral.deep.agent.types.TracePointConfig.EStage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -182,6 +183,8 @@ public static T coerc(final String str, final Class type) {
return (T) Level.parse(str);
} else if (type == Pattern.class) {
return (T) Pattern.compile(str);
+ } else if (type == EStage.class) {
+ return (T) EStage.fromArg(str);
} else if (type == URL.class) {
try {
return (T) new URL(str);
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/TracepointConfigService.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/TracepointConfigService.java
index c62d3c0..cdadaa1 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/TracepointConfigService.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/TracepointConfigService.java
@@ -39,7 +39,7 @@ public class TracepointConfigService implements ITracepointConfig {
private final TracepointInstrumentationService tracepointInstrumentationService;
private String currentHash = null;
private final Collection customTracepoints = new ArrayList<>();
- private Collection installedTracepoints = new ArrayList<>();
+ protected Collection installedTracepoints = new ArrayList<>();
@SuppressWarnings("unused")
private long lastUpdate;
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/cf/CFFrameProcessor.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/cf/CFFrameProcessor.java
index c43ca80..f0cd9b9 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/cf/CFFrameProcessor.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/cf/CFFrameProcessor.java
@@ -38,8 +38,9 @@ public CFFrameProcessor(final Settings settings,
final IEvaluator evaluator,
final Map variables,
final Collection tracePointConfigs,
- final long[] lineStart, final StackTraceElement[] stack) {
- super(settings, evaluator, variables, tracePointConfigs, lineStart, stack);
+ final long[] lineStart, final StackTraceElement[] stack,
+ final String methodName) {
+ super(settings, evaluator, variables, tracePointConfigs, lineStart, stack, methodName);
}
@Override
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/Callback.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/Callback.java
index 2b9fa21..b0587d1 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/Callback.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/Callback.java
@@ -19,23 +19,36 @@
import com.intergral.deep.agent.Utils;
import com.intergral.deep.agent.api.plugin.IEvaluator;
+import com.intergral.deep.agent.api.plugin.ISnapshotContext;
+import com.intergral.deep.agent.api.plugin.ISnapshotDecorator;
import com.intergral.deep.agent.api.plugin.ITraceProvider;
import com.intergral.deep.agent.api.plugin.ITraceProvider.ISpan;
import com.intergral.deep.agent.api.plugin.LazyEvaluator;
+import com.intergral.deep.agent.api.resource.Resource;
import com.intergral.deep.agent.push.PushService;
import com.intergral.deep.agent.settings.Settings;
import com.intergral.deep.agent.tracepoint.TracepointConfigService;
import com.intergral.deep.agent.tracepoint.cf.CFEvaluator;
import com.intergral.deep.agent.tracepoint.cf.CFFrameProcessor;
import com.intergral.deep.agent.tracepoint.evaluator.EvaluatorService;
+import com.intergral.deep.agent.tracepoint.handler.FrameProcessor.IFactory;
import com.intergral.deep.agent.types.TracePointConfig;
+import com.intergral.deep.agent.types.TracePointConfig.EStage;
import com.intergral.deep.agent.types.snapshot.EventSnapshot;
+import com.intergral.deep.agent.types.snapshot.Variable;
+import com.intergral.deep.agent.types.snapshot.VariableID;
+import com.intergral.deep.agent.types.snapshot.WatchResult;
import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
import java.util.List;
import java.util.Map;
-import java.util.Set;
+import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,23 +60,9 @@ public final class Callback {
private Callback() {
}
- // @SuppressWarnings("AnonymousHasLambdaAlternative")
- // public static final ThreadLocal> CALLBACKS = new ThreadLocal>()
- // {
- // @Override
- // protected Deque initialValue()
- // {
- // return new ArrayDeque<>();
- // }
- // };
+ private static final ThreadLocal> CALLBACKS = ThreadLocal.withInitial(ArrayDeque::new);
private static final Logger LOGGER = LoggerFactory.getLogger(Callback.class);
- @SuppressWarnings("AnonymousHasLambdaAlternative")
- private static final ThreadLocal FIRING = new ThreadLocal() {
- @Override
- protected Boolean initialValue() {
- return Boolean.FALSE;
- }
- };
+ private static final ThreadLocal FIRING = ThreadLocal.withInitial(() -> Boolean.FALSE);
private static Settings SETTINGS;
private static TracepointConfigService TRACEPOINT_SERVICE;
@@ -108,7 +107,7 @@ public static void callBackCF(final List bpIds,
final Map variables) {
try {
final IEvaluator evaluator = new LazyEvaluator(new CFEvaluator.Loader(variables));
- commonCallback(bpIds, filename, lineNo, variables, evaluator, CFFrameProcessor::new);
+ commonCallback(bpIds, filename, lineNo, null, variables, evaluator, CFFrameProcessor::new, null);
} catch (Throwable t) {
LOGGER.debug("Unable to process tracepoint {}:{}", filename, lineNo, t);
}
@@ -129,22 +128,42 @@ public static void callBack(final List bpIds,
final Map variables) {
try {
final IEvaluator evaluator = new LazyEvaluator(EvaluatorService::createEvaluator);
- commonCallback(bpIds, filename, lineNo, variables, evaluator, FrameProcessor::new);
+ final ICallbackResult callbackResult = commonCallback(bpIds, filename, lineNo, null, variables, evaluator,
+ FrameProcessor::new, null);
+ if (callbackResult != null) {
+ final String spans = callbackResult.tracepoints().stream()
+ .filter(tracePointConfig -> TracePointConfig.LINE.equals(tracePointConfig.getArg(TracePointConfig.SPAN, String.class, null)))
+ .map(TracePointConfig::getId).collect(Collectors.joining(","));
+ final Closeable span;
+ if (!spans.isEmpty()) {
+ span = span(filename + lineNo, spans);
+ } else {
+ span = null;
+ }
+ CALLBACKS.get().add(new CallbackHook(span, callbackResult.deferred(), callbackResult.frameProcessor(),
+ callbackResult.frameProcessor().getLineStart()[1]));
+ }
} catch (Throwable t) {
LOGGER.debug("Unable to process tracepoint {}:{}", filename, lineNo, t);
}
}
- private static void commonCallback(final List tracepointIds,
+ private static ICallbackResult commonCallback(final List tracepointIds,
final String filename,
final int lineNo,
+ final String methodName,
final Map variables,
- final IEvaluator evaluator, final FrameProcessor.IFactory factory) {
+ final IEvaluator evaluator,
+ final IFactory factory,
+ final CallbackHook callbackHook) {
+ if (tracepointIds.isEmpty()) {
+ return null;
+ }
final long[] lineStart = Utils.currentTimeNanos();
if (FIRING.get()) {
LOGGER.debug("hit - skipping as we are already firing");
- return;
+ return null;
}
try {
@@ -153,7 +172,7 @@ private static void commonCallback(final List tracepointIds,
// possible race condition but unlikely
if (Callback.TRACEPOINT_SERVICE == null) {
- return;
+ return null;
}
final Collection tracePointConfigs = Callback.TRACEPOINT_SERVICE.loadTracepointConfigs(
@@ -170,154 +189,122 @@ private static void commonCallback(final List tracepointIds,
variables,
tracePointConfigs,
lineStart,
- stack);
+ stack,
+ methodName);
+ final ArrayList deferredSnapshots = new ArrayList<>();
if (frameProcessor.canCollect()) {
frameProcessor.configureSelf();
-
try {
- final Collection snapshots = frameProcessor.collect();
- for (EventSnapshot snapshot : snapshots) {
- Callback.PUSH_SERVICE.pushSnapshot(snapshot, frameProcessor);
+ final Collection collect = frameProcessor.collect();
+ for (EventSnapshot eventSnapshot : collect) {
+ decorate(eventSnapshot, frameProcessor);
+ if (isDeferred(eventSnapshot)) {
+ deferredSnapshots.add(eventSnapshot);
+ continue;
+ }
+ // if we have a callback hook then decorate snapshot with details
+ if (callbackHook != null) {
+ callbackHook.decorate(eventSnapshot, frameProcessor);
+ }
+ Callback.PUSH_SERVICE.pushSnapshot(eventSnapshot);
}
} catch (Exception e) {
LOGGER.debug("Error processing snapshot", e);
}
}
+
+ if (callbackHook != null) {
+ callbackHook.close(Callback.PUSH_SERVICE);
+ }
+ return new ICallbackResult() {
+ @Override
+ public Collection deferred() {
+ return deferredSnapshots;
+ }
+
+ @Override
+ public Collection tracepoints() {
+ return frameProcessor.getFilteredTracepoints();
+ }
+
+ @Override
+ public FrameProcessor frameProcessor() {
+ frameProcessor.closeLookup();
+ return frameProcessor;
+ }
+ };
} finally {
FIRING.set(false);
}
}
- // the below methods are here as they are called from instrumented classes.
- // This is a throwback to NV that we will address in later releases
- public static void callBackException(final Throwable t) {
- // System.out.println( "callBackException" );
- // try
- // {
- // LOGGER.debug( "Capturing throwable", t );
- // final CallbackHook element = CALLBACKS.get().peekLast();
- // if( element != null && element.isHook())
- // {
- // element.setThrowable( t );
- // }
- // }
- // catch( Throwable tt )
- // {
- // LOGGER.debug( "Error processing callback", tt );
- // }
+ private interface ICallbackResult {
+ Collection deferred();
+
+ Collection tracepoints();
+
+ FrameProcessor frameProcessor();
}
+ private static boolean isDeferred(final EventSnapshot eventSnapshot) {
+ final EStage arg = eventSnapshot.getTracepoint().getArg(TracePointConfig.STAGE, EStage.class, null);
+ return arg == EStage.LINE_CAPTURE || arg == EStage.METHOD_CAPTURE;
+ }
- public static void callBackFinally(final Set breakpointIds,
- final Map map) {
- // System.out.println( "callBackFinally" );
- // for( String breakpointId : breakpointIds )
- // {
- // try
- // {
- // LOGGER.debug( "{}: Processing finally", breakpointId );
- // final Deque hooks = CALLBACKS.get();
- // final CallbackHook pop = hooks.pollLast();
- // LOGGER.debug( "Dequeue state: {}", hooks );
- // if( pop == null || !pop.isHook() )
- // {
- // LOGGER.debug( "No callback pending. {}", pop );
- // continue;
- // }
- //
- // final boolean processFrameStack = (pop.value.getType().equals( ITracepoint.STACK_TYPE )) || pop.value.getType()
- // .equals( ITracepoint.FRAME_TYPE ) || pop.value.getType().equals( ITracepoint.LOG_POINT_TYPE )
- // || pop.value.getType().equals( ITracepoint.NO_FRAME_TYPE );
- //
- // final List frames;
- // if( pop.value.getArg( ITracepoint.LINE_HOOK_ARG_KEY ).equals( ITracepoint.LINE_HOOK_DATA_RIGHT ) )
- // {
- // frames = pop.snapshotHandler.processFrames( map, processFrameStack, System.currentTimeMillis() );
- // }
- // else
- // {
- // frames = pop.frames;
- // }
- //
- // // trim frames to our type
- // @SuppressWarnings({ "RedundantTypeArguments", "Convert2Diamond" })
- // final IRequestDecorator iRequestDecorator = pop.snapshotHandler.generateSnapshotData( pop.watchValues, pop.value,
- // frames, Collections.emptySet(),
- // NVError.fromThrowable( pop.throwable, new HashMap() ),
- // System.currentTimeMillis(), Callback.CLIENT_CONFIG.getTags() );
- //
- // final EventSnapshot eventSnapshot = iRequestDecorator.getBody();
- // addDynamicTags( pop.value, eventSnapshot );
- //
- // sendEvent( iRequestDecorator, eventSnapshot );
- // }
- // catch( Throwable t )
- // {
- // LOGGER.debug( "Error processing callback", t );
- // }
- // }
+ private static void decorate(final EventSnapshot snapshot, final ISnapshotContext context) {
+ final Collection plugins = Callback.SETTINGS.getPlugins(ISnapshotDecorator.class);
+ for (ISnapshotDecorator plugin : plugins) {
+ try {
+ final Resource decorate = plugin.decorate(Callback.SETTINGS, context);
+ if (decorate != null) {
+ snapshot.mergeAttributes(decorate);
+ }
+ } catch (Throwable t) {
+ LOGGER.error("Error processing plugin {}", plugin.getClass().getName());
+ }
+ }
+ snapshot.close();
}
- // public static class CallbackHook
- // {
- //
- // private final SnapshotHandler snapshotHandler;
- // private final List watchValues;
- // private final ITracepoint value;
- // private final List frames;
- // private Throwable throwable;
- //
- //
- // public CallbackHook( final SnapshotHandler snapshotHandler,
- // final List watchValues,
- // final ITracepoint value,
- // final List frames )
- // {
- // this.snapshotHandler = snapshotHandler;
- // this.watchValues = watchValues;
- // this.value = value;
- // this.frames = frames;
- // }
- //
- //
- // public CallbackHook()
- // {
- // this.snapshotHandler = null;
- // this.watchValues = null;
- // this.value = null;
- // this.frames = null;
- // }
- //
- //
- // /**
- // * This will return {@code true} when there is a live hook for this.
- // *
- // * @return {@code true} if this is a hook else {@code false}.
- // */
- // public boolean isHook()
- // {
- // return this.snapshotHandler != null;
- // }
- //
- //
- // void setThrowable( final Throwable t )
- // {
- // this.throwable = t;
- // }
- //
- //
- // @Override
- // public String toString()
- // {
- // if( value == null )
- // {
- // return "Marker for non callback";
- // }
- // return String.format( "%s:%s", value.getRelPath(), value.getLineNo() );
- // }
- // }
+ /**
+ * This is called when an exception is captured on the visited line.
+ *
+ * @param t the exception that was captured.
+ */
+ public static void callBackException(final Throwable t) {
+ try {
+ LOGGER.debug("Capturing throwable", t);
+ final CallbackHook element = CALLBACKS.get().peekLast();
+ if (element != null) {
+ element.setThrowable(t);
+ }
+ } catch (Throwable tt) {
+ LOGGER.debug("Error processing callback", tt);
+ }
+ }
+
+ /**
+ * This is called when the visited line is completed.
+ *
+ * @param bpIds the tracepoint ids that triggered this
+ * @param filename the source file name
+ * @param lineNo the line number we are on
+ * @param variables the captured local variables
+ */
+ public static void callBackFinally(final List bpIds,
+ final String filename,
+ final int lineNo,
+ final Map variables) {
+ try {
+ final IEvaluator evaluator = new LazyEvaluator(EvaluatorService::createEvaluator);
+ final CallbackHook callbackHook = CALLBACKS.get().pollLast();
+ commonCallback(bpIds, filename, lineNo, null, variables, evaluator, FrameProcessor::new, callbackHook);
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to process tracepoint {}:{}", filename, lineNo, t);
+ }
+ }
/**
* Create a span using the tracepoint callback.
@@ -328,9 +315,10 @@ public static void callBackFinally(final Set breakpointIds,
* We use {@link Closeable} here, so we can stick to java types in the injected code. This makes testing and injected code simpler.
*
* @param name the name of the span
+ * @param bps the tracepoints that triggered this span
* @return a {@link Closeable} to close the span
*/
- public static Closeable span(final String name) {
+ public static Closeable span(final String name, final String bps) {
try {
final ITraceProvider plugin = SETTINGS.getPlugin(ITraceProvider.class);
if (plugin == null) {
@@ -343,6 +331,7 @@ public static Closeable span(final String name) {
return () -> {
};
}
+ span.addAttribute("tracepoint", bps);
return () -> {
try {
span.close();
@@ -356,4 +345,173 @@ public static Closeable span(final String name) {
};
}
}
+
+ /**
+ * This method is called when a tracepoint has triggered a method entry type.
+ *
+ * This method will Always return a closable. This way the injected code never deals with anything but calling close. Even if close
+ * doesn't do anything.
+ *
+ * We use {@link Closeable} here, so we can stick to java types in the injected code. This makes testing and injected code simpler.
+ *
+ * @param methodName the method name we have entered
+ * @param filename the file name the method is in
+ * @param lineNo the line number the method is on
+ * @param bpIds the tracepoint ids that have been triggered by this entry
+ * @param variables the map of variables captured
+ * @param spanOnlyIds the CSV of the tracepoints ids that just want a span
+ */
+ public static void methodEntry(final String methodName, final String filename, final int lineNo, final List bpIds,
+ final Map variables, final String spanOnlyIds) {
+ try {
+ final IEvaluator evaluator = new LazyEvaluator(EvaluatorService::createEvaluator);
+ final ICallbackResult callbackResult = commonCallback(bpIds, filename, lineNo, methodName, variables, evaluator,
+ FrameProcessor::new, null);
+ if (callbackResult != null) {
+ final String spans = callbackResult.tracepoints().stream()
+ .filter(tracePointConfig -> TracePointConfig.METHOD.equals(tracePointConfig.getArg(TracePointConfig.SPAN, String.class, null)))
+ .map(TracePointConfig::getId).collect(Collectors.joining(","));
+ final Closeable span;
+ if (!spans.isEmpty()) {
+ span = span(methodName, spans + "," + spanOnlyIds);
+ } else {
+ span = null;
+ }
+ CALLBACKS.get().add(new CallbackHook(span, callbackResult.deferred(), callbackResult.frameProcessor(),
+ callbackResult.frameProcessor().getLineStart()[1]));
+ } else if (spanOnlyIds != null && !spanOnlyIds.isEmpty()) {
+ final Closeable span = span(methodName, spanOnlyIds);
+ CALLBACKS.get().add(new CallbackHook(span, Collections.emptyList(), null, Utils.currentTimeNanos()[1]));
+ } else {
+ // we need a callback as we need to capture error/return
+ // we would only get this far if we are a method exit capture tp
+ CALLBACKS.get().add(new CallbackHook(null, Collections.emptyList(), null, Utils.currentTimeNanos()[1]));
+ }
+
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to process tracepoint {}:{}", filename, lineNo, t);
+ }
+ }
+
+ /**
+ * This is called when an exception is captured from a wrapped method.
+ *
+ * @param t the captured throwable
+ */
+ public static void methodException(final Throwable t) {
+ try {
+ LOGGER.debug("Capturing throwable", t);
+ final CallbackHook element = CALLBACKS.get().peekLast();
+ if (element != null) {
+ element.setThrowable(t);
+ }
+ } catch (Throwable tt) {
+ LOGGER.debug("Error processing callback", tt);
+ }
+ }
+
+ /**
+ * This is called when the returned value from the wrapped method is captured.
+ *
+ * This method is not called on void methods.
+ *
+ * @param value the captured return value.
+ */
+ public static void methodRet(final Object value) {
+ try {
+ LOGGER.debug("Capturing ret: {}", value);
+ final CallbackHook element = CALLBACKS.get().peekLast();
+ if (element != null) {
+ element.setReturn(value);
+ }
+ } catch (Throwable tt) {
+ LOGGER.debug("Error processing callback", tt);
+ }
+ }
+
+ /**
+ * This method is called when a wrapped method has completed.
+ *
+ * @param methodName the method name
+ * @param filename the source file name
+ * @param lineNo the line number
+ * @param bpIds the triggering tracepoints ids
+ * @param variables the captured local variables
+ */
+ public static void methodEnd(final String methodName, final String filename, final int lineNo, final List bpIds,
+ final Map variables) {
+ try {
+ final IEvaluator evaluator = new LazyEvaluator(EvaluatorService::createEvaluator);
+ final CallbackHook callbackHook = CALLBACKS.get().pollLast();
+ commonCallback(bpIds, filename, lineNo, methodName, variables, evaluator, FrameProcessor::new, callbackHook);
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to process tracepoint {}:{}", filename, lineNo, t);
+ }
+ }
+
+ private static class CallbackHook {
+
+ private final Closeable span;
+ private final Collection deferred;
+ private final FrameProcessor frameProcessor;
+ private final long ts;
+ private Throwable throwable;
+ private boolean isSet = false;
+ private Object value;
+
+ public CallbackHook(final Closeable span, final Collection deferred, final FrameProcessor frameProcessor,
+ final long ts) {
+ this.span = span;
+ this.deferred = deferred;
+ this.frameProcessor = frameProcessor;
+ this.ts = ts;
+ }
+
+ public void setThrowable(final Throwable throwable) {
+ this.throwable = throwable;
+ }
+
+ public void setReturn(final Object value) {
+ isSet = true;
+ this.value = value;
+ }
+
+ public void close(final PushService pushService) {
+ if (span != null) {
+ try {
+ span.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ for (EventSnapshot eventSnapshot : deferred) {
+ decorate(eventSnapshot, frameProcessor);
+ pushService.pushSnapshot(eventSnapshot);
+ }
+ }
+
+ public void decorate(final EventSnapshot eventSnapshot, final FrameProcessor frameProcessor) {
+ final long nanos = Utils.currentTimeNanos()[1];
+ final long durationNs = nanos - this.ts;
+ if (this.throwable != null) {
+ final List variableIds = frameProcessor.processVars(Collections.singletonMap("thrown", this.throwable));
+ final Map watchLookup = frameProcessor.closeLookup();
+ eventSnapshot.addWatchResult(new WatchResult("thrown", variableIds.get(0), WatchResult.WATCH));
+ eventSnapshot.mergeVariables(watchLookup);
+ }
+
+ if (this.isSet) {
+ final List variableIds = frameProcessor.processVars(Collections.singletonMap("return", this.value));
+ final Map watchLookup = frameProcessor.closeLookup();
+ eventSnapshot.addWatchResult(new WatchResult("return", variableIds.get(0), WatchResult.WATCH));
+ eventSnapshot.mergeVariables(watchLookup);
+ }
+
+ final List variableIds = frameProcessor.processVars(Collections.singletonMap("runtime", durationNs));
+ final Map watchLookup = frameProcessor.closeLookup();
+ eventSnapshot.addWatchResult(new WatchResult("runtime", variableIds.get(0), WatchResult.WATCH));
+ eventSnapshot.mergeVariables(watchLookup);
+ }
+ }
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameCollector.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameCollector.java
index 1165b56..924fdf0 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameCollector.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameCollector.java
@@ -78,6 +78,11 @@ public class FrameCollector extends VariableProcessor {
*/
private final List jspPackages;
+ /**
+ * The name of the method we are wrapping, or {@code null} if not a method wrapped collection.
+ */
+ private final String methodName;
+
/**
* Create a frame collector to collect the frame data.
*
@@ -85,18 +90,21 @@ public class FrameCollector extends VariableProcessor {
* @param evaluator the evaluator to use for this callback
* @param variables the variables captured by the callback
* @param stack the stack captured by the callback
+ * @param methodName the name of the method we are wrapping, or {@code null} if not a method wrapped collection
*/
public FrameCollector(
final Settings settings,
final IEvaluator evaluator,
final Map variables,
- final StackTraceElement[] stack) {
+ final StackTraceElement[] stack,
+ final String methodName) {
this.settings = settings;
this.evaluator = evaluator;
this.variables = variables;
this.stack = stack;
this.jspSuffix = settings.getSettingAs(ISettings.JSP_SUFFIX, String.class);
this.jspPackages = settings.getAsList(ISettings.JSP_PACKAGES);
+ this.methodName = methodName;
}
/**
@@ -105,6 +113,21 @@ public FrameCollector(
* @return the result of the process {@link IFrameResult}
*/
protected IFrameResult processFrame() {
+ // if all tracepoints are no collect then skip collection
+ if (this.frameConfig.isNoCollect()) {
+ return new IFrameResult() {
+ @Override
+ public Collection frames() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Map variables() {
+ return Collections.emptyMap();
+ }
+ };
+ }
+
final ArrayList frames = new ArrayList<>();
for (int i = 0; i < stack.length; i++) {
@@ -356,10 +379,9 @@ protected String getMethodName(final StackTraceElement stackTraceElement,
*
* So if we cannot get a result from the {@link IEvaluator} then we return an error result.
*
- * @param watch the watch expression to evaluate
+ * @param watch the watch expression to evaluate
* @param source the source of the watch expression
* @return a {@link IExpressionResult}
- *
* @see WatchResult#LOG
* @see WatchResult#METRIC
* @see WatchResult#WATCH
@@ -460,6 +482,10 @@ protected Resource processAttributes(final TracePointConfig tracepoint) {
attributes.put("stack", tracepoint.getStackType());
attributes.put("frame", tracepoint.getFrameType());
+ if (this.methodName != null) {
+ attributes.put("method_name", this.methodName);
+ }
+
if (!tracepoint.getWatches().isEmpty()) {
attributes.put("has_watches", true);
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameConfig.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameConfig.java
index c3bc06d..c9e29a3 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameConfig.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameConfig.java
@@ -41,6 +41,7 @@ public class FrameConfig {
private int maxWatchVars = -1;
private int maxTpProcessTime = -1;
+ private boolean noCollect = true;
private boolean cfRaw = false;
/**
@@ -62,6 +63,11 @@ public void process(final TracePointConfig tracePointConfig) {
maxTpProcessTime = Math.max(tracePointConfig.getArg("MAX_TP_PROCESS_TIME", Integer.class, -1),
maxTpProcessTime);
+ // if any tracepoint is set to collect then we need to collect
+ if (tracePointConfig.getArg(TracePointConfig.SNAPSHOT, String.class, TracePointConfig.COLLECT).equals(TracePointConfig.COLLECT)) {
+ noCollect = false;
+ }
+
final String frameType = tracePointConfig.getFrameType();
if (frameType != null) {
if (this.frameType == null) {
@@ -157,12 +163,15 @@ public int maxCollectionSize() {
}
/**
- * Is this frame set to cf raw.
- * cf raw allows the collection of the java variables instead of the mapped cf variables.
+ * Is this frame set to cf raw. cf raw allows the collection of the java variables instead of the mapped cf variables.
*
* @return {@code true} if we want to collect the raw cf variables.
*/
public boolean isCfRaw() {
return this.cfRaw;
}
+
+ public boolean isNoCollect() {
+ return noCollect;
+ }
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameProcessor.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameProcessor.java
index ec95f07..1f7f063 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameProcessor.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/handler/FrameProcessor.java
@@ -73,13 +73,15 @@ public class FrameProcessor extends FrameCollector implements ISnapshotContext {
* @param tracePointConfigs the tracepoints that are part of this Callback
* @param lineStart the Tuple of the time this Callback started
* @param stack the stack trace to use
+ * @param methodName the name of the method we are wrapping, or {@code null} if not a method wrapped collection
*/
public FrameProcessor(final Settings settings,
final IEvaluator evaluator,
final Map variables,
final Collection tracePointConfigs,
- final long[] lineStart, final StackTraceElement[] stack) {
- super(settings, evaluator, variables, stack);
+ final long[] lineStart, final StackTraceElement[] stack,
+ final String methodName) {
+ super(settings, evaluator, variables, stack, methodName);
this.tracePointConfigs = tracePointConfigs;
this.lineStart = lineStart;
}
@@ -137,6 +139,9 @@ public Collection collect() {
final IFrameResult processedFrame = processFrame();
for (final TracePointConfig tracepoint : filteredTracepoints) {
+ final boolean doCollect = TracePointConfig.COLLECT.equals(
+ tracepoint.getArg(TracePointConfig.SNAPSHOT, String.class, TracePointConfig.COLLECT));
+
try {
final EventSnapshot snapshot = new EventSnapshot(tracepoint,
this.lineStart[1],
@@ -144,38 +149,54 @@ public Collection collect() {
processedFrame.frames(),
processedFrame.variables());
- for (String watch : tracepoint.getWatches()) {
- final FrameCollector.IExpressionResult result = evaluateWatchExpression(watch, WatchResult.WATCH);
- snapshot.addWatchResult(result.result());
- snapshot.mergeVariables(result.variables());
+ // do not process watches if we are not a collecting tracepoint
+ if (doCollect) {
+ for (String watch : tracepoint.getWatches()) {
+ final FrameCollector.IExpressionResult result = evaluateWatchExpression(watch, WatchResult.WATCH);
+ snapshot.addWatchResult(result.result());
+ snapshot.mergeVariables(result.variables());
+ }
}
+ // always process log message
final String logMsg = tracepoint.getArg(TracePointConfig.LOG_MSG, String.class, null);
if (logMsg != null) {
final ILogProcessResult result = this.processLogMsg(tracepoint, logMsg);
- snapshot.setLogMsg(result.processedLog());
- for (WatchResult watchResult : result.result()) {
- snapshot.addWatchResult(watchResult);
+ // only collect data if we are a collection tracepoint
+ if (doCollect) {
+ snapshot.setLogMsg(result.processedLog());
+ for (WatchResult watchResult : result.result()) {
+ snapshot.addWatchResult(watchResult);
+ }
+ snapshot.mergeVariables(result.variables());
}
- snapshot.mergeVariables(result.variables());
this.logTracepoint(result.processedLog(), tracepoint.getId(), snapshot.getID());
}
+ // always process metrics
final Collection metricDefinitions = tracepoint.getMetricDefinitions();
if (!metricDefinitions.isEmpty()) {
for (MetricDefinition metricDefinition : metricDefinitions) {
final List watchResults = processMetric(tracepoint, metricDefinition);
- for (FrameCollector.IExpressionResult watchResult : watchResults) {
- snapshot.addWatchResult(watchResult.result());
- snapshot.mergeVariables(watchResult.variables());
+ // only collect data if we are a collection tracepoint
+ if (doCollect) {
+ for (FrameCollector.IExpressionResult watchResult : watchResults) {
+ snapshot.addWatchResult(watchResult.result());
+ snapshot.mergeVariables(watchResult.variables());
+ }
}
}
}
+ // if we are not a collection tracepoint, then record fire and continue. Do not collect.
+ if (!doCollect) {
+ tracepoint.fired(this.lineStart[0]);
+ continue;
+ }
final Resource attributes = processAttributes(tracepoint);
snapshot.mergeAttributes(attributes);
-
snapshots.add(snapshot);
+
tracepoint.fired(this.lineStart[0]);
} catch (Exception e) {
throw new RuntimeException(e);
@@ -276,6 +297,14 @@ public IReflection reflectionService() {
return Reflection.getInstance();
}
+ public Collection getFilteredTracepoints() {
+ return filteredTracepoints;
+ }
+
+ public long[] getLineStart() {
+ return lineStart;
+ }
+
/**
* This defines a functional interface to allow for creating difference processors in the Callback.
*/
@@ -290,12 +319,13 @@ public interface IFactory {
* @param tracePointConfigs the tracepoints that are part of this Callback
* @param lineStart the Tuple of the time this Callback started
* @param stack the stack trace to use
+ * @param methodName the name of the method we are wrapping, or {@code null} if not a method wrapped collection
* @return the new {@link FrameProcessor}
* @see FrameProcessor
* @see com.intergral.deep.agent.tracepoint.cf.CFFrameProcessor
*/
- FrameProcessor provide(Settings settings, IEvaluator evaluator, Map variables,
- Collection tracePointConfigs, long[] lineStart,
- StackTraceElement[] stack);
+ FrameProcessor provide(final Settings settings, final IEvaluator evaluator, final Map variables,
+ final Collection tracePointConfigs, final long[] lineStart,
+ final StackTraceElement[] stack, final String methodName);
}
}
diff --git a/agent/src/main/java/com/intergral/deep/agent/tracepoint/inst/asm/Visitor.java b/agent/src/main/java/com/intergral/deep/agent/tracepoint/inst/asm/Visitor.java
index 3b55320..0a51715 100644
--- a/agent/src/main/java/com/intergral/deep/agent/tracepoint/inst/asm/Visitor.java
+++ b/agent/src/main/java/com/intergral/deep/agent/tracepoint/inst/asm/Visitor.java
@@ -32,9 +32,7 @@
import static org.objectweb.asm.Opcodes.FSTORE;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.GOTO;
-import static org.objectweb.asm.Opcodes.IFNULL;
import static org.objectweb.asm.Opcodes.ILOAD;
-import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
@@ -47,7 +45,9 @@
import static org.objectweb.asm.Opcodes.RETURN;
import com.google.common.collect.Sets;
+import com.intergral.deep.agent.tracepoint.inst.asm.Visitor.MappedMethod.MappedVar;
import com.intergral.deep.agent.types.TracePointConfig;
+import com.intergral.deep.agent.types.TracePointConfig.EStage;
import java.com.intergral.deep.ProxyCallback;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -55,11 +55,12 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -351,11 +352,11 @@ static int replacedMethodAcc(final boolean isStatic) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
- String[] exceptions) {
+ String[] exps) {
// if the method is abstract then we cannot inject tracepoints - so skip it
if (TransformerUtils.isAbstract(access)) {
- return super.visitMethod(access, name, desc, signature, exceptions);
+ return super.visitMethod(access, name, desc, signature, exps);
}
LOGGER.debug("visitMethod {} {}", classname, name);
@@ -363,27 +364,45 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
// if we have a method tracepoint for this method name then rename the method
final String methodName;
final int methodAccess;
+ // we use atomic as we have to update this later
+ final AtomicBoolean isMapped = new AtomicBoolean(false);
final List tracePointConfigs = this.methodBPs.get(name);
+ final MappedMethod mappedMethod = new MappedMethod(access, name, desc, signature, exps, -1);
// if we have a method tracepoint for this method name then rename the method.
if (tracePointConfigs != null) {
// rename the method and make it private synthetic $deep$..
methodName = determineNewMethodName(name);
methodAccess = replacedMethodAcc(TransformerUtils.isStatic(access));
// record the change so we can fix them up later
- this.mappedMethods.add(new MappedMethod(access, name, desc, signature, exceptions));
+ this.mappedMethods.add(mappedMethod);
+ isMapped.set(true);
} else {
methodName = name;
methodAccess = access;
}
- final MethodVisitor methodVisitor = super.visitMethod(methodAccess, methodName, desc, signature,
- exceptions);
- final JSRInlinerAdapter jsrInlinerAdapter = new JSRInlinerAdapter(methodVisitor, methodAccess, methodName,
- desc, signature,
- exceptions);
-
// MethodNode used to handle the maxes for us to make it simpler
- return new MethodNode(ASM7, methodAccess, methodName, desc, signature, exceptions) {
+ return new MethodNode(ASM7, methodAccess, methodName, desc, signature, exps) {
+
+ Label startLabel;
+
+ @Override
+ public void visitLocalVariable(final String name, final String descriptor, final String signature, final Label start, final Label end,
+ final int index) {
+ if (startLabel != null && startLabel.equals(start)) {
+ mappedMethod.acceptVariable(name, descriptor, index);
+ }
+ super.visitLocalVariable(name, descriptor, signature, start, end, index);
+ }
+
+ @Override
+ public void visitLineNumber(final int line, final Label start) {
+ mappedMethod.acceptLine(line);
+ if (startLabel == null) {
+ startLabel = start;
+ }
+ super.visitLineNumber(line, start);
+ }
@Override
public void visitEnd() {
@@ -398,6 +417,7 @@ public void visitEnd() {
// the start label for the line to wrap
LabelNode start = null;
+ LineNumberNode ln = null;
// we need to handle constructors a little differently
final boolean isConstructor = name.equals("");
@@ -479,21 +499,31 @@ public void visitEnd() {
}
hook.add(new LabelNode(endOfTry));
- // set = new HashSet()
- hook.add(new TypeInsnNode(NEW, Type.getInternalName(HashSet.class)));
+ // list = new ArrayList()
+ hook.add(new TypeInsnNode(NEW, Type.getInternalName(ArrayList.class)));
hook.add(new InsnNode(DUP));
hook.add(
- new MethodInsnNode(INVOKESPECIAL, Type.getInternalName(HashSet.class), "",
+ new MethodInsnNode(INVOKESPECIAL, Type.getInternalName(ArrayList.class), "",
"()V", false));
for (final TracePointConfig bp : iBreakpoints) {
- // set.add(bp.getId());
+ if (!bp.acceptStage(EStage.LINE_END)) {
+ continue;
+ }
+ // list.add(bp.getId());
hook.add(new InsnNode(DUP)); // we need a ptr to our map
hook.add(new LdcInsnNode(bp.getId())); // bp id
- hook.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(HashSet.class), "add",
+ hook.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(ArrayList.class), "add",
"(Ljava/lang/Object;)Z"));
hook.add(new InsnNode(POP)); // dont care about return
}
+
+ hook.add(new LdcInsnNode(filename));
+ if (ln != null) {
+ hook.add(new LdcInsnNode(ln.line));
+ } else {
+ hook.add(new LdcInsnNode(-1));
+ }
// if we are a next line then we need to remove the start line label from the seen labels so
// the variable capture in the finally does not capture variables defined on the line we are wrapping
if (isNextLine) {
@@ -510,7 +540,9 @@ public void visitEnd() {
Type.getInternalName(CALLBACK_CLASS),
"callBackFinally",
Type.getMethodDescriptor(Type.VOID_TYPE,
- Type.getType(Set.class),
+ Type.getType(List.class),
+ Type.getType(String.class),
+ Type.getType(int.class),
Type.getType(Map.class)),
false));
if (isReturnNode) {
@@ -590,20 +622,30 @@ public void visitEnd() {
hook.add(new LabelNode(endCatch));
// set = new HashSet()
- hook.add(new TypeInsnNode(NEW, Type.getInternalName(HashSet.class)));
+ hook.add(new TypeInsnNode(NEW, Type.getInternalName(ArrayList.class)));
hook.add(new InsnNode(DUP));
hook.add(
- new MethodInsnNode(INVOKESPECIAL, Type.getInternalName(HashSet.class), "",
+ new MethodInsnNode(INVOKESPECIAL, Type.getInternalName(ArrayList.class), "",
"()V", false));
for (final TracePointConfig bp : iBreakpoints) {
+ if (!bp.acceptStage(EStage.LINE_END)) {
+ continue;
+ }
// set.add(bp.getId());
hook.add(new InsnNode(DUP)); // we need a ptr to our map
hook.add(new LdcInsnNode(bp.getId())); // bp id
- hook.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(HashSet.class), "add",
+ hook.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(ArrayList.class), "add",
"(Ljava/lang/Object;)Z"));
hook.add(new InsnNode(POP)); // don't care about return
}
+
+ hook.add(new LdcInsnNode(filename));
+ if (ln != null) {
+ hook.add(new LdcInsnNode(ln.line));
+ } else {
+ hook.add(new LdcInsnNode(-1));
+ }
// if we are a next line then we need to remove the start line label from the seen labels so
// the variable capture in the finally does not capture variables defined on the line we are wrapping
if (isNextLine) {
@@ -619,7 +661,9 @@ public void visitEnd() {
Type.getInternalName(CALLBACK_CLASS),
"callBackFinally",
Type.getMethodDescriptor(Type.VOID_TYPE,
- Type.getType(Set.class),
+ Type.getType(List.class),
+ Type.getType(String.class),
+ Type.getType(int.class),
Type.getType(Map.class)),
false));
// load exception back
@@ -664,7 +708,7 @@ public void visitEnd() {
if (node.getType() == AbstractInsnNode.LINE) {
//noinspection DataFlowIssue
- LineNumberNode ln = (LineNumberNode) node;
+ ln = (LineNumberNode) node;
// if we are a constructor and have not called super yet - the cache the line for later
if (isConstructor && !hasCalledSuper) {
constructorLine = ln;
@@ -679,10 +723,33 @@ public void visitEnd() {
// but we might need to use them in forth coming instructions for line end etc
iBreakpoints.clear();
iBreakpoints.addAll(thisLineBps);
+ // if we are not already mapped then check if we need to map it
+ if (!isMapped.get()) {
+ // do we need to wrap the method later
+ final List collect = thisLineBps.stream().filter(
+ tracePointConfig -> TracePointConfig.METHOD.equals(tracePointConfig.getArg(TracePointConfig.SPAN, String.class, null)))
+ .collect(Collectors.toList());
+ if (!collect.isEmpty()) {
+ // we have a tracepoint on this line that is set to 'method' span type. So add the method to the mapped methods, then rename this method.
+ Visitor.this.mappedMethods.add(mappedMethod);
+ // track the mapped tracepoints, so we can pass them back later
+ final List mappedTps = Visitor.this.methodBPs.computeIfAbsent(this.name,
+ k -> new ArrayList<>());
+ mappedTps.addAll(collect);
+
+ // rename the method and make it private synthetic $deep$..
+ this.name = determineNewMethodName(name);
+ this.access = replacedMethodAcc(TransformerUtils.isStatic(access));
+
+ // set is mapped so we do not check again
+ isMapped.set(true);
+ }
+ }
}
// check if we have any Bps for the constructor
if (constructorLine != null) {
+ // todo how do we want to deal with method entry in constructors
// add any bps for the constructor call into the list to be processed
final List constructorBps = lineNos.remove(
(long) constructorLine.line);
@@ -720,6 +787,13 @@ public void visitEnd() {
}
}
+ // now apply the modified instructions using the original class writer
+ final MethodVisitor methodVisitor = Visitor.this.cv.visitMethod(this.access, this.name, desc, signature,
+ exps);
+ final JSRInlinerAdapter jsrInlinerAdapter = new JSRInlinerAdapter(methodVisitor, this.access, this.name,
+ desc, signature,
+ exps);
+
this.accept(jsrInlinerAdapter);
super.visitEnd();
@@ -751,6 +825,9 @@ private InsnList getAbstractInsnNodes(final Set