1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.lang; 26 27 import jdk.internal.misc.JavaLangInvokeAccess; 28 import jdk.internal.misc.SharedSecrets; 29 30 import static java.lang.StackWalker.Option.*; 31 import java.lang.StackWalker.StackFrame; 32 import java.util.Optional; 33 import java.util.OptionalInt; 34 35 class StackFrameInfo implements StackFrame { 36 private final static JavaLangInvokeAccess jlInvokeAccess = 37 SharedSecrets.getJavaLangInvokeAccess(); 38 39 // -XX:+MemberNameInStackFrame will initialize MemberName and all other fields; 40 // otherwise, VM will set the hidden fields (injected by the VM). 41 // -XX:+MemberNameInStackFrame is temporary to enable performance measurement 42 // 43 // Footprint improvement: MemberName::clazz and MemberName::name 44 // can replace StackFrameInfo::declaringClass and StackFrameInfo::methodName 45 // Currently VM sets StackFrameInfo::methodName instead of expanding MemberName::name 46 47 final StackWalker walker; 48 final Class<?> declaringClass; 49 final Object memberName; 50 final int bci; 51 52 // methodName, fileName, and lineNumber will be lazily set by the VM 53 // when first requested. 54 private String methodName; 55 private String fileName = null; // default for unavailable filename 56 private int lineNumber = -1; // default for unavailable lineNumber 57 58 /* 59 * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser 60 * to use 61 */ 62 StackFrameInfo(StackWalker walker) { 63 this.walker = walker; 64 this.declaringClass = null; 65 this.bci = -1; 66 this.memberName = jlInvokeAccess.newMemberName(); 67 } 68 69 @Override 70 public String getClassName() { 71 return declaringClass.getName(); 72 } 73 74 @Override 75 public Class<?> getDeclaringClass() { 76 walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE); 77 return declaringClass; 78 } 79 80 // Call the VM to set methodName, lineNumber, and fileName 81 private synchronized void ensureMethodInfoInitialized() { 82 if (methodName == null) { 83 setMethodInfo(); 84 } 85 } 86 87 @Override 88 public String getMethodName() { 89 ensureMethodInfoInitialized(); 90 return methodName; 91 } 92 93 @Override 94 public Optional<String> getFileName() { 95 ensureMethodInfoInitialized(); 96 return fileName != null ? Optional.of(fileName) : Optional.empty(); 97 } 98 99 @Override 100 public OptionalInt getLineNumber() { 101 ensureMethodInfoInitialized(); 102 return lineNumber != -1 ? OptionalInt.of(lineNumber) : OptionalInt.empty(); 103 } 104 105 @Override 106 public boolean isNativeMethod() { 107 ensureMethodInfoInitialized(); 108 return lineNumber == -2; 109 } 110 111 @Override 112 public String toString() { 113 ensureMethodInfoInitialized(); 114 // similar format as StackTraceElement::toString 115 if (isNativeMethod()) { 116 return getClassName() + "." + getMethodName() + "(Native Method)"; 117 } else { 118 String sep = getLineNumber().isPresent() ? ":" : " bci:"; 119 return getClassName() + "." + getMethodName() + 120 "(" + getFileName().orElse("Unknown Source") + sep + 121 getLineNumber().orElse(bci) + ")"; 122 } 123 } 124 125 /** 126 * Lazily initialize method name, file name, line number 127 */ 128 private native void setMethodInfo(); 129 130 /** 131 * Fill in source file name and line number of the given StackFrame array. 132 */ 133 static native void fillInStackFrames(int startIndex, 134 Object[] stackframes, 135 int fromIndex, int toIndex); 136 }