[vmkit-commits] [PATCH] Add support for stack traces in OpenJDK

Will Dietz wdietz2 at illinois.edu
Wed Oct 26 19:20:46 PDT 2011


Inlined below.

While very similar, didn't see a particularly good way to share this
with the Classpath version of the same, as I recall.

~Will


>From 502715afce04e56d3c8c30156a1c670dfb62b17e Mon Sep 17 00:00:00 2001
From: Will Dietz <w at wdtz.org>
Date: Wed, 26 Oct 2011 21:11:48 -0500
Subject: [PATCH 2/2] Add support for stack traces in OpenJDK

---
 lib/J3/ClassLib/OpenJDK/ClasspathReflect.cpp |   51 ++++++++++-
 lib/J3/ClassLib/OpenJDK/ClasspathReflect.h   |   18 ++--
 lib/J3/ClassLib/OpenJDK/OpenJDK.inc          |  134 +++++++++++++++++++++++++-
 3 files changed, 190 insertions(+), 13 deletions(-)

diff --git a/lib/J3/ClassLib/OpenJDK/ClasspathReflect.cpp
b/lib/J3/ClassLib/OpenJDK/ClasspathReflect.cpp
index 31dd417..a4f9ab2 100644
--- a/lib/J3/ClassLib/OpenJDK/ClasspathReflect.cpp
+++ b/lib/J3/ClassLib/OpenJDK/ClasspathReflect.cpp
@@ -11,6 +11,10 @@
 #include "JavaClass.h"
 #include "JavaObject.h"
 #include "JavaThread.h"
+#include "Jnjvm.h"
+#include "JavaUpcalls.h"
+
+#include <map>

 namespace j3 {

@@ -21,11 +25,56 @@ JavaMethod*
JavaObjectConstructor::getInternalMethod(JavaObjectConstructor* self
   return &(cls->asClass()->virtualMethods[self->slot]);
 }

-
 JavaMethod* JavaObjectMethod::getInternalMethod(JavaObjectMethod* self) {
   llvm_gcroot(self, 0);
   UserCommonClass* cls = JavaObjectClass::getClass(self->declaringClass);
   return &(cls->asClass()->virtualMethods[self->slot]);
 }

+int JavaObjectThrowable::getStackTraceBase(JavaObjectThrowable * self) {
+  if (!self->backtrace) return 0;
+
+  Jnjvm* vm = JavaThread::get()->getJVM();
+
+  JavaObject * stack = self->backtrace;
+  llvm_gcroot(self, 0);
+  llvm_gcroot(stack, 0);
+  sint32 index = 2;;
+  while (index != JavaArray::getSize(stack)) {
+    mvm::FrameInfo* FI =
vm->IPToFrameInfo(ArrayPtr::getElement((ArrayPtr*)stack, index));
+    if (FI->Metadata == NULL) ++index;
+    else {
+      JavaMethod* meth = (JavaMethod*)FI->Metadata;
+      assert(meth && "Wrong stack trace");
+      if (meth->classDef->isAssignableFrom(vm->upcalls->newThrowable)) {
+        ++index;
+      } else return index;
+    }
+  }
+
+  assert(0 && "Invalid stack trace!");
+  return 0;
+}
+
+int JavaObjectThrowable::getStackTraceDepth(JavaObjectThrowable * self) {
+  if (!self->backtrace) return 0;
+
+  Jnjvm* vm = JavaThread::get()->getJVM();
+
+  JavaObject * stack = self->backtrace;
+  llvm_gcroot(self, 0);
+  llvm_gcroot(stack, 0);
+  sint32 index = getStackTraceBase(self);
+
+  sint32 size = 0;
+  sint32 cur = index;
+  while (cur < JavaArray::getSize(stack)) {
+    mvm::FrameInfo* FI =
vm->IPToFrameInfo(ArrayPtr::getElement((ArrayPtr*)stack, cur));
+    ++cur;
+    if (FI->Metadata != NULL) ++size;
+  }
+
+  return size;
+}
+
 }
