mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +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 {
|
||||
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);
|
||||
}
|
||||
|
8
makefile
8
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))
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
||||
|
179
src/vm.cpp
179
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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user