Skip to content

Commit

Permalink
perf(core) optimize Java 9+ stack walking
Browse files Browse the repository at this point in the history
A few micro-optimizations and one major: avoid
StackFrame::getFileName() because it requires an expensive internal
conversion to StackTraceElement.
  • Loading branch information
Spasi committed Sep 21, 2022
1 parent 94aae06 commit b390cd1
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 32 deletions.
1 change: 1 addition & 0 deletions .idea/modules/lwjgl/lwjgl.core9.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
*/
package org.lwjgl.system;

import javax.annotation.*;
import java.util.*;

import static org.lwjgl.system.APIUtil.*;

/** Java 9 version of {@code {@link StackWalkUtil}}. */
final class StackWalkUtil {

private static final StackWalker STACKWALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

static {
apiLog("Java 9 stack walker enabled");
}
Expand All @@ -25,23 +28,27 @@ static StackTraceElement[] stackWalkArray(Object[] a) {
}

static Object stackWalkGetMethod(Class<?> after) {
return StackWalker.getInstance()
.walk(s -> s
.skip(2)
.filter(f -> !f.getClassName().startsWith(after.getName()))
.findFirst()
)
.orElseThrow(IllegalStateException::new);
return STACKWALKER.walk(s -> {
Iterator<StackWalker.StackFrame> iter = s.iterator();
iter.next(); // skip this method
iter.next(); // skip MemoryStack::pop

StackWalker.StackFrame frame;
do {
frame = iter.next();
} while (frame.getDeclaringClass() == after && iter.hasNext());

return frame;
});
}

private static boolean isSameMethod(StackWalker.StackFrame a, StackWalker.StackFrame b) {
return isSameMethod(a, b, b.getMethodName());
}

private static boolean isSameMethod(StackWalker.StackFrame a, StackWalker.StackFrame b, String methodName) {
return a.getMethodName().equals(methodName) &&
a.getClassName().equals(b.getClassName()) &&
Objects.equals(a.getFileName(), b.getFileName());
return a.getDeclaringClass() == b.getDeclaringClass() &&
a.getMethodName().equals(methodName);
}

private static boolean isAutoCloseable(StackWalker.StackFrame element, StackWalker.StackFrame pushed) {
Expand All @@ -51,42 +58,42 @@ private static boolean isAutoCloseable(StackWalker.StackFrame element, StackWalk
}

// Kotlin T.use: kotlin.AutoCloseable::closeFinally
if ("closeFinally".equals(element.getMethodName()) && "AutoCloseable.kt".equals(element.getFileName())) {
if ("kotlin.jdk7.AutoCloseableKt".equals(element.getClassName()) && "closeFinally".equals(element.getMethodName())) {
return true;
}

return false;
}

@Nullable
static Object stackWalkCheckPop(Class<?> after, Object pushedObj) {
return StackWalker.getInstance().walk(s -> {
Iterator<StackWalker.StackFrame> iter = s
.skip(2)
.dropWhile(f -> f.getClassName().startsWith(after.getName()))
.iterator();
StackWalker.StackFrame pushed = (StackWalker.StackFrame)pushedObj;

return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s -> {
Iterator<StackWalker.StackFrame> iter = s.iterator();
iter.next();
iter.next();

if (iter.hasNext()) {
StackWalker.StackFrame element = iter.next();
StackWalker.StackFrame element;
do {
element = iter.next();
} while (element.getDeclaringClass() == after && iter.hasNext());

if (isSameMethod(element, pushed)) {
return null;
}

StackWalker.StackFrame pushed = (StackWalker.StackFrame)pushedObj;
if (iter.hasNext() && isAutoCloseable(element, pushed)) {
// Some runtimes use a separate method to call AutoCloseable::close in try-with-resources blocks.
// That method suppresses any exceptions thrown by close if necessary.
// When that happens, the pop is 1 level deeper than expected.
element = iter.next();
if (isSameMethod(element, pushed)) {
return null;
}

if (isAutoCloseable(element, pushed) && iter.hasNext()) {
// Some runtimes use a separate method to call AutoCloseable::close in try-with-resources blocks.
// That method suppresses any exceptions thrown by close if necessary.
// When that happens, the pop is 1 level deeper than expected.
element = iter.next();
if (isSameMethod(pushed, element)) {
return null;
}
}

return element;
}

throw new IllegalStateException();
return element;
});
}

Expand Down

0 comments on commit b390cd1

Please sign in to comment.