diff --git a/lib/J3/ClassLib/OpenJDK/ClasspathReflect.h
b/lib/J3/ClassLib/OpenJDK/ClasspathReflect.h
index 101e726..d371fdc 100644
--- a/lib/J3/ClassLib/OpenJDK/ClasspathReflect.h
+++ b/lib/J3/ClassLib/OpenJDK/ClasspathReflect.h
@@ -157,18 +157,18 @@ public:
     llvm_gcroot(self, 0);
     llvm_gcroot(stackTrace, 0);

-    // TODO: Implement this right
-    assert(0 && "fillInStackTrace not implemented yet!");
-
-    // stackTrace = internalFillInStackTrace(self);
-    // mvm::Collector::objectReferenceWriteBarrier(
-    //     (gc*)self, (gc**)&(self->vmState), (gc*)stackTrace);
+    stackTrace = internalFillInStackTrace(self);
+    mvm::Collector::objectReferenceWriteBarrier(
+        (gc*)self, (gc**)&(self->backtrace), (gc*)stackTrace);

-    // mvm::Collector::objectReferenceWriteBarrier(
-    //     (gc*)self, (gc**)&(self->cause), (gc*)self);
+    mvm::Collector::objectReferenceWriteBarrier(
+        (gc*)self, (gc**)&(self->cause), (gc*)self);

-    // self->stackTrace = NULL;
+    self->stackTrace = NULL;
   }
