From c34ee64988603a0273238a055c51e7c04b618702 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 29 Jun 2007 19:37:45 -0600 Subject: [PATCH] classloading bugfixes and stack trace work --- classpath/java/lang/Throwable.java | 22 +++- makefile | 8 +- src/type-generator.cpp | 45 ++++---- src/types.def | 15 ++- src/vm.cpp | 179 +++++++++++++++++++++++------ 5 files changed, 201 insertions(+), 68 deletions(-) diff --git a/classpath/java/lang/Throwable.java b/classpath/java/lang/Throwable.java index 6ddb1cdfd7..d4330f7bf4 100644 --- a/classpath/java/lang/Throwable.java +++ b/classpath/java/lang/Throwable.java @@ -2,6 +2,26 @@ package java.lang; public class Throwable { private String message; - private Object trace; + private StackTraceElement[] trace; 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); } diff --git a/makefile b/makefile index 9725fafa93..97ca7c1b11 100644 --- a/makefile +++ b/makefile @@ -122,10 +122,10 @@ fast-objects = \ fast-executable = $(bld)/fast-vm fast-cflags = $(fast) $(cflags) -input = $(bld)/classes/Hello.class -input-depends = \ - $(bld)/classes/java/lang/System.class \ - $(jni-library) +input = $(bld)/classes/TestExceptions.class +# input-depends = \ +# $(bld)/classes/java/lang/System.class \ +# $(jni-library) gen-run-arg = $(shell echo $(1) | sed -e 's:$(bld)/classes/\(.*\)\.class:\1:') args = -cp $(bld)/classes -hs 67108864 $(call gen-run-arg,$(input)) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 8ba1497cd6..e71c3a77cc 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -659,7 +659,7 @@ class MemberIterator { switch (member->type) { case Object::Scalar: { size_ = memberSize(member); - padding_ = pad(size_, alignment_); + padding_ = pad(size_, alignment_); alignment_ = (alignment_ + size_ + padding_) % sizeof(void*); } break; @@ -674,6 +674,9 @@ class MemberIterator { offset_ += padding_; +// printf("size: %d; padding: %d; alignment: %d; offset: %d;\n", +// size_, padding_, alignment_, offset_); + return member; } @@ -1271,8 +1274,6 @@ writeConstructorDeclarations(Output* out, Object* declarations) Object* o = car(p); switch (o->type) { case Object::Type: { - if (typeMemberCount(o) == 0) continue; - out->write("object make"); out->write(capitalize(typeName(o))); if (typeHideConstructor(o)) out->write("0"); @@ -1295,8 +1296,6 @@ writeConstructors(Output* out, Object* declarations) Object* o = car(p); switch (o->type) { case Object::Type: { - if (typeMemberCount(o) == 0) continue; - out->write("object\nmake"); out->write(capitalize(typeName(o))); if (typeHideConstructor(o)) out->write("0"); @@ -1343,15 +1342,13 @@ writeEnums(Output* out, Object* declarations) Object* o = car(p); switch (o->type) { case Object::Type: { - if (typeMemberCount(o)) { - if (wrote) { - out->write(",\n"); - } else { - wrote = true; - } - out->write(capitalize(typeName(o))); - out->write("Type"); + if (wrote) { + out->write(",\n"); + } else { + wrote = true; } + out->write(capitalize(typeName(o))); + out->write("Type"); } break; default: break; @@ -1387,7 +1384,7 @@ set(uint32_t* mask, unsigned index) unsigned typeFixedSize(Object* type) { - unsigned length = 0; + unsigned length = sizeof(void*); for (MemberIterator it(type); it.hasMore();) { Object* m = it.next(); switch (m->type) { @@ -1465,9 +1462,6 @@ typeObjectMask(Object* type) void writeInitialization(Output* out, Object* type) { - unsigned memberCount = ::memberCount(type); - if (memberCount == 0) return; - out->write("{\n"); if (typeObjectMask(type) != 1) { @@ -1487,8 +1481,17 @@ writeInitialization(Output* out, Object* type) out->write(" object name = makeByteArray(t, \""); out->write(typeJavaName(type)); 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 { - out->write(" object name = 0;\n"); + out->write(" object name = 0;\n"); + out->write(" object super = 0;\n"); } out->write(" object class_ = makeClass"); @@ -1496,7 +1499,7 @@ writeInitialization(Output* out, Object* type) out->write(typeFixedSize(type)); out->write(", "); 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(capitalize(typeName(type))); @@ -1518,9 +1521,7 @@ typeCount(Object* declarations) Object* o = car(p); switch (o->type) { case Object::Type: { - if (typeMemberCount(o)) { - ++ count; - } + ++ count; } break; default: break; diff --git a/src/types.def b/src/types.def index 645a984e58..e71d0115b3 100644 --- a/src/types.def +++ b/src/types.def @@ -51,9 +51,17 @@ (type exceptionHandlerTable (array exceptionHandler body)) +(pod lineNumber + (uint16_t ip) + (uint16_t line)) + +(type lineNumberTable + (array lineNumber body)) + (type code (object pool) (object exceptionHandlerTable) + (object lineNumberTable) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) @@ -100,11 +108,10 @@ (object front) (object rear)) -(type trace +(type stackTraceElement (object method) - (uint32_t ip) - (object next)) - + (int32_t ip)) + (type array (noassert array object body)) diff --git a/src/vm.cpp b/src/vm.cpp index 6358cd1dc7..39ef725e96 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -52,6 +52,9 @@ enum FieldCode { ObjectField }; +static const int NativeLine = -1; +static const int UnknownLine = -2; + class Machine { public: enum { @@ -808,19 +811,35 @@ makeString(Thread* t, const char* format, ...) 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 makeTrace(Thread* t) { - object trace = 0; - if (t->frame) { - PROTECT(t, trace); - frameIp(t, t->frame) = t->ip; - for (; t->frame; t->frame = frameNext(t, t->frame)) { - trace = makeTrace - (t, frameMethod(t, t->frame), frameIp(t, t->frame), trace); - } - } - return trace; + frameIp(t, t->frame) = t->ip; + return makeTrace(t, t->frame); } object @@ -1093,6 +1112,7 @@ setField(Thread* t, object o, object field, object value) break; case ObjectField: set(t, cast(o, fieldOffset(t, field)), value); + break; 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 (t, divide(classFixedSize(t, class_), BitsPerWord), true); + intArrayBody(t, mask, 0) = 1; bool sawReferenceField = false; 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 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); unsigned ehtLength = s.read2(); @@ -1539,8 +1560,24 @@ parseCode(Thread* t, Stream& s, object pool) unsigned attributeCount = s.read2(); for (unsigned j = 0; j < attributeCount; ++j) { - s.read2(); - s.skip(s.read4()); + object name = arrayBody(t, pool, s.read2() - 1); + unsigned length = s.read4(); + + if (strcmp(reinterpret_cast("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; @@ -1574,6 +1611,30 @@ parameterCount(Thread* t, object spec) 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 mangledSize(int8_t c) { @@ -2158,7 +2219,7 @@ invokeNative(Thread* t, object method) args[offset++] = reinterpret_cast(t); 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; object o = t->stack[position]; @@ -2222,8 +2283,10 @@ invokeNative(Thread* t, object method) } } +namespace builtin { + void -builtinLoadLibrary(JNIEnv* e, jstring nameString) +loadLibrary(JNIEnv* e, jstring nameString) { Thread* t = static_cast(e); @@ -2250,7 +2313,7 @@ builtinLoadLibrary(JNIEnv* e, jstring nameString) } jstring -builtinToString(JNIEnv* e, jobject this_) +toString(JNIEnv* e, jobject this_) { Thread* t = static_cast(e); @@ -2263,6 +2326,34 @@ builtinToString(JNIEnv* e, jobject this_) return t->stack + (t->sp - 1); } +jarray +trace(JNIEnv* e, jint skipCount) +{ + Thread* t = static_cast(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(""), + &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 GetStringUTFLength(JNIEnv* e, jstring s) { @@ -2304,7 +2395,7 @@ GetStringUTFChars(JNIEnv* e, jstring s, jboolean* isCopy) enter(t, Thread::IdleState); - *isCopy = true; + if (isCopy) *isCopy = true; return chars; } @@ -2314,6 +2405,8 @@ ReleaseStringUTFChars(JNIEnv* e, jstring, const char* chars) static_cast(e)->vm->system->free(chars); } +} // namespace jni + Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): system(system), heap(heap), @@ -2334,9 +2427,9 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): { memset(&jniEnvVTable, 0, sizeof(JNIEnvVTable)); - jniEnvVTable.GetStringUTFLength = GetStringUTFLength; - jniEnvVTable.GetStringUTFChars = GetStringUTFChars; - jniEnvVTable.ReleaseStringUTFChars = ReleaseStringUTFChars; + jniEnvVTable.GetStringUTFLength = jni::GetStringUTFLength; + jniEnvVTable.GetStringUTFChars = jni::GetStringUTFChars; + jniEnvVTable.ReleaseStringUTFChars = jni::ReleaseStringUTFChars; if (not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or @@ -2408,9 +2501,11 @@ Thread::Thread(Machine* m): void* value; } builtins[] = { { "Java_java_lang_Object_toString", - reinterpret_cast(builtinToString) }, + reinterpret_cast(builtin::toString) }, { "Java_java_lang_System_loadLibrary", - reinterpret_cast(builtinLoadLibrary) }, + reinterpret_cast(builtin::loadLibrary) }, + { "Java_java_lang_Throwable_trace", + reinterpret_cast(builtin::trace) }, { 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)) { if (e == exception) { fprintf(stderr, "uncaught exception: "); @@ -3870,14 +3957,32 @@ run(Thread* t) if (throwableMessage(t, exception)) { fprintf(stderr, ": %s\n", &byteArrayBody (t, stringBytes(t, throwableMessage(t, exception)), 0)); + } else { + fprintf(stderr, "\n"); } - for (; p; p = traceNext(t, p)) { - fprintf(stderr, " at %s.%s\n", - &byteArrayBody - (t, className(t, methodClass(t, traceMethod(t, p))), 0), - &byteArrayBody - (t, methodName(t, traceMethod(t, p)), 0)); + object trace = throwableTrace(t, e); + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { + object e = objectArrayBody(t, trace, i); + const int8_t* class_ = &byteArrayBody + (t, className(t, methodClass(t, stackTraceElementMethod(t, e))), 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); + } } }