mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
classloading bugfixes and stack trace work
This commit is contained in:
parent
60da97dfc8
commit
c34ee64988
@ -2,6 +2,26 @@ package java.lang;
|
|||||||
|
|
||||||
public class Throwable {
|
public class Throwable {
|
||||||
private String message;
|
private String message;
|
||||||
private Object trace;
|
private StackTraceElement[] trace;
|
||||||
private Throwable cause;
|
private Throwable cause;
|
||||||
|
|
||||||
|
public Throwable(String message, Throwable cause) {
|
||||||
|
this.message = message;
|
||||||
|
this.trace = trace(1);
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable(String message) {
|
||||||
|
this(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable(Throwable cause) {
|
||||||
|
this(null, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native StackTraceElement[] trace(int skipCount);
|
||||||
}
|
}
|
||||||
|
8
makefile
8
makefile
@ -122,10 +122,10 @@ fast-objects = \
|
|||||||
fast-executable = $(bld)/fast-vm
|
fast-executable = $(bld)/fast-vm
|
||||||
fast-cflags = $(fast) $(cflags)
|
fast-cflags = $(fast) $(cflags)
|
||||||
|
|
||||||
input = $(bld)/classes/Hello.class
|
input = $(bld)/classes/TestExceptions.class
|
||||||
input-depends = \
|
# input-depends = \
|
||||||
$(bld)/classes/java/lang/System.class \
|
# $(bld)/classes/java/lang/System.class \
|
||||||
$(jni-library)
|
# $(jni-library)
|
||||||
|
|
||||||
gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
|
gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:')
|
||||||
args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input))
|
args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input))
|
||||||
|
@ -674,6 +674,9 @@ class MemberIterator {
|
|||||||
|
|
||||||
offset_ += padding_;
|
offset_ += padding_;
|
||||||
|
|
||||||
|
// printf("size: %d; padding: %d; alignment: %d; offset: %d;\n",
|
||||||
|
// size_, padding_, alignment_, offset_);
|
||||||
|
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,8 +1274,6 @@ writeConstructorDeclarations(Output* out, Object* declarations)
|
|||||||
Object* o = car(p);
|
Object* o = car(p);
|
||||||
switch (o->type) {
|
switch (o->type) {
|
||||||
case Object::Type: {
|
case Object::Type: {
|
||||||
if (typeMemberCount(o) == 0) continue;
|
|
||||||
|
|
||||||
out->write("object make");
|
out->write("object make");
|
||||||
out->write(capitalize(typeName(o)));
|
out->write(capitalize(typeName(o)));
|
||||||
if (typeHideConstructor(o)) out->write("0");
|
if (typeHideConstructor(o)) out->write("0");
|
||||||
@ -1295,8 +1296,6 @@ writeConstructors(Output* out, Object* declarations)
|
|||||||
Object* o = car(p);
|
Object* o = car(p);
|
||||||
switch (o->type) {
|
switch (o->type) {
|
||||||
case Object::Type: {
|
case Object::Type: {
|
||||||
if (typeMemberCount(o) == 0) continue;
|
|
||||||
|
|
||||||
out->write("object\nmake");
|
out->write("object\nmake");
|
||||||
out->write(capitalize(typeName(o)));
|
out->write(capitalize(typeName(o)));
|
||||||
if (typeHideConstructor(o)) out->write("0");
|
if (typeHideConstructor(o)) out->write("0");
|
||||||
@ -1343,7 +1342,6 @@ writeEnums(Output* out, Object* declarations)
|
|||||||
Object* o = car(p);
|
Object* o = car(p);
|
||||||
switch (o->type) {
|
switch (o->type) {
|
||||||
case Object::Type: {
|
case Object::Type: {
|
||||||
if (typeMemberCount(o)) {
|
|
||||||
if (wrote) {
|
if (wrote) {
|
||||||
out->write(",\n");
|
out->write(",\n");
|
||||||
} else {
|
} else {
|
||||||
@ -1351,7 +1349,6 @@ writeEnums(Output* out, Object* declarations)
|
|||||||
}
|
}
|
||||||
out->write(capitalize(typeName(o)));
|
out->write(capitalize(typeName(o)));
|
||||||
out->write("Type");
|
out->write("Type");
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
@ -1387,7 +1384,7 @@ set(uint32_t* mask, unsigned index)
|
|||||||
unsigned
|
unsigned
|
||||||
typeFixedSize(Object* type)
|
typeFixedSize(Object* type)
|
||||||
{
|
{
|
||||||
unsigned length = 0;
|
unsigned length = sizeof(void*);
|
||||||
for (MemberIterator it(type); it.hasMore();) {
|
for (MemberIterator it(type); it.hasMore();) {
|
||||||
Object* m = it.next();
|
Object* m = it.next();
|
||||||
switch (m->type) {
|
switch (m->type) {
|
||||||
@ -1465,9 +1462,6 @@ typeObjectMask(Object* type)
|
|||||||
void
|
void
|
||||||
writeInitialization(Output* out, Object* type)
|
writeInitialization(Output* out, Object* type)
|
||||||
{
|
{
|
||||||
unsigned memberCount = ::memberCount(type);
|
|
||||||
if (memberCount == 0) return;
|
|
||||||
|
|
||||||
out->write("{\n");
|
out->write("{\n");
|
||||||
|
|
||||||
if (typeObjectMask(type) != 1) {
|
if (typeObjectMask(type) != 1) {
|
||||||
@ -1487,8 +1481,17 @@ writeInitialization(Output* out, Object* type)
|
|||||||
out->write(" object name = makeByteArray(t, \"");
|
out->write(" object name = makeByteArray(t, \"");
|
||||||
out->write(typeJavaName(type));
|
out->write(typeJavaName(type));
|
||||||
out->write("\");\n");
|
out->write("\");\n");
|
||||||
|
|
||||||
|
if (typeSuper(type)) {
|
||||||
|
out->write(" object super = arrayBody(t, t->vm->types, Machine::");
|
||||||
|
out->write(capitalize(typeName(typeSuper(type))));
|
||||||
|
out->write("Type);\n");
|
||||||
|
} else {
|
||||||
|
out->write(" object super = 0;\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
out->write(" object name = 0;\n");
|
out->write(" object name = 0;\n");
|
||||||
|
out->write(" object super = 0;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
out->write(" object class_ = makeClass");
|
out->write(" object class_ = makeClass");
|
||||||
@ -1496,7 +1499,7 @@ writeInitialization(Output* out, Object* type)
|
|||||||
out->write(typeFixedSize(type));
|
out->write(typeFixedSize(type));
|
||||||
out->write(", ");
|
out->write(", ");
|
||||||
out->write(typeArrayElementSize(type));
|
out->write(typeArrayElementSize(type));
|
||||||
out->write(", mask, name, 0, 0, 0, 0, 0, 0, 0);\n");
|
out->write(", mask, name, super, 0, 0, 0, 0, 0, 0);\n");
|
||||||
|
|
||||||
out->write(" set(t, arrayBody(t, t->vm->types, Machine::");
|
out->write(" set(t, arrayBody(t, t->vm->types, Machine::");
|
||||||
out->write(capitalize(typeName(type)));
|
out->write(capitalize(typeName(type)));
|
||||||
@ -1518,9 +1521,7 @@ typeCount(Object* declarations)
|
|||||||
Object* o = car(p);
|
Object* o = car(p);
|
||||||
switch (o->type) {
|
switch (o->type) {
|
||||||
case Object::Type: {
|
case Object::Type: {
|
||||||
if (typeMemberCount(o)) {
|
|
||||||
++ count;
|
++ count;
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -51,9 +51,17 @@
|
|||||||
(type exceptionHandlerTable
|
(type exceptionHandlerTable
|
||||||
(array exceptionHandler body))
|
(array exceptionHandler body))
|
||||||
|
|
||||||
|
(pod lineNumber
|
||||||
|
(uint16_t ip)
|
||||||
|
(uint16_t line))
|
||||||
|
|
||||||
|
(type lineNumberTable
|
||||||
|
(array lineNumber body))
|
||||||
|
|
||||||
(type code
|
(type code
|
||||||
(object pool)
|
(object pool)
|
||||||
(object exceptionHandlerTable)
|
(object exceptionHandlerTable)
|
||||||
|
(object lineNumberTable)
|
||||||
(uint16_t maxStack)
|
(uint16_t maxStack)
|
||||||
(uint16_t maxLocals)
|
(uint16_t maxLocals)
|
||||||
(array uint8_t body))
|
(array uint8_t body))
|
||||||
@ -100,10 +108,9 @@
|
|||||||
(object front)
|
(object front)
|
||||||
(object rear))
|
(object rear))
|
||||||
|
|
||||||
(type trace
|
(type stackTraceElement
|
||||||
(object method)
|
(object method)
|
||||||
(uint32_t ip)
|
(int32_t ip))
|
||||||
(object next))
|
|
||||||
|
|
||||||
(type array
|
(type array
|
||||||
(noassert array object body))
|
(noassert array object body))
|
||||||
|
177
src/vm.cpp
177
src/vm.cpp
@ -52,6 +52,9 @@ enum FieldCode {
|
|||||||
ObjectField
|
ObjectField
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int NativeLine = -1;
|
||||||
|
static const int UnknownLine = -2;
|
||||||
|
|
||||||
class Machine {
|
class Machine {
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
@ -808,19 +811,35 @@ makeString(Thread* t, const char* format, ...)
|
|||||||
return makeString(t, s, 0, byteArrayLength(t, s), 0);
|
return makeString(t, s, 0, byteArrayLength(t, s), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
makeTrace(Thread* t, object frame)
|
||||||
|
{
|
||||||
|
PROTECT(t, frame);
|
||||||
|
|
||||||
|
unsigned count = 0;
|
||||||
|
for (object f = frame; f; f = frameNext(t, f)) {
|
||||||
|
++ count;
|
||||||
|
}
|
||||||
|
|
||||||
|
object trace = makeObjectArray
|
||||||
|
(t, arrayBody(t, t->vm->types, Machine::StackTraceElementType),
|
||||||
|
count, true);
|
||||||
|
PROTECT(t, trace);
|
||||||
|
|
||||||
|
unsigned index = 0;
|
||||||
|
for (object f = frame; f; f = frameNext(t, f)) {
|
||||||
|
object e = makeStackTraceElement(t, frameMethod(t, f), frameIp(t, f));
|
||||||
|
set(t, objectArrayBody(t, trace, index++), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return trace;
|
||||||
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t)
|
makeTrace(Thread* t)
|
||||||
{
|
{
|
||||||
object trace = 0;
|
|
||||||
if (t->frame) {
|
|
||||||
PROTECT(t, trace);
|
|
||||||
frameIp(t, t->frame) = t->ip;
|
frameIp(t, t->frame) = t->ip;
|
||||||
for (; t->frame; t->frame = frameNext(t, t->frame)) {
|
return makeTrace(t, t->frame);
|
||||||
trace = makeTrace
|
|
||||||
(t, frameMethod(t, t->frame), frameIp(t, t->frame), trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return trace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -1093,6 +1112,7 @@ setField(Thread* t, object o, object field, object value)
|
|||||||
break;
|
break;
|
||||||
case ObjectField:
|
case ObjectField:
|
||||||
set(t, cast<object>(o, fieldOffset(t, field)), value);
|
set(t, cast<object>(o, fieldOffset(t, field)), value);
|
||||||
|
break;
|
||||||
|
|
||||||
default: abort(t);
|
default: abort(t);
|
||||||
}
|
}
|
||||||
@ -1486,10 +1506,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classFixedSize(t, class_) = divide(memberOffset, BytesPerWord);
|
classFixedSize(t, class_) = pad(memberOffset);
|
||||||
|
|
||||||
object mask = makeIntArray
|
object mask = makeIntArray
|
||||||
(t, divide(classFixedSize(t, class_), BitsPerWord), true);
|
(t, divide(classFixedSize(t, class_), BitsPerWord), true);
|
||||||
|
intArrayBody(t, mask, 0) = 1;
|
||||||
|
|
||||||
bool sawReferenceField = false;
|
bool sawReferenceField = false;
|
||||||
for (object c = class_; c; c = classSuper(t, c)) {
|
for (object c = class_; c; c = classSuper(t, c)) {
|
||||||
@ -1518,7 +1539,7 @@ parseCode(Thread* t, Stream& s, object pool)
|
|||||||
unsigned maxLocals = s.read2();
|
unsigned maxLocals = s.read2();
|
||||||
unsigned length = s.read4();
|
unsigned length = s.read4();
|
||||||
|
|
||||||
object code = makeCode(t, pool, 0, maxStack, maxLocals, length, false);
|
object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false);
|
||||||
s.read(&codeBody(t, code, 0), length);
|
s.read(&codeBody(t, code, 0), length);
|
||||||
|
|
||||||
unsigned ehtLength = s.read2();
|
unsigned ehtLength = s.read2();
|
||||||
@ -1539,8 +1560,24 @@ parseCode(Thread* t, Stream& s, object pool)
|
|||||||
|
|
||||||
unsigned attributeCount = s.read2();
|
unsigned attributeCount = s.read2();
|
||||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||||
s.read2();
|
object name = arrayBody(t, pool, s.read2() - 1);
|
||||||
s.skip(s.read4());
|
unsigned length = s.read4();
|
||||||
|
|
||||||
|
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
||||||
|
&byteArrayBody(t, name, 0)) == 0)
|
||||||
|
{
|
||||||
|
unsigned lntLength = s.read2();
|
||||||
|
object lnt = makeLineNumberTable(t, lntLength, false);
|
||||||
|
for (unsigned i = 0; i < lntLength; ++i) {
|
||||||
|
LineNumber* ln = lineNumberTableBody(t, lnt, i);
|
||||||
|
lineNumberIp(ln) = s.read2();
|
||||||
|
lineNumberLine(ln) = s.read2();
|
||||||
|
}
|
||||||
|
|
||||||
|
set(t, codeLineNumberTable(t, code), lnt);
|
||||||
|
} else {
|
||||||
|
s.skip(length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
@ -1574,6 +1611,30 @@ parameterCount(Thread* t, object spec)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lineNumber(Thread* t, object method, unsigned ip)
|
||||||
|
{
|
||||||
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||||
|
return NativeLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
object table = codeLineNumberTable(t, methodCode(t, method));
|
||||||
|
if (table) {
|
||||||
|
// todo: do a binary search:
|
||||||
|
int last = UnknownLine;
|
||||||
|
for (unsigned i = 0; i < lineNumberTableLength(t, table); ++i) {
|
||||||
|
if (ip <= lineNumberIp(lineNumberTableBody(t, table, i))) {
|
||||||
|
return last;
|
||||||
|
} else {
|
||||||
|
last = lineNumberLine(lineNumberTableBody(t, table, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
} else {
|
||||||
|
return UnknownLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
mangledSize(int8_t c)
|
mangledSize(int8_t c)
|
||||||
{
|
{
|
||||||
@ -2158,7 +2219,7 @@ invokeNative(Thread* t, object method)
|
|||||||
args[offset++] = reinterpret_cast<uintptr_t>(t);
|
args[offset++] = reinterpret_cast<uintptr_t>(t);
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
unsigned type = nativeMethodDataParameterTypes(t, data, i);
|
unsigned type = nativeMethodDataParameterTypes(t, data, i + 1);
|
||||||
unsigned position = (t->sp - count) + i;
|
unsigned position = (t->sp - count) + i;
|
||||||
object o = t->stack[position];
|
object o = t->stack[position];
|
||||||
|
|
||||||
@ -2222,8 +2283,10 @@ invokeNative(Thread* t, object method)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace builtin {
|
||||||
|
|
||||||
void
|
void
|
||||||
builtinLoadLibrary(JNIEnv* e, jstring nameString)
|
loadLibrary(JNIEnv* e, jstring nameString)
|
||||||
{
|
{
|
||||||
Thread* t = static_cast<Thread*>(e);
|
Thread* t = static_cast<Thread*>(e);
|
||||||
|
|
||||||
@ -2250,7 +2313,7 @@ builtinLoadLibrary(JNIEnv* e, jstring nameString)
|
|||||||
}
|
}
|
||||||
|
|
||||||
jstring
|
jstring
|
||||||
builtinToString(JNIEnv* e, jobject this_)
|
toString(JNIEnv* e, jobject this_)
|
||||||
{
|
{
|
||||||
Thread* t = static_cast<Thread*>(e);
|
Thread* t = static_cast<Thread*>(e);
|
||||||
|
|
||||||
@ -2263,6 +2326,34 @@ builtinToString(JNIEnv* e, jobject this_)
|
|||||||
return t->stack + (t->sp - 1);
|
return t->stack + (t->sp - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jarray
|
||||||
|
trace(JNIEnv* e, jint skipCount)
|
||||||
|
{
|
||||||
|
Thread* t = static_cast<Thread*>(e);
|
||||||
|
|
||||||
|
object frame = t->frame;
|
||||||
|
while (skipCount--) frame = frameNext(t, frame);
|
||||||
|
|
||||||
|
if (methodClass(t, frameMethod(t, frame))
|
||||||
|
== arrayBody(t, t->vm->types, Machine::ThrowableType))
|
||||||
|
{
|
||||||
|
// skip Throwable constructors
|
||||||
|
while (strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||||
|
&byteArrayBody(t, methodName(t, frameMethod(t, frame)), 0))
|
||||||
|
== 0)
|
||||||
|
{
|
||||||
|
frame = frameNext(t, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushSafe(t, makeTrace(t, frame));
|
||||||
|
return t->stack + (t->sp - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace builtin
|
||||||
|
|
||||||
|
namespace jni {
|
||||||
|
|
||||||
jsize
|
jsize
|
||||||
GetStringUTFLength(JNIEnv* e, jstring s)
|
GetStringUTFLength(JNIEnv* e, jstring s)
|
||||||
{
|
{
|
||||||
@ -2304,7 +2395,7 @@ GetStringUTFChars(JNIEnv* e, jstring s, jboolean* isCopy)
|
|||||||
|
|
||||||
enter(t, Thread::IdleState);
|
enter(t, Thread::IdleState);
|
||||||
|
|
||||||
*isCopy = true;
|
if (isCopy) *isCopy = true;
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2314,6 +2405,8 @@ ReleaseStringUTFChars(JNIEnv* e, jstring, const char* chars)
|
|||||||
static_cast<Thread*>(e)->vm->system->free(chars);
|
static_cast<Thread*>(e)->vm->system->free(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace jni
|
||||||
|
|
||||||
Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
|
Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
|
||||||
system(system),
|
system(system),
|
||||||
heap(heap),
|
heap(heap),
|
||||||
@ -2334,9 +2427,9 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
|
|||||||
{
|
{
|
||||||
memset(&jniEnvVTable, 0, sizeof(JNIEnvVTable));
|
memset(&jniEnvVTable, 0, sizeof(JNIEnvVTable));
|
||||||
|
|
||||||
jniEnvVTable.GetStringUTFLength = GetStringUTFLength;
|
jniEnvVTable.GetStringUTFLength = jni::GetStringUTFLength;
|
||||||
jniEnvVTable.GetStringUTFChars = GetStringUTFChars;
|
jniEnvVTable.GetStringUTFChars = jni::GetStringUTFChars;
|
||||||
jniEnvVTable.ReleaseStringUTFChars = ReleaseStringUTFChars;
|
jniEnvVTable.ReleaseStringUTFChars = jni::ReleaseStringUTFChars;
|
||||||
|
|
||||||
if (not system->success(system->make(&stateLock)) or
|
if (not system->success(system->make(&stateLock)) or
|
||||||
not system->success(system->make(&heapLock)) or
|
not system->success(system->make(&heapLock)) or
|
||||||
@ -2408,9 +2501,11 @@ Thread::Thread(Machine* m):
|
|||||||
void* value;
|
void* value;
|
||||||
} builtins[] = {
|
} builtins[] = {
|
||||||
{ "Java_java_lang_Object_toString",
|
{ "Java_java_lang_Object_toString",
|
||||||
reinterpret_cast<void*>(builtinToString) },
|
reinterpret_cast<void*>(builtin::toString) },
|
||||||
{ "Java_java_lang_System_loadLibrary",
|
{ "Java_java_lang_System_loadLibrary",
|
||||||
reinterpret_cast<void*>(builtinLoadLibrary) },
|
reinterpret_cast<void*>(builtin::loadLibrary) },
|
||||||
|
{ "Java_java_lang_Throwable_trace",
|
||||||
|
reinterpret_cast<void*>(builtin::trace) },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3849,14 +3944,6 @@ run(Thread* t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object p = 0;
|
|
||||||
object n = 0;
|
|
||||||
for (object trace = throwableTrace(t, exception); trace; trace = n) {
|
|
||||||
n = traceNext(t, trace);
|
|
||||||
set(t, traceNext(t, trace), p);
|
|
||||||
p = trace;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (object e = exception; e; e = throwableCause(t, e)) {
|
for (object e = exception; e; e = throwableCause(t, e)) {
|
||||||
if (e == exception) {
|
if (e == exception) {
|
||||||
fprintf(stderr, "uncaught exception: ");
|
fprintf(stderr, "uncaught exception: ");
|
||||||
@ -3870,14 +3957,32 @@ run(Thread* t)
|
|||||||
if (throwableMessage(t, exception)) {
|
if (throwableMessage(t, exception)) {
|
||||||
fprintf(stderr, ": %s\n", &byteArrayBody
|
fprintf(stderr, ": %s\n", &byteArrayBody
|
||||||
(t, stringBytes(t, throwableMessage(t, exception)), 0));
|
(t, stringBytes(t, throwableMessage(t, exception)), 0));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; p; p = traceNext(t, p)) {
|
object trace = throwableTrace(t, e);
|
||||||
fprintf(stderr, " at %s.%s\n",
|
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
|
||||||
&byteArrayBody
|
object e = objectArrayBody(t, trace, i);
|
||||||
(t, className(t, methodClass(t, traceMethod(t, p))), 0),
|
const int8_t* class_ = &byteArrayBody
|
||||||
&byteArrayBody
|
(t, className(t, methodClass(t, stackTraceElementMethod(t, e))), 0);
|
||||||
(t, methodName(t, traceMethod(t, p)), 0));
|
const int8_t* method = &byteArrayBody
|
||||||
|
(t, methodName(t, stackTraceElementMethod(t, e)), 0);
|
||||||
|
int line = lineNumber
|
||||||
|
(t, stackTraceElementMethod(t, e), stackTraceElementIp(t, e));
|
||||||
|
|
||||||
|
fprintf(stderr, " at %s.%s", class_, method);
|
||||||
|
|
||||||
|
switch (line) {
|
||||||
|
case NativeLine:
|
||||||
|
fprintf(stderr, "(native)\n");
|
||||||
|
break;
|
||||||
|
case UnknownLine:
|
||||||
|
fprintf(stderr, "(unknown)\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "(%d)\n", line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user