+
+  static int getStackTraceDepth(JavaObjectThrowable * self);
+  static int getStackTraceBase(JavaObjectThrowable * self);
 };

 class JavaObjectReference : public JavaObject {
diff --git a/lib/J3/ClassLib/OpenJDK/OpenJDK.inc
b/lib/J3/ClassLib/OpenJDK/OpenJDK.inc
index 8ff8035..cbdd3d9 100644
--- a/lib/J3/ClassLib/OpenJDK/OpenJDK.inc
+++ b/lib/J3/ClassLib/OpenJDK/OpenJDK.inc
@@ -17,6 +17,77 @@
 #define NYI() \
   do{ assert(0 && "Not yet implemented!"); abort(); } while(0)

+JavaObject* internalFillInStackTrace(JavaObject* throwable) {
+
+  ArrayPtr* result = 0;
+  llvm_gcroot(throwable, 0);
+  llvm_gcroot(result, 0);
+
+  JavaThread* th = JavaThread::get();
+  Jnjvm* vm = th->getJVM();
+  assert(th);
+  assert(vm);
+
+  uint32 length = th->getFrameContextLength();
+
+  if (sizeof(void*) == 4) {
+    ClassArray* cl = vm->upcalls->ArrayOfInt;
+    result = (ArrayPtr*) cl->doNew(length, vm);
+  } else {
+    ClassArray* cl = vm->upcalls->ArrayOfLong;
+    result = (ArrayPtr*) cl->doNew(length, vm);
+  }
+
+  // Don't call th->getFrameContext because it is not GC-safe.
+  mvm::StackWalker Walker(th);
+  uint32_t i = 0;
+
+  while (intptr_t ip = *Walker) {
+    ArrayPtr::setElement(result, ip, i);
+    ++i;
+    ++Walker;
+  }
+
+  return result;
+}
+
+JavaObject* consStackElement(mvm::FrameInfo* FI, intptr_t ip) {
+
+  JavaString* methodName = 0;
+  JavaString* className = 0;
+  JavaString* sourceName = 0;
+  JavaObject* res = 0;
+  llvm_gcroot(methodName, 0);
+  llvm_gcroot(className, 0);
+  llvm_gcroot(sourceName, 0);
+  llvm_gcroot(res, 0);
+
+  Jnjvm* vm = JavaThread::get()->getJVM();
+  JavaMethod* meth = (JavaMethod*)FI->Metadata;
+  methodName = vm->internalUTF8ToStr(meth->name);
+  Class* cl = meth->classDef;
+  className = JavaString::internalToJava(cl->name, vm);
+
+  Attribut* sourceAtt = cl->lookupAttribut(Attribut::sourceFileAttribut);
+
+  // We don't have the bytes if the class was vmjc'ed.
+  if (sourceAtt && cl->getBytes()) {
+    Reader reader(sourceAtt, cl->bytes);
+    uint16 index = reader.readU2();
+    sourceName = vm->internalUTF8ToStr(cl->getConstantPool()->UTF8At(index));
+  }
+
+  uint16 lineNumber = meth->lookupLineNumber(FI);
+
+  UserClass* newS = vm->upcalls->newStackTraceElement;
+  res = newS->doNew(vm);
+  vm->upcalls->initStackTraceElement->invokeIntSpecial(vm, newS, res,
+                                                       &className,
+                                                       &methodName,
+                                                       &sourceName,
+                                                       lineNumber);
+  return res;
+}

 JNIEXPORT jint JNICALL
 JVM_GetInterfaceVersion(void) {
@@ -261,7 +332,17 @@ JVM_IsNaN(jdouble d) {
  */
 JNIEXPORT void JNICALL
 JVM_FillInStackTrace(JNIEnv *env, jobject throwable) {
-  NYI();
+  JavaObjectThrowable * T = 0;
+  llvm_gcroot(T, 0);
+
+  BEGIN_JNI_EXCEPTION
+
+  T = *(JavaObjectThrowable**)throwable;
+  JavaObjectThrowable::fillInStackTrace(T);
+
+  RETURN_VOID_FROM_JNI;
+
+  END_JNI_EXCEPTION
 }

 JNIEXPORT void JNICALL
@@ -271,12 +352,59 @@ JVM_PrintStackTrace(JNIEnv *env, jobject
throwable, jobject printable) {

 JNIEXPORT jint JNICALL
 JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable) {
-  NYI();
+  JavaObjectThrowable * T = 0;
+  llvm_gcroot(T, 0);
+
+  jint res = -1;
+
+  BEGIN_JNI_EXCEPTION
+
+  T = *(JavaObjectThrowable**)throwable;
+  res = JavaObjectThrowable::getStackTraceDepth(T);
+
+  RETURN_FROM_JNI(res);
+
+  END_JNI_EXCEPTION
+
+  return 0;
 }

 JNIEXPORT jobject JNICALL
 JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index) {
-  NYI();
+  JavaObjectThrowable * T = 0;
+  JavaObject * result = 0;
+  JavaObject * stack = 0;
+  llvm_gcroot(T, 0);
+  llvm_gcroot(result, 0);
+  llvm_gcroot(stack, 0);
+
+  BEGIN_JNI_EXCEPTION
+
+  T = *(JavaObjectThrowable**)throwable;
+  Jnjvm* vm = JavaThread::get()->getJVM();
+  stack = vm->upcalls->backtrace->getInstanceObjectField(T);
+  verifyNull(stack);
+
+  sint32 base = JavaObjectThrowable::getStackTraceBase(T);
+
+  sint32 cur = 0;
+  for (sint32 i = base; i < JavaArray::getSize(stack); ++i) {
+    intptr_t sp = ArrayPtr::getElement((ArrayPtr*)stack, i);
+    mvm::FrameInfo* FI = vm->IPToFrameInfo(sp);
+    if (FI->Metadata != NULL) {
+      if (cur == index) {
+        result = consStackElement(FI, sp);
+        break;
+      }
+      cur++;
+    }
+  }
+
+  RETURN_FROM_JNI((jobject)th->pushJNIRef(result));
+
+  END_JNI_EXCEPTION
+
+  return 0;
 }

 /*
-- 
1.7.5.1



More information about the vmkit-commits mailing list