classloading bugfixes and stack trace work

This commit is contained in:
Joel Dice 2007-06-29 19:37:45 -06:00
parent 60da97dfc8
commit c34ee64988
5 changed files with 201 additions and 68 deletions

View File

@ -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);
}

View File

@ -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))

View File

@ -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;

View File

@ -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))

View File

@ -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<object>(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<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;
@ -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<uintptr_t>(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<Thread*>(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<Thread*>(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<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
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<Thread*>(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<void*>(builtinToString) },
reinterpret_cast<void*>(builtin::toString) },
{ "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 }
};
@ -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);
}
}
}