All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.versions.9.org.lwjgl.system.StackWalkUtil Maven / Gradle / Ivy

There is a newer version: 3.3.4
Show newest version
/*
 * Copyright LWJGL. All rights reserved.
 * License terms: https://www.lwjgl.org/license
 */
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");
    }

    private StackWalkUtil() {
    }

    static StackTraceElement[] stackWalkArray(Object[] a) {
        return Arrays.stream(((StackWalker.StackFrame[])a))
            .map(StackWalker.StackFrame::toStackTraceElement)
            .toArray(StackTraceElement[]::new);
    }

    static Object stackWalkGetMethod(Class after) {
        return STACKWALKER.walk(s -> {
            Iterator 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.getDeclaringClass() == b.getDeclaringClass() &&
               a.getMethodName().equals(methodName);
    }

    private static boolean isAutoCloseable(StackWalker.StackFrame element, StackWalker.StackFrame pushed) {
        // Java 9 try-with-resources: synthetic $closeResource
        if (isSameMethod(element, pushed, "$closeResource")) {
            return true;
        }

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

        return false;
    }

    @Nullable
    static Object stackWalkCheckPop(Class after, Object pushedObj) {
        StackWalker.StackFrame pushed = (StackWalker.StackFrame)pushedObj;

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

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

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

            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;
                }
            }

            return element;
        });
    }

    static Object[] stackWalkGetTrace() {
        return StackWalker.getInstance()
            .walk(s -> s
                .skip(2)
                .dropWhile(f -> f.getClassName().startsWith("org.lwjgl.system.Memory"))
                .toArray(StackWalker.StackFrame[]::new)
            );
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy