8153123: Streamline StackWalker code
Reviewed-by: coleenp, dfuchs, mchung, redestad
This commit is contained in:
parent
fd6a72271b
commit
74f12569ec
jdk
make/mapfiles/libjava
src/java.base/share
classes
java/lang
jdk/internal/misc
native
test/java/lang/StackWalker
@ -139,8 +139,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_Double_doubleToRawLongBits;
|
||||
Java_java_lang_Float_intBitsToFloat;
|
||||
Java_java_lang_Float_floatToRawIntBits;
|
||||
Java_java_lang_StackFrameInfo_fillInStackFrames;
|
||||
Java_java_lang_StackFrameInfo_setMethodInfo;
|
||||
Java_java_lang_StackFrameInfo_toStackTraceElement0;
|
||||
Java_java_lang_StackStreamFactory_checkStackWalkModes;
|
||||
Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk;
|
||||
Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames;
|
||||
|
@ -37,24 +37,14 @@ 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
|
||||
// Footprint improvement: MemberName::clazz can replace
|
||||
// StackFrameInfo::declaringClass.
|
||||
|
||||
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
|
||||
final short bci;
|
||||
private volatile StackTraceElement ste;
|
||||
|
||||
/*
|
||||
* Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser
|
||||
@ -78,77 +68,53 @@ class StackFrameInfo implements StackFrame {
|
||||
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;
|
||||
return jlInvokeAccess.getName(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getFileName() {
|
||||
ensureMethodInfoInitialized();
|
||||
return fileName != null ? Optional.of(fileName) : Optional.empty();
|
||||
public final Optional<String> getFileName() {
|
||||
StackTraceElement ste = toStackTraceElement();
|
||||
return ste.getFileName() != null ? Optional.of(ste.getFileName()) : Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getLineNumber() {
|
||||
ensureMethodInfoInitialized();
|
||||
return lineNumber > 0 ? OptionalInt.of(lineNumber) : OptionalInt.empty();
|
||||
public final OptionalInt getLineNumber() {
|
||||
StackTraceElement ste = toStackTraceElement();
|
||||
return ste.getLineNumber() > 0 ? OptionalInt.of(ste.getLineNumber()) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNativeMethod() {
|
||||
ensureMethodInfoInitialized();
|
||||
return lineNumber == -2;
|
||||
public final boolean isNativeMethod() {
|
||||
StackTraceElement ste = toStackTraceElement();
|
||||
return ste.isNativeMethod();
|
||||
}
|
||||
|
||||
@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) + ")";
|
||||
}
|
||||
StackTraceElement ste = toStackTraceElement();
|
||||
return ste.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily initialize method name, file name, line number
|
||||
* Fill in the fields of the given StackTraceElement
|
||||
*/
|
||||
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);
|
||||
private native void toStackTraceElement0(StackTraceElement ste);
|
||||
|
||||
@Override
|
||||
public StackTraceElement toStackTraceElement() {
|
||||
ensureMethodInfoInitialized();
|
||||
|
||||
Module module = declaringClass.getModule();
|
||||
String moduleName = module.isNamed() ? module.getName() : null;
|
||||
String moduleVersion = null;
|
||||
if (module.isNamed() && module.getDescriptor().version().isPresent()) {
|
||||
moduleVersion = module.getDescriptor().version().get().toString();
|
||||
StackTraceElement s = ste;
|
||||
if (s == null) {
|
||||
synchronized (this) {
|
||||
s = ste;
|
||||
if (s == null) {
|
||||
s = new StackTraceElement();
|
||||
toStackTraceElement0(s);
|
||||
ste = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new StackTraceElement(moduleName, moduleVersion,
|
||||
getClassName(), getMethodName(),
|
||||
fileName,
|
||||
lineNumber);
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1388,7 +1388,7 @@ class Thread implements Runnable {
|
||||
* This method is used only for debugging.
|
||||
*/
|
||||
public static void dumpStack() {
|
||||
StackStreamFactory.makeStackTrace().printStackTrace(System.err);
|
||||
new Exception("Stack trace").printStackTrace();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1610,8 +1610,7 @@ class Thread implements Runnable {
|
||||
}
|
||||
return stackTrace;
|
||||
} else {
|
||||
// Don't need JVM help for current thread
|
||||
return StackStreamFactory.makeStackTrace().getStackTraceElements();
|
||||
return (new Exception()).getStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,11 +785,7 @@ public class Throwable implements Serializable {
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
if (stackTrace != null ||
|
||||
backtrace != null /* Out of protocol state */ ) {
|
||||
if (backtrace == null && StackStreamFactory.useStackTrace(this)) {
|
||||
backtrace = StackStreamFactory.makeStackTrace(this);
|
||||
} else {
|
||||
fillInStackTrace(0);
|
||||
}
|
||||
fillInStackTrace(0);
|
||||
stackTrace = UNASSIGNED_STACK;
|
||||
}
|
||||
return this;
|
||||
@ -830,15 +826,11 @@ public class Throwable implements Serializable {
|
||||
// backtrace if this is the first call to this method
|
||||
if (stackTrace == UNASSIGNED_STACK ||
|
||||
(stackTrace == null && backtrace != null) /* Out of protocol state */) {
|
||||
if (backtrace instanceof StackStreamFactory.StackTrace) {
|
||||
stackTrace = ((StackStreamFactory.StackTrace)backtrace).getStackTraceElements();
|
||||
} else {
|
||||
stackTrace = new StackTraceElement[depth];
|
||||
for (int i = 0; i < depth; i++) {
|
||||
stackTrace[i] = new StackTraceElement();
|
||||
}
|
||||
getStackTraceElements(stackTrace);
|
||||
stackTrace = new StackTraceElement[depth];
|
||||
for (int i = 0; i < depth; i++) {
|
||||
stackTrace[i] = new StackTraceElement();
|
||||
}
|
||||
getStackTraceElements(stackTrace);
|
||||
} else if (stackTrace == null) {
|
||||
return UNASSIGNED_STACK;
|
||||
}
|
||||
|
@ -1132,6 +1132,10 @@ import java.util.Objects;
|
||||
public Object newMemberName() {
|
||||
return new MemberName();
|
||||
}
|
||||
public String getName(Object mname) {
|
||||
MemberName memberName = (MemberName)mname;
|
||||
return memberName.getName();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -30,4 +30,9 @@ public interface JavaLangInvokeAccess {
|
||||
* Create a new MemberName instance
|
||||
*/
|
||||
Object newMemberName();
|
||||
|
||||
/**
|
||||
* Returns the name for the given MemberName
|
||||
*/
|
||||
String getName(Object mname);
|
||||
}
|
||||
|
@ -179,7 +179,6 @@ JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements)
|
||||
*/
|
||||
enum {
|
||||
JVM_STACKWALK_FILL_CLASS_REFS_ONLY = 0x2,
|
||||
JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE = 0x10,
|
||||
JVM_STACKWALK_SHOW_HIDDEN_FRAMES = 0x20,
|
||||
JVM_STACKWALK_FILL_LIVE_STACK_FRAMES = 0x100
|
||||
};
|
||||
@ -187,23 +186,15 @@ enum {
|
||||
JNIEXPORT jobject JNICALL
|
||||
JVM_CallStackWalk(JNIEnv *env, jobject stackStream, jlong mode,
|
||||
jint skip_frames, jint frame_count, jint start_index,
|
||||
jobjectArray classes,
|
||||
jobjectArray frames);
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JVM_MoreStackWalk(JNIEnv *env, jobject stackStream, jlong mode, jlong anchor,
|
||||
jint frame_count, jint start_index,
|
||||
jobjectArray classes,
|
||||
jobjectArray frames);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_FillStackFrames(JNIEnv* env, jclass cls,
|
||||
jint start_index,
|
||||
jobjectArray stackFrames,
|
||||
jint from_index, jint toIndex);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_SetMethodInfo(JNIEnv* env, jobject frame);
|
||||
JVM_ToStackTraceElement(JNIEnv* env, jobject frame, jobject stackElement);
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetVmArguments(JNIEnv *env);
|
||||
|
@ -38,22 +38,10 @@
|
||||
|
||||
/*
|
||||
* Class: java_lang_StackFrameInfo
|
||||
* Method: fillInStackFrames
|
||||
* Signature: (I[Ljava/lang/Object;[Ljava/lang/Object;II)V
|
||||
* Method: toStackTraceElement0
|
||||
* Signature: (Ljava/lang/StackTraceElement;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_fillInStackFrames
|
||||
(JNIEnv *env, jclass dummy, jint startIndex,
|
||||
jobjectArray stackFrames, jint fromIndex, jint toIndex) {
|
||||
JVM_FillStackFrames(env, dummy, startIndex,
|
||||
stackFrames, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_lang_StackFrameInfo
|
||||
* Method: setMethodInfo
|
||||
* Signature: (Ljava/lang/Class;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_setMethodInfo
|
||||
(JNIEnv *env, jobject stackframeinfo) {
|
||||
JVM_SetMethodInfo(env, stackframeinfo);
|
||||
JNIEXPORT void JNICALL Java_java_lang_StackFrameInfo_toStackTraceElement0
|
||||
(JNIEnv *env, jobject stackframeinfo, jobject stacktraceinfo) {
|
||||
JVM_ToStackTraceElement(env, stackframeinfo, stacktraceinfo);
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes
|
||||
(JNIEnv *env, jclass dummy)
|
||||
{
|
||||
return JVM_STACKWALK_FILL_CLASS_REFS_ONLY == java_lang_StackStreamFactory_FILL_CLASS_REFS_ONLY &&
|
||||
JVM_STACKWALK_FILTER_FILL_IN_STACK_TRACE == java_lang_StackStreamFactory_FILTER_FILL_IN_STACKTRACE &&
|
||||
JVM_STACKWALK_SHOW_HIDDEN_FRAMES == java_lang_StackStreamFactory_SHOW_HIDDEN_FRAMES &&
|
||||
JVM_STACKWALK_FILL_LIVE_STACK_FRAMES == java_lang_StackStreamFactory_FILL_LIVE_STACK_FRAMES;
|
||||
}
|
||||
@ -53,26 +52,26 @@ JNIEXPORT jboolean JNICALL Java_java_lang_StackStreamFactory_checkStackWalkModes
|
||||
/*
|
||||
* Class: java_lang_StackStreamFactory_AbstractStackWalker
|
||||
* Method: callStackWalk
|
||||
* Signature: (JIII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)Ljava/lang/Object;
|
||||
* Signature: (JIII[Ljava/lang/Object;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk
|
||||
(JNIEnv *env, jobject stackstream, jlong mode, jint skipFrames, jint batchSize, jint startIndex,
|
||||
jobjectArray classes, jobjectArray frames)
|
||||
jobjectArray frames)
|
||||
{
|
||||
return JVM_CallStackWalk(env, stackstream, mode, skipFrames, batchSize,
|
||||
startIndex, classes, frames);
|
||||
startIndex, frames);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: java_lang_StackStreamFactory_AbstractStackWalker
|
||||
* Method: fetchStackFrames
|
||||
* Signature: (JJII[Ljava/lang/Class;[Ljava/lang/StackWalker/StackFrame;)I
|
||||
* Signature: (JJII[Ljava/lang/Object;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames
|
||||
(JNIEnv *env, jobject stackstream, jlong mode, jlong anchor,
|
||||
jint batchSize, jint startIndex,
|
||||
jobjectArray classes, jobjectArray frames)
|
||||
jobjectArray frames)
|
||||
{
|
||||
return JVM_MoreStackWalk(env, stackstream, mode, anchor, batchSize,
|
||||
startIndex, classes, frames);
|
||||
startIndex, frames);
|
||||
}
|
||||
|
@ -28,9 +28,6 @@
|
||||
* This test should also been run against jdk9 successfully except of
|
||||
* VM option MemberNameInStackFrame.
|
||||
* @run main/othervm DumpStackTest
|
||||
* @run main/othervm -Dstackwalk.newThrowable=false DumpStackTest
|
||||
* @run main/othervm -Dstackwalk.newThrowable=true -XX:-MemberNameInStackFrame DumpStackTest
|
||||
* @run main/othervm -Dstackwalk.newThrowable=true -XX:+MemberNameInStackFrame DumpStackTest
|
||||
*/
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
@ -25,8 +25,7 @@
|
||||
* @test
|
||||
* @bug 8140450
|
||||
* @summary Basic test for StackWalker.getCallerClass()
|
||||
* @run main/othervm -XX:-MemberNameInStackFrame GetCallerClassTest
|
||||
* @run main/othervm -XX:+MemberNameInStackFrame GetCallerClassTest
|
||||
* @run main/othervm GetCallerClassTest
|
||||
* @run main/othervm GetCallerClassTest sm
|
||||
*/
|
||||
|
||||
|
@ -44,10 +44,6 @@ import jdk.testlibrary.RandomFactory;
|
||||
* @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest
|
||||
* @run main/othervm StackWalkTest -random:50
|
||||
* @run main/othervm/java.security.policy=stackwalktest.policy StackWalkTest -random:50
|
||||
* @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50
|
||||
* @run main/othervm -XX:-MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50
|
||||
* @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=false StackWalkTest -random:50
|
||||
* @run main/othervm -XX:+MemberNameInStackFrame -Dstackwalk.newThrowable=true StackWalkTest -random:50
|
||||
* @author danielfuchs, bchristi
|
||||
* @key randomness
|
||||
*/
|
||||
|
@ -40,8 +40,7 @@ import static java.lang.StackWalker.Option.*;
|
||||
* @summary Verify stack trace information obtained with respect to StackWalker
|
||||
* options, when the stack contains lambdas, method handle invoke
|
||||
* virtual calls, and reflection.
|
||||
* @run main/othervm -XX:-MemberNameInStackFrame VerifyStackTrace
|
||||
* @run main/othervm -XX:+MemberNameInStackFrame VerifyStackTrace
|
||||
* @run main/othervm VerifyStackTrace
|
||||
* @run main/othervm/java.security.policy=stackwalk.policy VerifyStackTrace
|
||||
* @author danielfuchs
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user