jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java
changeset 34372 ccdd9223ab7a
parent 34362 3396ae214e7d
child 36511 9d0388c6b336
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java	Tue Nov 24 15:05:58 2015 -0800
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import jdk.internal.misc.JavaLangInvokeAccess;
+import jdk.internal.misc.SharedSecrets;
+
+import static java.lang.StackWalker.Option.*;
+import java.lang.StackWalker.StackFrame;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+class StackFrameInfo implements StackFrame {
+    private final static JavaLangInvokeAccess jlInvokeAccess =
+        SharedSecrets.getJavaLangInvokeAccess();
+
+    // -XX:+MemberNameInStackFrame will initialize MemberName and all other fields;
+    // otherwise, VM will set the hidden fields (injected by the VM).
+    // -XX:+MemberNameInStackFrame is temporary to enable performance measurement
+    //
+    // Footprint improvement: MemberName::clazz and MemberName::name
+    // can replace StackFrameInfo::declaringClass and StackFrameInfo::methodName
+    // Currently VM sets StackFrameInfo::methodName instead of expanding MemberName::name
+
+    final StackWalker walker;
+    final Class<?> declaringClass;
+    final Object memberName;
+    final int bci;
+
+    // methodName, fileName, and lineNumber will be lazily set by the VM
+    // when first requested.
+    private String methodName;
+    private String fileName = null;     // default for unavailable filename
+    private int    lineNumber = -1;     // default for unavailable lineNumber
+
+    /*
+     * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser
+     * to use
+     */
+    StackFrameInfo(StackWalker walker) {
+        this.walker = walker;
+        this.declaringClass = null;
+        this.bci = -1;
+        this.memberName = jlInvokeAccess.newMemberName();
+    }
+
+    @Override
+    public String getClassName() {
+        return declaringClass.getName();
+    }
+
+    @Override
+    public Class<?> getDeclaringClass() {
+        walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
+        return declaringClass;
+    }
+
+    // Call the VM to set methodName, lineNumber, and fileName
+    private synchronized void ensureMethodInfoInitialized() {
+        if (methodName == null) {
+            setMethodInfo();
+        }
+    }
+
+    @Override
+    public String getMethodName() {
+        ensureMethodInfoInitialized();
+        return methodName;
+    }
+
+    @Override
+    public Optional<String> getFileName() {
+        ensureMethodInfoInitialized();
+        return fileName != null ? Optional.of(fileName) : Optional.empty();
+    }
+
+    @Override
+    public OptionalInt getLineNumber() {
+        ensureMethodInfoInitialized();
+        return lineNumber > 0 ? OptionalInt.of(lineNumber) : OptionalInt.empty();
+    }
+
+    @Override
+    public boolean isNativeMethod() {
+        ensureMethodInfoInitialized();
+        return lineNumber == -2;
+    }
+
+    @Override
+    public String toString() {
+        ensureMethodInfoInitialized();
+        // similar format as StackTraceElement::toString
+        if (isNativeMethod()) {
+            return getClassName() + "." + getMethodName() + "(Native Method)";
+        } else {
+            // avoid allocating Optional objects
+            return getClassName() + "." + getMethodName() +
+                "(" + (fileName != null ? fileName : "Unknown Source") +
+                      (lineNumber > 0 ? ":" + lineNumber : " bci:" + bci) + ")";
+        }
+    }
+
+    /**
+     * Lazily initialize method name, file name, line number
+     */
+    private native void setMethodInfo();
+
+    /**
+     * Fill in source file name and line number of the given StackFrame array.
+     */
+    static native void fillInStackFrames(int startIndex,
+                                         Object[] stackframes,
+                                         int fromIndex, int toIndex);
+}