Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ dependencies {
testImplementation("org.openjdk.jmh:jmh-core:1.37")
}

test {
if (JavaVersion.current().isJava9Compatible()) {
jvmArgs "--add-opens=java.base/java.lang=ALL-UNNAMED"
}
}

task mainJar(type: Jar) {
from configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
with jar
Expand Down
24 changes: 16 additions & 8 deletions src/main/java/com/intellij/rt/debugger/agent/CaptureStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ private static Deque<CapturedStack> getStacksForCurrentThread() {
}
}

static CapturedStack getCurrentCapturedStack() {
return getStacksForCurrentThread().peekLast();
}

@SuppressWarnings("StaticNonFinalField")
public static boolean DEBUG; // set from debugger
private static boolean ENABLED = true; // set from debugger
Expand Down Expand Up @@ -120,6 +124,11 @@ public void run() {
});
}

@SuppressWarnings("unused")
public static void captureThrowableBacktrace(Object backtrace) {
ThrowableInterner.captureBacktrace(backtrace);
}

@SuppressWarnings("unused")
public static void captureThrowable(final Throwable throwable) {
final ThreadLocalContext context = CURRENT_CONTEXT.get();
Expand Down Expand Up @@ -406,7 +415,7 @@ private StackData(List<StackTraceElement> stackTrace, CapturedStack previous) {
}
}

private static abstract class CapturedStack {
static abstract class CapturedStack {
abstract List<StackTraceElement> getStackTrace();

int getRecursionDepth() {
Expand Down Expand Up @@ -488,13 +497,12 @@ StackData collectStacks(List<StackTraceElement> stackTrace) {
}
}

/**
* Returns the captured stack trace of the current thread.
*/
static List<StackTraceElement> getCurrentCapturedStack(int limit) {
CapturedStack stack = getStacksForCurrentThread().peekLast();
if (stack == null) return null;
return getStackTrace(stack, limit);
static List<StackTraceElement> getThrowableStackTrace(Throwable throwable) {
return trimInitAgentFrames(Arrays.asList(throwable.getStackTrace()));
}

static List<StackTraceElement> getCapturedStackTrace(CapturedStack capturedStack, int limit) {
return getStackTrace(capturedStack, limit);
}

// to be run from the debugger
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.intellij.rt.debugger.agent;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;

final class CapturedStackDeduplicator {
static final class StackDictionary {
final List<List<StackTraceElement>> stacks;
final int[] throwableStackIds;
final int[] capturedStackIds;

private StackDictionary(List<List<StackTraceElement>> stacks, int[] throwableStackIds, int[] capturedStackIds) {
this.stacks = stacks;
this.throwableStackIds = throwableStackIds;
this.capturedStackIds = capturedStackIds;
}
}

private static final class StackRef {
final int id;
final List<StackTraceElement> stack;

private StackRef(int id, List<StackTraceElement> stack) {
this.id = id;
this.stack = stack;
}
}

private final List<LogCaptureStorage.Event> events;
private final int maxStackDepth;
private final ArrayList<List<StackTraceElement>> stacks;
private final int[] throwableStackIds;
private final int[] capturedStackIds;
private final IdentityHashMap<Throwable, StackRef> throwableStacks;
private final IdentityHashMap<CaptureStorage.CapturedStack, CapturedStackInfo> capturedStacks;

private CapturedStackDeduplicator(List<LogCaptureStorage.Event> events, int maxStackDepth) {
this.events = events;
this.maxStackDepth = maxStackDepth;
int eventCount = events.size();
stacks = new ArrayList<>();
throwableStackIds = new int[eventCount];
capturedStackIds = new int[eventCount];
throwableStacks = new IdentityHashMap<>();
capturedStacks = new IdentityHashMap<>();
}

static StackDictionary createStackDictionary(List<LogCaptureStorage.Event> events, int maxStackDepth) {
CapturedStackDeduplicator deduplicator = new CapturedStackDeduplicator(events, maxStackDepth);
deduplicator.collectThrowableStacksAndCapturedStackDepths();
deduplicator.collectCapturedStacks();
return new StackDictionary(deduplicator.stacks, deduplicator.throwableStackIds, deduplicator.capturedStackIds);
}

private void collectThrowableStacksAndCapturedStackDepths() {
for (int i = 0; i < events.size(); i++) {
LogCaptureStorage.Event event = events.get(i);
StackRef throwableStackRef = getThrowableStackRef(event.throwable);
throwableStackIds[i] = throwableStackRef.id;

if (event.stack == null) {
continue;
}

CapturedStackInfo capturedStackInfo = capturedStacks.get(event.stack);
if (capturedStackInfo == null) {
capturedStackInfo = new CapturedStackInfo(event.stack);
capturedStacks.put(event.stack, capturedStackInfo);
}
capturedStackInfo.requireDepth(maxStackDepth - throwableStackRef.stack.size());
}
}

private StackRef getThrowableStackRef(Throwable throwable) {
StackRef stackRef = throwableStacks.get(throwable);
if (stackRef != null) return stackRef;

stackRef = addStack(CaptureStorage.getThrowableStackTrace(throwable));
throwableStacks.put(throwable, stackRef);
return stackRef;
}

private void collectCapturedStacks() {
for (int i = 0; i < events.size(); i++) {
CaptureStorage.CapturedStack capturedStack = events.get(i).stack;
if (capturedStack == null) {
capturedStackIds[i] = -1;
continue;
}

CapturedStackInfo capturedStackInfo = capturedStacks.get(capturedStack);
if (capturedStackInfo.stackId == -1) {
capturedStackInfo.stackId = addStack(capturedStackInfo.getStackTrace()).id;
}
capturedStackIds[i] = capturedStackInfo.stackId;
}
}

private StackRef addStack(List<StackTraceElement> stack) {
StackRef stackRef = new StackRef(stacks.size(), stack);
stacks.add(stack);
return stackRef;
}

private static final class CapturedStackInfo {
private final CaptureStorage.CapturedStack capturedStack;
private int maxRequiredDepth;
private List<StackTraceElement> stackTrace;
private int stackId = -1;

private CapturedStackInfo(CaptureStorage.CapturedStack capturedStack) {
this.capturedStack = capturedStack;
}

private void requireDepth(int depth) {
if (maxRequiredDepth < depth) {
maxRequiredDepth = depth;
}
}

private List<StackTraceElement> getStackTrace() {
if (stackTrace == null) {
stackTrace = CaptureStorage.getCapturedStackTrace(capturedStack, maxRequiredDepth);
}
return stackTrace;
}
}
}
Loading
Loading