diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 35d50c5965..e27bf654c9 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -1,5 +1,8 @@ package java.lang; +import java.lang.reflect.Method; +import java.lang.reflect.Field; + public final class Class { private short flags; private byte vmFlags; @@ -9,16 +12,57 @@ public final class Class { private int[] objectMask; private byte[] name; private Class super_; - private Object interfaceTable; - private Object virtualTable; - private Object fieldTable; - private Object methodTable; - private Object staticTable; - private Object initializer; + private Object[] interfaceTable; + private Method[] virtualTable; + private Field[] fieldTable; + private Method[] methodTable; + private Object[] staticTable; + private Method initializer; private Class() { } public String getName() { return new String(name, 0, name.length - 1, false); } + + public static native Class forName(String name); + + public native boolean isAssignableFrom(Class c); + + public Field getDeclaredField(String name) throws NoSuchFieldException { + for (int i = 0; i < fieldTable.length; ++i) { + if (fieldTable[i].getName().equals(name)) { + return fieldTable[i]; + } + } + + throw new NoSuchFieldException(name); + } + + private static boolean match(Class[] a, Class[] b) { + if (a.length == b.length) { + for (int i = 0; i < a.length; ++i) { + if (! a[i].isAssignableFrom(b[i])) { + return false; + } + } + return true; + } else { + return false; + } + } + + public Method getDeclaredMethod(String name, Class ... parameterTypes) + throws NoSuchMethodException + { + for (int i = 0; i < methodTable.length; ++i) { + if (methodTable[i].getName().equals(name) + && match(parameterTypes, methodTable[i].getParameterTypes())) + { + return methodTable[i]; + } + } + + throw new NoSuchMethodException(name); + } } diff --git a/classpath/java/lang/NullPointerException.java b/classpath/java/lang/NullPointerException.java new file mode 100644 index 0000000000..92e2eae934 --- /dev/null +++ b/classpath/java/lang/NullPointerException.java @@ -0,0 +1,19 @@ +package java.lang; + +public class NullPointerException extends RuntimeException { + public NullPointerException(String message, Throwable cause) { + super(message, cause); + } + + public NullPointerException(String message) { + this(message, null); + } + + public NullPointerException(Throwable cause) { + this(null, cause); + } + + public NullPointerException() { + this(null, null); + } +} diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index d7218911d2..c913f27ef9 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -101,7 +101,8 @@ public final class String implements Comparable { return new String(data, offset + start, end - start, false); } } else { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException + (start + " not in (0, " + end + ") or " + end + " > " + length); } } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 175f22f287..f9fc796858 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -30,4 +30,6 @@ public class Field extends AccessibleObject { public String getName() { return new String(name, 0, name.length - 1, false); } + + public native Object get(Object instance); } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 236138d439..84831c01b6 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -32,4 +32,54 @@ public class Method extends AccessibleObject implements Member { public String getName() { return new String(name, 0, name.length - 1, false); } + + private static int next(char c, String s, int start) { + for (int i = start; i < s.length(); ++i) { + if (s.charAt(i) == c) return i; + } + throw new RuntimeException(); + } + + public Class[] getParameterTypes() { + int count = parameterCount; + if ((flags & Modifier.STATIC) == 0) { + -- count; + } + + Class[] types = new Class[count]; + int index = 0; + + String spec = new String(this.spec, 1, this.spec.length - 1, false); + + for (int i = 0; i < spec.length(); ++i) { + char c = spec.charAt(i); + if (c == ')') { + break; + } else if (c == 'L') { + int start = i + 1; + i = next(';', spec, start); + String name = spec.substring(start, i); + types[index++] = Class.forName(name); + } else if (c == '[') { + int start = i; + while (spec.charAt(i) == '[') ++i; + + if (spec.charAt(i) == 'L') { + i = next(';', spec, i + 1); + String name = spec.substring(start, i); + types[index++] = Class.forName(name); + } else { + String name = spec.substring(start, i + 1); + types[index++] = Class.forName(name); + } + } else { + String name = spec.substring(i, i + 1); + types[index++] = Class.forName(name); + } + } + + return types; + } + + public native Object invoke(Object instance, Object ... arguments); } diff --git a/makefile b/makefile index daf0b7b600..d7b7654b52 100644 --- a/makefile +++ b/makefile @@ -16,7 +16,7 @@ src = src classpath = classpath test = test -input = $(cls)/References.class +input = $(cls)/Threads.class cxx = g++ cc = gcc diff --git a/src/builtin.cpp b/src/builtin.cpp index 8d8257678c..27a5cc4e0b 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -1,7 +1,30 @@ #include "builtin.h" #include "machine.h" +#include "constants.h" #include "run.h" +using namespace vm; + +namespace { + +object +doInvoke(Thread* t, object this_, object instance, object arguments) +{ + object v = pushReference(t, run2(t, this_, instance, arguments)); + if (t->exception) { + t->exception = makeInvocationTargetException(t, t->exception); + } + return v; +} + +inline void +replace(char a, char b, char* c) +{ + for (; *c; ++c) if (*c == a) *c = b; +} + +} // namespace + namespace vm { namespace builtin { @@ -41,6 +64,148 @@ notifyAll(Thread* t, jobject this_) vm::notifyAll(t, *this_); } +jclass +forName(Thread* t, jstring name) +{ + if (LIKELY(name)) { + object n = makeByteArray(t, stringLength(t, *name) + 1, false); + char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); + stringChars(t, *name, s); + + replace('.', '/', s); + + object c = resolveClass(t, n); + if (t->exception) { + return 0; + } + + object clinit = classInitializer(t, c); + if (clinit) { + PROTECT(t, c); + + set(t, classInitializer(t, c), 0); + run(t, clinit, 0); + } + + return pushReference(t, c); + } else { + t->exception = makeNullPointerException(t); + return 0; + } +} + +jboolean +isAssignableFrom(Thread* t, jobject this_, jclass that) +{ + if (LIKELY(that)) { + return vm::isAssignableFrom(t, *this_, *that); + } else { + t->exception = makeNullPointerException(t); + return 0; + } +} + +jobject +get(Thread* t, jobject this_, jobject instancep) +{ + object field = *this_; + + if (fieldFlags(t, field) & ACC_STATIC) { + return pushReference + (t, arrayBody(t, classStaticTable(t, fieldClass(t, field)), + fieldOffset(t, field))); + } else if (instancep) { + object instance = *instancep; + + if (instanceOf(t, fieldClass(t, this_), instance)) { + switch (fieldCode(t, field)) { + case ByteField: + return pushReference + (t, makeByte(t, cast(instance, fieldOffset(t, field)))); + + case BooleanField: + return pushReference + (t, makeBoolean(t, cast(instance, fieldOffset(t, field)))); + + case CharField: + return pushReference + (t, makeChar(t, cast(instance, fieldOffset(t, field)))); + + case ShortField: + return pushReference + (t, makeShort(t, cast(instance, fieldOffset(t, field)))); + + case FloatField: + return pushReference + (t, makeFloat(t, cast(instance, fieldOffset(t, field)))); + + case IntField: + return pushReference + (t, makeInt(t, cast(instance, fieldOffset(t, field)))); + + case DoubleField: + return pushReference + (t, makeDouble(t, cast(instance, fieldOffset(t, field)))); + + case LongField: + return pushReference + (t, makeLong(t, cast(instance, fieldOffset(t, field)))); + + case ObjectField: + return pushReference + (t, cast(instance, fieldOffset(t, field))); + + default: + abort(t); + } + } else { + t->exception = makeIllegalArgumentException(t); + return 0; + } + } else { + t->exception = makeNullPointerException(t); + return 0; + } +} + +jobject +invoke(Thread* t, jobject this_, jobject instancep, jobjectArray argumentsp) +{ + object method = *this_; + + if (argumentsp) { + object arguments = *argumentsp; + + if (methodFlags(t, method) & ACC_STATIC) { + if (objectArrayLength(t, arguments) + == methodParameterCount(t, method)) + { + return pushReference(t, doInvoke(t, method, 0, arguments)); + } else { + t->exception = makeArrayIndexOutOfBoundsException(t, 0); + } + } else if (instancep) { + object instance = *instancep; + + if (instanceOf(t, methodClass(t, method), instance)) { + if (objectArrayLength(t, arguments) + == static_cast(methodParameterCount(t, method) - 1)) + { + return pushReference(t, doInvoke(t, method, instance, arguments)); + } else { + t->exception = makeArrayIndexOutOfBoundsException(t, 0); + } + } + } else { + t->exception = makeNullPointerException(t); + } + } else { + t->exception = makeNullPointerException(t); + } + + return 0; +} + jobject currentThread(Thread* t) { @@ -104,15 +269,14 @@ currentTimeMillis(Thread* t) } void -loadLibrary(Thread* t, jobject, jstring nameString) +loadLibrary(Thread* t, jobject, jstring name) { - if (LIKELY(nameString)) { - object n = *nameString; - char name[stringLength(t, n) + 1]; - stringChars(t, n, name); + if (LIKELY(name)) { + char n[stringLength(t, *name) + 1]; + stringChars(t, *name, n); for (System::Library* lib = t->vm->libraries; lib; lib = lib->next()) { - if (::strcmp(lib->name(), name) == 0) { + if (::strcmp(lib->name(), n) == 0) { // already loaded return; } @@ -120,11 +284,11 @@ loadLibrary(Thread* t, jobject, jstring nameString) System::Library* lib; if (LIKELY(t->vm->system->success - (t->vm->system->load(&lib, name, t->vm->libraries)))) + (t->vm->system->load(&lib, n, t->vm->libraries)))) { t->vm->libraries = lib; } else { - object message = makeString(t, "library not found: %s", name); + object message = makeString(t, "library not found: %s", n); t->exception = makeRuntimeException(t, message); } } else { @@ -224,6 +388,10 @@ start(Thread* t, jobject this_) vm::run(t, "java/lang/Thread", "run", "()V", t->javaThread); + if (t->exception) { + printTrace(t, t->exception); + } + t->exit(); } @@ -252,6 +420,11 @@ populate(Thread* t, object map) const char* key; void* value; } builtins[] = { + { "Java_java_lang_Class_forName", + reinterpret_cast(forName) }, + { "Java_java_lang_Class_isAssignableFrom", + reinterpret_cast(isAssignableFrom) }, + { "Java_java_lang_System_arraycopy", reinterpret_cast(arraycopy) }, @@ -285,6 +458,12 @@ populate(Thread* t, object map) { "Java_java_lang_Object_wait", reinterpret_cast(wait) }, + { "Java_java_lang_reflect_Field_get", + reinterpret_cast(get) }, + + { "Java_java_lang_reflect_Method_invoke", + reinterpret_cast(invoke) }, + { 0, 0 } }; diff --git a/src/constants.h b/src/constants.h index e381b2dc09..4f571d0ec1 100644 --- a/src/constants.h +++ b/src/constants.h @@ -99,7 +99,7 @@ enum OpCode { i2s = 0x93, iadd = 0x60, iaload = 0x2e, - iand = 0x73, + iand = 0x7e, iastore = 0x4f, iconst_m1 = 0x02, iconst_0 = 0x03, @@ -113,9 +113,9 @@ enum OpCode { if_acmpne = 0xa6, if_icmpeq = 0x9f, if_icmpne = 0xa0, - if_icmpgt = 0xa1, + if_icmplt = 0xa1, if_icmpge = 0xa2, - if_icmplt = 0xa3, + if_icmpgt = 0xa3, if_icmple = 0xa4, ifeq = 0x99, ifge = 0x9c, diff --git a/src/machine.cpp b/src/machine.cpp index 50a609bc0b..6a0da2f6cb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1376,7 +1376,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): builtin::populate(t, m->builtinMap); - javaThread = makeThread(t, 0, 0, reinterpret_cast(t)); + t->javaThread = makeThread(t, 0, 0, reinterpret_cast(t)); } else { threadPeer(this, javaThread) = reinterpret_cast(this); parent->child = this; @@ -1625,6 +1625,39 @@ stringChars(Thread* t, object string, char* chars) chars[stringLength(t, string)] = 0; } +bool +isAssignableFrom(Thread* t, object a, object b) +{ + if (classFlags(t, a) & ACC_INTERFACE) { + for (; b; b = classSuper(t, b)) { + object itable = classInterfaceTable(t, b); + for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { + if (arrayBody(t, itable, i) == a) { + return true; + } + } + } + } else { + for (; b; b = classSuper(t, b)) { + if (b == a) { + return true; + } + } + } + + return false; +} + +bool +instanceOf(Thread* t, object class_, object o) +{ + if (o == 0) { + return false; + } else { + return isAssignableFrom(t, class_, objectClass(t, o)); + } +} + unsigned parameterFootprint(const char* s) { @@ -2015,27 +2048,27 @@ resolveClass(Thread* t, object spec) if (data) { if (Verbose) { - fprintf(stderr, "parsing %s\n", &byteArrayBody - (t, spec, 0)); + fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0)); } // parse class file class_ = parseClass(t, data->start(), data->length()); data->dispose(); - if (Verbose) { - fprintf(stderr, "done parsing %s\n", &byteArrayBody - (t, className(t, class_), 0)); - } + if (LIKELY(t->exception == 0)) { + if (Verbose) { + fprintf(stderr, "done parsing %s\n", &byteArrayBody(t, spec, 0)); + } - object bootstrapClass = hashMapFind - (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + object bootstrapClass = hashMapFind + (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); - if (bootstrapClass) { - PROTECT(t, bootstrapClass); + if (bootstrapClass) { + PROTECT(t, bootstrapClass); - updateBootstrapClass(t, bootstrapClass, class_); - class_ = bootstrapClass; + updateBootstrapClass(t, bootstrapClass, class_); + class_ = bootstrapClass; + } } } } @@ -2313,6 +2346,51 @@ collect(Thread* t, Heap::CollectionType type) killZombies(t, m->rootThread); } +void +printTrace(Thread* t, object exception) +{ + for (object e = exception; e; e = throwableCauseUnsafe(t, e)) { + if (e != exception) { + fprintf(stderr, "caused by: "); + } + + fprintf(stderr, "%s", &byteArrayBody + (t, className(t, objectClass(t, e)), 0)); + + if (throwableMessageUnsafe(t, e)) { + object m = throwableMessageUnsafe(t, e); + char message[stringLength(t, m) + 1]; + stringChars(t, m, message); + fprintf(stderr, ": %s\n", message); + } else { + fprintf(stderr, "\n"); + } + + object trace = throwableTraceUnsafe(t, e); + for (unsigned i = 0; i < arrayLength(t, trace); ++i) { + object e = arrayBody(t, trace, i); + const int8_t* class_ = &byteArrayBody + (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); + const int8_t* method = &byteArrayBody + (t, methodName(t, traceElementMethod(t, e)), 0); + int line = lineNumber(t, traceElementMethod(t, e), traceElementIp(t, e)); + + fprintf(stderr, " at %s.%s ", class_, method); + + switch (line) { + case NativeLine: + fprintf(stderr, "(native)\n"); + break; + case UnknownLine: + fprintf(stderr, "(unknown line)\n"); + break; + default: + fprintf(stderr, "(line %d)\n", line); + } + } + } +} + void noop() { } diff --git a/src/machine.h b/src/machine.h index 11b23206ff..49018fdac5 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1377,6 +1377,12 @@ makeIllegalStateException(Thread* t, object message) return makeIllegalStateException(t, message, trace, 0); } +inline object +makeIllegalArgumentException(Thread* t) +{ + return makeIllegalArgumentException(t, 0, makeTrace(t), 0); +} + inline object makeIllegalMonitorStateException(Thread* t) { @@ -1427,6 +1433,14 @@ makeNullPointerException(Thread* t) return makeNullPointerException(t, 0, makeTrace(t), 0); } +inline object +makeInvocationTargetException(Thread* t, object targetException) +{ + PROTECT(t, targetException); + object trace = makeTrace(t); + return makeRuntimeException(t, 0, trace, targetException); +} + inline object makeStackOverflowError(Thread* t) { @@ -1466,6 +1480,12 @@ makeString(Thread* t, const char* format, ...); void stringChars(Thread* t, object string, char* chars); +bool +isAssignableFrom(Thread* t, object a, object b); + +bool +instanceOf(Thread* t, object class_, object o); + inline void pushObject(Thread* t, object o) { @@ -1622,9 +1642,13 @@ pokeLong(Thread* t, unsigned index, uint64_t value) inline object* pushReference(Thread* t, object o) { - expect(t, t->sp + 1 < Thread::StackSizeInWords / 2); - pushObject(t, o); - return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); + if (o) { + expect(t, t->sp + 1 < Thread::StackSizeInWords / 2); + pushObject(t, o); + return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); + } else { + return 0; + } } inline int @@ -2055,6 +2079,9 @@ vmNotifyAll(Thread* t, object o) notifyAll(t, o); } +void +printTrace(Thread* t, object exception); + void exit(Thread* t); diff --git a/src/run.cpp b/src/run.cpp index 9c6f5d6bf6..5f1cee20bc 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -91,8 +91,7 @@ make(Thread* t, object class_) ACQUIRE(t, t->vm->referenceLock); - // jreferenceNext(t, instance) - cast(instance, BytesPerWord) = t->vm->weakReferences; + jreferenceNextUnsafe(t, instance) = t->vm->weakReferences; t->vm->weakReferences = instance; } @@ -106,33 +105,6 @@ setStatic(Thread* t, object field, object value) fieldOffset(t, field)), value); } -bool -instanceOf(Thread* t, object class_, object o) -{ - if (o == 0) { - return false; - } - - if (classFlags(t, class_) & ACC_INTERFACE) { - for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) { - object itable = classInterfaceTable(t, oc); - for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { - if (arrayBody(t, itable, i) == class_) { - return true; - } - } - } - } else { - for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) { - if (oc == class_) { - return true; - } - } - } - - return false; -} - object findInterfaceMethod(Thread* t, object method, object o) { @@ -328,6 +300,16 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin) case '[': argumentTableSize += BytesPerWord; while (*s == '[') ++ s; + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + default: + ++ s; + break; + } break; default: @@ -535,6 +517,8 @@ invokeNative(Thread* t, object method) object run(Thread* t) { + const int base = t->frame; + unsigned instruction = nop; unsigned& ip = t->ip; unsigned& sp = t->sp; @@ -659,8 +643,8 @@ run(Thread* t) case areturn: { object result = popObject(t); - popFrame(t); - if (frame >= 0) { + if (frame > base) { + popFrame(t); pushObject(t, result); goto loop; } else { @@ -1451,8 +1435,8 @@ run(Thread* t) case ireturn: { int32_t result = popInt(t); - popFrame(t); - if (frame >= 0) { + if (frame > base) { + popFrame(t); pushInt(t, result); goto loop; } else { @@ -1626,16 +1610,16 @@ run(Thread* t) if (objectClass(t, v) == arrayBody(t, t->vm->types, Machine::IntType)) { pushInt(t, intValue(t, v)); - } else if (objectClass(t, v) - == arrayBody(t, t->vm->types, Machine::StringType)) - { - pushObject(t, v); } else if (objectClass(t, v) == arrayBody(t, t->vm->types, Machine::FloatType)) { pushInt(t, floatValue(t, v)); + } else if (objectClass(t, v) + == arrayBody(t, t->vm->types, Machine::StringType)) + { + pushObject(t, v); } else { - abort(t); + pushObject(t, resolveClass(t, v)); } } goto loop; @@ -1710,8 +1694,8 @@ run(Thread* t) case lreturn: { int64_t result = popLong(t); - popFrame(t); - if (frame >= 0) { + if (frame > base) { + popFrame(t); pushLong(t, result); goto loop; } else { @@ -1993,8 +1977,8 @@ run(Thread* t) } goto loop; case return_: { - popFrame(t); - if (frame >= 0) { + if (frame > base) { + popFrame(t); goto loop; } else { return 0; @@ -2148,7 +2132,7 @@ run(Thread* t) pokeInt(t, t->frame + FrameIpOffset, t->ip); for (; frame >= 0; frame = frameNext(t, frame)) { - if (methodFlags(t, frameMethod(t, frame)) & ACC_NATIVE) { + if (frame < base) { return 0; } @@ -2185,49 +2169,6 @@ run(Thread* t) } } - for (object e = exception; e; e = throwableCause(t, e)) { - if (e == exception) { - fprintf(stderr, "uncaught exception: "); - } else { - fprintf(stderr, "caused by: "); - } - - fprintf(stderr, "%s", &byteArrayBody - (t, className(t, objectClass(t, exception)), 0)); - - if (throwableMessage(t, exception)) { - object m = throwableMessage(t, exception); - char message[stringLength(t, m) + 1]; - stringChars(t, m, message); - fprintf(stderr, ": %s\n", message); - } else { - fprintf(stderr, "\n"); - } - - object trace = throwableTrace(t, e); - for (unsigned i = 0; i < arrayLength(t, trace); ++i) { - object e = arrayBody(t, trace, i); - const int8_t* class_ = &byteArrayBody - (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); - const int8_t* method = &byteArrayBody - (t, methodName(t, traceElementMethod(t, e)), 0); - int line = lineNumber(t, traceElementMethod(t, e), traceElementIp(t, e)); - - fprintf(stderr, " at %s.%s ", class_, method); - - switch (line) { - case NativeLine: - fprintf(stderr, "(native)\n"); - break; - case UnknownLine: - fprintf(stderr, "(unknown line)\n"); - break; - default: - fprintf(stderr, "(line %d)\n", line); - } - } - } - return 0; } @@ -2249,32 +2190,14 @@ run(Thread* t, const char* className, int argc, const char** argv) run(t, className, "main", "([Ljava/lang/String;)V", 0, args); } -} // namespace - -namespace vm { - -object -run(Thread* t, const char* className, const char* methodName, - const char* methodSpec, object this_, ...) +void +pushArguments(Thread* t, object this_, const char* spec, va_list a) { - assert(t, t->state == Thread::ActiveState - or t->state == Thread::ExclusiveState); - - if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1 - > Thread::StackSizeInWords / 2)) - { - t->exception = makeStackOverflowError(t); - return 0; - } - if (this_) { pushObject(t, this_); } - va_list a; - va_start(a, this_); - - const char* s = methodSpec; + const char* s = spec; ++ s; // skip '(' while (*s and *s != ')') { switch (*s) { @@ -2311,6 +2234,172 @@ run(Thread* t, const char* className, const char* methodName, break; } } +} + +void +pushArguments(Thread* t, object this_, const char* spec, object a) +{ + if (this_) { + pushObject(t, this_); + } + + unsigned index = 0; + const char* s = spec; + ++ s; // skip '(' + while (*s and *s != ')') { + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + pushObject(t, objectArrayBody(t, a, index++)); + break; + + case '[': + while (*s == '[') ++ s; + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + default: + ++ s; + break; + } + pushObject(t, objectArrayBody(t, a, index++)); + break; + + case 'J': + case 'D': + ++ s; + pushLong(t, cast(objectArrayBody(t, a, index++), BytesPerWord)); + break; + + default: + ++ s; + pushInt(t, cast(objectArrayBody(t, a, index++), BytesPerWord)); + break; + } + } +} + +object +invoke(Thread* t, object method) +{ + object result = 0; + + if (methodFlags(t, method) & ACC_NATIVE) { + unsigned returnCode = invokeNative(t, method); + + if (LIKELY(t->exception == 0)) { + switch (returnCode) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: + return makeInt(t, popInt(t)); + + case LongField: + case DoubleField: + return makeLong(t, popLong(t)); + + case ObjectField: + return popObject(t); + + case VoidField: + return 0; + + default: + abort(t); + }; + } + } else { + checkStack(t, method); + if (LIKELY(t->exception == 0)) { + pushFrame(t, method); + result = ::run(t); + if (LIKELY(t->exception == 0)) { + popFrame(t); + } + } + } + + return result; +} + +} // namespace + +namespace vm { + +object +run(Thread* t, object method, object this_, ...) +{ + assert(t, t->state == Thread::ActiveState + or t->state == Thread::ExclusiveState); + + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + + if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 + > Thread::StackSizeInWords / 2)) + { + t->exception = makeStackOverflowError(t); + return 0; + } + + va_list a; + va_start(a, this_); + + const char* spec = reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0)); + pushArguments(t, this_, spec, a); + + va_end(a); + + return invoke(t, method); +} + +object +run2(Thread* t, object method, object this_, object arguments) +{ + assert(t, t->state == Thread::ActiveState + or t->state == Thread::ExclusiveState); + + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + + if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 + > Thread::StackSizeInWords / 2)) + { + t->exception = makeStackOverflowError(t); + return 0; + } + + const char* spec = reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0)); + pushArguments(t, this_, spec, arguments); + + return invoke(t, method); +} + +object +run(Thread* t, const char* className, const char* methodName, + const char* methodSpec, object this_, ...) +{ + assert(t, t->state == Thread::ActiveState + or t->state == Thread::ExclusiveState); + + if (UNLIKELY(t->sp + parameterFootprint(methodSpec) + 1 + > Thread::StackSizeInWords / 2)) + { + t->exception = makeStackOverflowError(t); + return 0; + } + + va_list a; + va_start(a, this_); + + pushArguments(t, this_, methodSpec, a); va_end(a); @@ -2328,43 +2417,11 @@ run(Thread* t, const char* className, const char* methodName, if (LIKELY(t->exception == 0)) { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - if (methodFlags(t, method) & ACC_NATIVE) { - unsigned returnCode = invokeNative(t, method); - - if (LIKELY(t->exception == 0)) { - switch (returnCode) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: - return makeInt(t, popInt(t)); - - case LongField: - case DoubleField: - return makeLong(t, popLong(t)); - - case ObjectField: - return popObject(t); - - case VoidField: - return 0; - - default: - abort(t); - }; - } - } else { - checkStack(t, method); - if (LIKELY(t->exception == 0)) { - pushFrame(t, method); - } - } + return invoke(t, method); } } - return ::run(t); + return 0; } int @@ -2379,7 +2436,10 @@ run(System* system, Heap* heap, ClassFinder* classFinder, ::run(t, className, argc, argv); int exitCode = 0; - if (t->exception) exitCode = -1; + if (t->exception) { + exitCode = -1; + printTrace(t, t->exception); + } exit(t); diff --git a/src/run.h b/src/run.h index 069b38c0a6..eed6e8e7f1 100644 --- a/src/run.h +++ b/src/run.h @@ -8,6 +8,12 @@ namespace vm { +object +run(Thread* t, object method, object this_, ...); + +object +run2(Thread* t, object method, object this_, object arguments); + object run(Thread* t, const char* className, const char* methodName, const char* methodSpec, object this_, ...); diff --git a/src/system.cpp b/src/system.cpp index 83ecb0fb6c..ee872acb5d 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -212,7 +212,7 @@ class MySystem: public System { } virtual void dispose() { - assert(s, context == 0); + //assert(s, context == 0); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&condition); s->free(this); diff --git a/src/types.def b/src/types.def index cb2d124737..155eb4c704 100644 --- a/src/types.def +++ b/src/types.def @@ -139,9 +139,9 @@ (type throwable java/lang/Throwable (extends jobject) - (object message) - (object trace) - (object cause)) + (noassert object message) + (noassert object trace) + (noassert object cause)) (type exception java/lang/Exception (extends throwable)) @@ -155,6 +155,9 @@ (type illegalStateException java/lang/IllegalStateException (extends runtimeException)) +(type illegalArgumentException java/lang/IllegalArgumentException + (extends runtimeException)) + (type illegalMonitorStateException java/lang/IllegalMonitorStateException (extends runtimeException)) @@ -174,6 +177,9 @@ (type classNotFoundException java/lang/ClassNotFoundException (extends runtimeException)) +(type invocationTargetException java/lang/InvocationTargetException + (extends exception)) + (type error java/lang/Error (extends throwable)) @@ -231,7 +237,7 @@ (type jreference java/lang/ref/Reference (extends jobject) - (void* next) + (noassert void* next) (void* target) (void* queue) (object jnext)) @@ -273,3 +279,30 @@ (type doubleArray [D (extends jobject) (array uint64_t body)) + +(type jbyte B + (extends jobject)) + +(type jboolean Z + (extends jobject)) + +(type jshort S + (extends jobject)) + +(type jchar C + (extends jobject)) + +(type jint I + (extends jobject)) + +(type jlong L + (extends jobject)) + +(type jfloat F + (extends jobject)) + +(type jdouble D + (extends jobject)) + +(type jvoid V + (extends jobject)) diff --git a/test/Reflection.java b/test/Reflection.java new file mode 100644 index 0000000000..f3878a8609 --- /dev/null +++ b/test/Reflection.java @@ -0,0 +1,13 @@ +import java.lang.reflect.Method; +import java.lang.reflect.Field; + +public class Reflection { + public static void main(String[] args) throws Exception { + Class system = Class.forName("java.lang.System"); + Field out = system.getDeclaredField("out"); + Class output = Class.forName("java.lang.System$Output"); + Method println = output.getDeclaredMethod("println", String.class); + + println.invoke(out.get(null), "Hello, World!"); + } +}