diff --git a/input/java/lang/Object.java b/input/java/lang/Object.java index cb9ab57c7f..3879e8d39b 100644 --- a/input/java/lang/Object.java +++ b/input/java/lang/Object.java @@ -1,11 +1,7 @@ package java.lang; -import vm.VM; - public class Object { - protected Object clone() { - return VM.clone(this); - } + protected native Object clone(); public boolean equals(Object o) { return this == o; @@ -13,35 +9,19 @@ public class Object { protected void finalize() { } - public final Class getClass() { - return VM.getClass(this); - } + public native final Class getClass(); - public int hashCode() { - return VM.hashCode(this); - } + public native int hashCode(); - public final void notify() { - VM.notify(this); - } + public native final void notify(); - public final void notifyAll() { - VM.notifyAll(this); - } + public native final void notifyAll(); - public String toString() { - return VM.toString(this); - } + public native String toString(); - public final void wait() { - VM.wait(this); - } + public native final void wait(); - public final void wait(long timeout) { - VM.wait(this, timeout); - } + public native final void wait(long timeout); - public final void wait(long timeout, int nanos) { - VM.wait(this, timeout, nanos); - } + public native final void wait(long timeout, int nanos); } diff --git a/input/vm/VM.java b/input/vm/VM.java deleted file mode 100644 index ff733f2fef..0000000000 --- a/input/vm/VM.java +++ /dev/null @@ -1,21 +0,0 @@ -package vm; - -public class VM { - public static native Object clone(Object o); - - public static native Class getClass(Object o); - - public static native int hashCode(Object o); - - public static native void notify(Object o); - - public static native void notifyAll(Object o); - - public static native String toString(Object o); - - public static native void wait(Object o); - - public static native void wait(Object o, long timeout); - - public static native void wait(Object o, long timeout, int nanos); -} diff --git a/src/main.cpp b/src/main.cpp index 5913c72cf3..6d0a1e28df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" +#include "dlfcn.h" #include "common.h" #include "system.h" #include "heap.h" @@ -30,6 +31,34 @@ class System: public vm::System { vm::System* s; }; + class Library: public vm::System::Library { + public: + Library(vm::System* s, void* p, vm::System::Library* next): + s(s), + p(p), + next_(next) + { } + + virtual void* resolve(const char* function) { + return dlsym(p, function); + } + + virtual vm::System::Library* next() { + return next_; + } + + virtual void dispose() { + if (next_) { + next_->dispose(); + } + s->free(this); + } + + vm::System* s; + void* p; + vm::System::Library* next_; + }; + System(unsigned limit): limit(limit), count(0) { } virtual bool success(Status s) { @@ -81,6 +110,24 @@ class System: public vm::System { return 0; } + virtual uint64_t call(void* function, unsigned argumentCount, + uint32_t* argumentTable, uint8_t* argumentSizeTable, + unsigned returnSize) + { + + } + + virtual Status load(Library** lib, const char* name, Library* next) { + void* p = dlopen(name, RTLD_LAZY); + if (p) { + *lib = new (vm::System::allocate(sizeof(Library))) + Library(this, p, next); + return 0; + } else { + return 1; + } + } + virtual void abort() { ::abort(); } diff --git a/src/types.def b/src/types.def index dbd2e6c0f9..cb2ef259a2 100644 --- a/src/types.def +++ b/src/types.def @@ -33,11 +33,15 @@ (object code)) (type nativeMethodData - (void* pointer) + (void* function) (uint16_t argumentTableSize) (uint8_t returnCode) + (uint8_t builtin) (array uint8_t parameterCodes)) +(type pointer + (void* value)) + (pod exceptionHandler (uint16_t start) (uint16_t end) diff --git a/src/vm.cpp b/src/vm.cpp index f934ffb43b..98a7fc18eb 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -28,6 +28,7 @@ object resolveClass(Thread*, object); object allocate(Thread*, unsigned); object& arrayBodyUnsafe(Thread*, object, unsigned); void set(Thread*, object&, object); +object makeString(Thread*, const char*, ...); object makeByteArray(Thread*, const char*, ...); unsigned objectSize(Thread* t, object o); @@ -38,6 +39,7 @@ objectClass(object o) } enum FieldCode { + VoidField, ByteField, CharField, DoubleField, @@ -76,6 +78,7 @@ class Machine { System::Library* libraries; object classMap; object bootstrapClassMap; + object builtinMap; object types; bool unsafe; }; @@ -222,6 +225,7 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): libraries(0), classMap(0), bootstrapClassMap(0), + builtinMap(0), types(0), unsafe(false) { @@ -429,6 +433,42 @@ listAppend(Thread* t, object list, object value) set(t, listRear(t, list), p); } +inline void +push(Thread* t, object o) +{ + t->stack[(t->sp)++] = o; +} + +inline void +pushSafe(Thread* t, object o) +{ + expect(t, t->sp + 1 < Thread::StackSizeInWords); + push(t, o); +} + +inline object +pop(Thread* t) +{ + return t->stack[--(t->sp)]; +} + +inline object& +top(Thread* t) +{ + return t->stack[t->sp - 1]; +} + +int32_t +builtinToString(Thread* t, int32_t this_) +{ + object o = t->stack[this_ - 1]; + object s = makeString(t, "%s@%p", + &byteArrayBody(t, className(t, objectClass(o)), 0), + o); + pushSafe(t, s); + return t->sp; +} + Thread::Thread(Machine* m): vm(m), next(0), @@ -463,10 +503,29 @@ Thread::Thread(Machine* m): m->unsafe = false; - m->classMap = makeHashMap(this, 0, 0); m->bootstrapClassMap = makeHashMap(this, 0, 0); #include "type-java-initializations.cpp" + + m->classMap = makeHashMap(this, 0, 0); + m->builtinMap = makeHashMap(this, 0, 0); + + struct { + const char* key; + void* value; + } builtins[] = { + { "Java_java_lang_Object_toString", + reinterpret_cast(builtinToString) }, + { 0, 0 } + }; + + for (unsigned i = 0; builtins[i].key; ++i) { + object key = makeByteArray(t, builtins[i].key); + PROTECT(t, key); + object value = makePointer(t, builtins[i].value); + + hashMapInsert(t, m->builtinMap, key, value, byteArrayHash); + } } } @@ -524,6 +583,7 @@ collect(Machine* m, Heap::CollectionType type) virtual void visitRoots(Heap::Visitor* v) { v->visit(&(m->classMap)); v->visit(&(m->bootstrapClassMap)); + v->visit(&(m->builtinMap)); v->visit(&(m->types)); for (Thread* t = m->rootThread; t; t = t->next) { @@ -792,24 +852,6 @@ set(Thread* t, object& target, object value) } } -inline void -push(Thread* t, object o) -{ - t->stack[(t->sp)++] = o; -} - -inline object -pop(Thread* t) -{ - return t->stack[--(t->sp)]; -} - -inline object& -top(Thread* t) -{ - return t->stack[t->sp - 1]; -} - inline object make(Thread* t, object class_) { @@ -1586,9 +1628,23 @@ parameterCount(Thread* t, object spec) } object -makeJNIName(Thread* t, object method, bool decorate) +makeJNIName(Thread* t, object method, bool /*decorate*/) { - // todo + object name = makeByteArray + (t, "Java_%s_%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0)); + + for (unsigned i = 0; i < byteArrayLength(t, name) - 1; ++i) { + switch (byteArrayBody(t, name, i)) { + case '/': + byteArrayBody(t, name, i) = '_'; + break; + } + } + + // todo: decorate and translate as needed + return name; } void @@ -1648,15 +1704,21 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) } } - object method = makeMethod - (t, - flags, - 0, // offset - parameterCount(t, arrayBody(t, pool, spec - 1)), - arrayBody(t, pool, name - 1), - arrayBody(t, pool, spec - 1), - class_, - code); + unsigned parameterCount = ::parameterCount + (t, arrayBody(t, pool, spec - 1)); + + if ((flags & ACC_STATIC) == 0) { + ++ parameterCount; + } + + object method = makeMethod(t, + flags, + 0, // offset + parameterCount, + arrayBody(t, pool, name - 1), + arrayBody(t, pool, spec - 1), + class_, + code); PROTECT(t, method); if (flags & ACC_STATIC) { @@ -1938,67 +2000,179 @@ resolveMethod(Thread* t, object pool, unsigned index) return resolve(t, pool, index, findMethodInClass); } +object +makeNativeMethodData(Thread* t, object method, void* function, bool builtin) +{ + PROTECT(t, method); + + object data = makeNativeMethodData(t, + function, + 0, // argument table size + 0, // return code, + builtin, + methodParameterCount(t, method), + false); + + unsigned argumentTableSize = sizeof(void*) / 4; + unsigned index = 0; + + if ((methodFlags(t, method) & ACC_STATIC) == 0) { + nativeMethodDataParameterCodes(t, data, index++) = ObjectField; + argumentTableSize += 1; + } + + const char* s = reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0)); + ++ s; // skip '(' + while (*s and *s != ')') { + unsigned code = fieldCode(t, *s); + nativeMethodDataParameterCodes(t, data, index++) = code; + + switch (*s) { + case 'L': + argumentTableSize += 1; + while (*s and *s != ';') ++ s; + ++ s; + break; + + case '[': + argumentTableSize += 1; + while (*s == '[') ++ s; + break; + + default: + argumentTableSize += divide(primitiveSize(t, code), 4); + ++ s; + break; + } + } + + nativeMethodDataArgumentTableSize(t, data) = argumentTableSize; + nativeMethodDataReturnCode(t, data) = fieldCode(t, s[1]); + + return data; +} + inline object resolveNativeMethodData(Thread* t, object method) { if (objectClass(methodCode(t, method)) == arrayBody(t, t->vm->types, Machine::ByteArrayType)) { + object data = 0; for (System::Library* lib = t->vm->libraries; lib; lib = lib->next()) { void* p = lib->resolve(reinterpret_cast (&byteArrayBody(t, methodCode(t, method), 0))); if (p) { PROTECT(t, method); - - object data = makeNativeMethodData(t, - p, - 0, // argument table size - 0, // return code - methodParameterCount(t, method), - false); - - unsigned argumentTableSize = 0; - unsigned index = 0; - const char* s = reinterpret_cast - (&byteArrayBody(t, methodSpec(t, method), 0)); - ++ s; // skip '(' - while (*s and *s != ')') { - unsigned code = fieldCode(t, *s); - nativeMethodDataParameterCodes(t, data, index++) = code; - - switch (*s) { - case 'L': - argumentTableSize += 1; - while (*s and *s != ';') ++ s; - ++ s; - break; - - case '[': - argumentTableSize += 1; - while (*s == '[') ++ s; - break; - - default: - argumentTableSize += divide(primitiveSize(t, code), 4); - ++ s; - break; - } - } - - nativeMethodDataArgumentTableSize(t, data) = argumentTableSize; - nativeMethodDataReturnCode(t, data) = fieldCode(t, s[1]); - - set(t, methodCode(t, method), data); - return data; + data = makeNativeMethodData(t, method, p, false); + break; } } - return 0; + if (data == 0) { + object p = hashMapFind(t, t->vm->builtinMap, methodCode(t, method), + byteArrayHash, byteArrayEqual); + if (p) { + PROTECT(t, method); + data = makeNativeMethodData(t, method, pointerValue(t, p), true); + } + } + + if (data) { + set(t, methodCode(t, method), data); + } + return data; } else { return methodCode(t, method); } } +inline object +invokeNative(Thread* t, object method) +{ + object data = resolveNativeMethodData(t, method); + if (UNLIKELY(data == 0)) { + object message = makeString + (t, "%s.%s:%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + t->exception = makeUnsatisfiedLinkError(t, message); + return 0; + } + + unsigned parameterCount = methodParameterCount(t, method); + + uint32_t args[nativeMethodDataArgumentTableSize(t, data)]; + uint8_t sizes[parameterCount + 1]; + unsigned offset = 0; + + switch (sizeof(uintptr_t)) { + case 4: { + sizes[0] = 4; + args[offset++] = reinterpret_cast(t); + } break; + + case 8: { + sizes[0] = 8; + uint64_t v = reinterpret_cast(t); + args[offset++] = static_cast(v >> 32); + args[offset++] = static_cast(v & 0xFFFFFFFF); + } break; + + default: + abort(t); + } + + for (unsigned i = 0; i < parameterCount; ++i) { + unsigned code = nativeMethodDataParameterCodes(t, data, i); + + if (code == ObjectField) { + sizes[i + 1] = 4; + args[offset++] = t->sp + i + 1; + } else { + sizes[i + 1] = primitiveSize(t, code); + uint64_t v = primitiveValue(t, code, t->stack[t->sp + i]); + if (sizes[i + 1] == 8) { + args[offset++] = static_cast(v >> 32); + args[offset++] = static_cast(v & 0xFFFFFFFF); + } else { + args[offset++] = v; + } + } + } + + unsigned returnCode = nativeMethodDataReturnCode(t, data); + unsigned returnSize + = (returnCode == ObjectField ? 4 : primitiveSize(t, returnCode)); + + void* function = nativeMethodDataFunction(t, data); + + bool builtin = nativeMethodDataBuiltin(t, data); + if (not builtin) { + enter(t, Thread::IdleState); + } + + uint64_t rv = t->vm->system->call(function, + parameterCount, + args, + sizes, + returnSize); + + if (not builtin) { + enter(t, Thread::ActiveState); + } + + if (UNLIKELY(t->exception) or returnCode == VoidField) { + return 0; + } else if (returnCode == ObjectField) { + return (rv == 0 ? 0 : t->stack[rv - 1]); + } else { + return makePrimitive(t, returnCode, rv); + } +} + object run(Thread* t) { @@ -2008,7 +2182,6 @@ run(Thread* t) object& frame = t->frame; object& exception = t->exception; object* stack = t->stack; - unsigned parameterCount = 0; if (UNLIKELY(exception)) goto throw_; @@ -2427,7 +2600,6 @@ run(Thread* t) set(t, classInitializer(t, fieldClass(t, field)), 0); code = clinit; ip -= 3; - parameterCount = 0; goto invoke; } @@ -2800,7 +2972,7 @@ run(Thread* t) object method = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - parameterCount = methodParameterCount(t, method); + unsigned parameterCount = methodParameterCount(t, method); if (LIKELY(stack[sp - parameterCount])) { code = findInterfaceMethod(t, method, stack[sp - parameterCount]); if (UNLIKELY(exception)) goto throw_; @@ -2820,7 +2992,7 @@ run(Thread* t) object method = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - parameterCount = methodParameterCount(t, method); + unsigned parameterCount = methodParameterCount(t, method); if (LIKELY(stack[sp - parameterCount])) { object class_ = methodClass(t, frameMethod(t, t->frame)); if (isSpecialMethod(t, method, class_)) { @@ -2850,11 +3022,9 @@ run(Thread* t) set(t, classInitializer(t, methodClass(t, method)), 0); code = clinit; ip -= 3; - parameterCount = 0; goto invoke; } - parameterCount = methodParameterCount(t, method); code = method; } goto invoke; @@ -2866,7 +3036,7 @@ run(Thread* t) object method = resolveMethod(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - parameterCount = methodParameterCount(t, method); + unsigned parameterCount = methodParameterCount(t, method); if (LIKELY(stack[sp - parameterCount])) { code = findVirtualMethod(t, method, stack[sp - parameterCount]); if (UNLIKELY(exception)) goto throw_; @@ -3122,7 +3292,6 @@ run(Thread* t) set(t, classInitializer(t, class_), 0); code = clinit; ip -= 3; - parameterCount = 0; goto invoke; } @@ -3228,7 +3397,6 @@ run(Thread* t) set(t, classInitializer(t, fieldClass(t, field)), 0); code = clinit; ip -= 3; - parameterCount = 0; goto invoke; } @@ -3359,65 +3527,27 @@ run(Thread* t) default: abort(t); } - invoke: { - if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + sp - parameterCount + invoke: { + unsigned parameterCount = methodParameterCount(t, code); + unsigned base = sp - parameterCount; + + if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + base > Thread::StackSizeInWords)) { exception = makeStackOverflowError(t); goto throw_; } - - unsigned base = sp - parameterCount; if (methodFlags(t, code) & ACC_NATIVE) { - object data = resolveNativeMethodData(t, code); - if (UNLIKELY(data == 0)) { - object message = makeString - (t, "%s.%s:%s", - &byteArrayBody(t, className(t, methodClass(t, code)), 0), - &byteArrayBody(t, methodName(t, code), 0), - &byteArrayBody(t, methodSpec(t, code), 0)); - exception = makeUnsatisfiedLinkError(t, message); + object r = invokeNative(t, code); + + if (UNLIKELY(exception)) { goto throw_; } - uint32_t args[nativeMethodDataArgumentTableSize(t, data)]; - uint8_t sizes[parameterCount]; - unsigned offset = 0; - for (unsigned i = 0; i < parameterCount; ++i) { - unsigned code = nativeMethodDataParameterCodes(t, data, i); - - if (code == ObjectField) { - sizes[i] = 4; - args[offset++] = sp + i + 1; - } else { - sizes[i] = primitiveSize(t, code); - uint64_t v = primitiveValue(t, code, stack[sp + i]); - if (sizes[i] == 8) { - args[offset++] = static_cast(v & 0xFFFFFFFF); - args[offset++] = static_cast(v >> 32); - } else { - args[offset++] = v; - } - } - } - - unsigned returnCode = nativeMethodDataReturnCode(t, data); - unsigned returnSize - = (returnCode == ObjectField ? 4 : primitiveSize(t, returnCode)); - - uint64_t rv = t->vm->system->call(nativeMethodDataPointer(t, data), - parameterCount, - args, - sizes, - returnSize); - sp = base; - - if (returnCode == ObjectField) { - push(t, (rv == 0 ? 0 : stack[rv - 1])); - } else { - push(t, makePrimitive(t, returnCode, rv)); + if (nativeMethodDataReturnCode(t, methodCode(t, code)) != VoidField) { + push(t, r); } } else { frameIp(t, frame) = ip;