From 9dc8b0529d36ecc4eda3f40581ba9c09cb24cfd5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 Jun 2007 19:39:49 -0600 Subject: [PATCH] snapshot --- src/system.h | 11 ++ src/types.def | 7 + src/vm.cpp | 368 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 316 insertions(+), 70 deletions(-) diff --git a/src/system.h b/src/system.h index 9441fb1a73..a33b0ead78 100644 --- a/src/system.h +++ b/src/system.h @@ -27,6 +27,13 @@ class System { virtual void dispose() = 0; }; + class Library { + public: + virtual ~Library() { } + virtual void* resolve(const char* function) = 0; + virtual Library* next() = 0; + }; + virtual ~System() { } virtual bool success(Status) = 0; @@ -34,6 +41,10 @@ class System { virtual void free(const void*) = 0; virtual Status start(Thread*) = 0; virtual Status make(Monitor**) = 0; + virtual uint64_t call(void* function, unsigned argumentCount, + uint32_t* argumentTable, uint8_t* argumentSizeTable, + unsigned returnSize); + virtual Status load(Library**, const char* name, Library* next); virtual void abort() = 0; void* allocate(unsigned size) { diff --git a/src/types.def b/src/types.def index 39ff95df07..1bfe4990a5 100644 --- a/src/types.def +++ b/src/types.def @@ -18,6 +18,7 @@ (type field (uint16_t flags) (uint16_t offset) + (uint8_t code) (object name) (object spec) (object class)) @@ -31,6 +32,12 @@ (object class) (object code)) +(type nativeMethodData + (void* pointer) + (uint16_t argumentTableSize) + (uint8_t returnCode) + (array uint8_t parameterCodes)) + (pod exceptionHandler (uint16_t start) (uint16_t end) diff --git a/src/vm.cpp b/src/vm.cpp index d2ee6d535a..3c1fbaadbd 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -20,11 +20,14 @@ static const bool Debug = true; class Thread; +void (*Initializer)(Thread*, object); + void assert(Thread*, bool); object resolveClass(Thread*, object); object allocate(Thread*, unsigned); object& arrayBodyUnsafe(Thread*, object, unsigned); void set(Thread*, object&, object); +object bootstrapInitializers(Thread*); object& objectClass(object o) @@ -32,6 +35,18 @@ objectClass(object o) return cast(o, 0); } +enum FieldCode { + ByteField, + CharField, + DoubleField, + FloatField, + IntField, + LongField, + ShortField, + BooleanField, + ObjectField +}; + class Machine { public: enum { @@ -250,9 +265,11 @@ Thread::Thread(Machine* m): object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType); set(t, objectClass(intArrayClass), classClass); + m->unsafe = false; + m->classMap = makeHashMap(this, 0, 0); - m->unsafe = false; + m->bootstrapInitializers = bootstrapInitializers(this); } } @@ -725,64 +742,161 @@ isLongOrDouble(Thread* t, object o) or objectClass(o) == arrayBody(t, t->vm->types, Machine::DoubleType); } -inline object -getField(Thread* t, object instance, object field) +unsigned +fieldCode(unsigned javaCode) { - switch (byteArrayBody(t, fieldSpec(t, field), 0)) { + switch (javaCode) { case 'B': - return makeByte(t, cast(instance, fieldOffset(t, field))); + return ByteField; case 'C': - return makeChar(t, cast(instance, fieldOffset(t, field))); + return CharField; case 'D': - return makeDouble(t, cast(instance, fieldOffset(t, field))); + return DoubleField; case 'F': - return makeFloat(t, cast(instance, fieldOffset(t, field))); + return FloatField; case 'I': - return makeInt(t, cast(instance, fieldOffset(t, field))); + return IntField; case 'J': - return makeLong(t, cast(instance, fieldOffset(t, field))); + return LongField; case 'S': - return makeShort(t, cast(instance, fieldOffset(t, field))); + return ShortField; case 'Z': - return makeBoolean(t, cast(instance, fieldOffset(t, field))); + return BooleanField; case 'L': case '[': + return ObjectField; + + default: abort(t); + } +} + +uint64_t +primitiveValue(Thread* t, unsigned code, object o) +{ + switch (code) { + case ByteField: + return byteValue(t, o); + case CharField: + return charValue(t, o); + case DoubleField: + return doubleValue(t, o); + case FloatField: + return floatValue(t, o); + case IntField: + return intValue(t, o); + case LongField: + return longValue(t, o); + case ShortField: + return shortValue(t, o); + case BooleanField: + return booleanValue(t, o); + + default: abort(t); + } +} + +object +makePrimitive(Thread* t, unsigned code, uint64_t value) +{ + switch (code) { + case ByteField: + return makeByte(t, value); + case CharField: + return makeChar(t, value); + case DoubleField: + return makeDouble(t, value); + case FloatField: + return makeFloat(t, value); + case IntField: + return makeInt(t, value); + case LongField: + return makeLong(t, value); + case ShortField: + return makeShort(t, value); + case BooleanField: + return makeBoolean(t, value); + + default: abort(t); + } +} + +unsigned +primitiveSize(unsigned code) +{ + switch (code) { + case ByteField: + case BooleanField: + return 1; + case CharField: + case ShortField: + return 2; + case DoubleField: + case LongField: + return 8; + case FloatField: + case IntField: + return 4; + + default: abort(t); + } +} + +object +getField(Thread* t, object instance, object field) +{ + switch (fieldCode(t, field)) { + case ByteField: + return makeByte(t, cast(instance, fieldOffset(t, field))); + case CharField: + return makeChar(t, cast(instance, fieldOffset(t, field))); + case DoubleField: + return makeDouble(t, cast(instance, fieldOffset(t, field))); + case FloatField: + return makeFloat(t, cast(instance, fieldOffset(t, field))); + case IntField: + return makeInt(t, cast(instance, fieldOffset(t, field))); + case LongField: + return makeLong(t, cast(instance, fieldOffset(t, field))); + case ShortField: + return makeShort(t, cast(instance, fieldOffset(t, field))); + case BooleanField: + return makeBoolean(t, cast(instance, fieldOffset(t, field))); + case ObjectField: return cast(instance, fieldOffset(t, field)); default: abort(t); } } -inline void +void setField(Thread* t, object o, object field, object value) { - switch (byteArrayBody(t, fieldSpec(t, field), 0)) { - case 'B': + switch (fieldCode(t, field)) { + case ByteField: cast(o, fieldOffset(t, field)) = byteValue(t, value); break; - case 'C': + case CharField: cast(o, fieldOffset(t, field)) = charValue(t, value); break; - case 'D': + case DoubleField: cast(o, fieldOffset(t, field)) = doubleValue(t, value); break; - case 'F': + case FloatField: cast(o, fieldOffset(t, field)) = floatValue(t, value); break; - case 'I': + case IntField: cast(o, fieldOffset(t, field)) = intValue(t, value); break; - case 'J': + case LongField: cast(o, fieldOffset(t, field)) = longValue(t, value); break; - case 'S': + case ShortField: cast(o, fieldOffset(t, field)) = shortValue(t, value); break; - case 'Z': + case BooleanField: cast(o, fieldOffset(t, field)) = booleanValue(t, value); break; - case 'L': - case '[': + case ObjectField: set(t, cast(o, fieldOffset(t, field)), value); default: abort(t); @@ -1277,40 +1391,14 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) set(t, classInterfaceTable(t, class_), interfaceTable); } -bool -isReferenceField(Thread* t, object field) -{ - switch (byteArrayBody(t, fieldSpec(t, field), 0)) { - case 'L': - case '[': - return true; - - default: - return false; - } -} - -unsigned +inline unsigned fieldSize(Thread* t, object field) { - switch (byteArrayBody(t, fieldSpec(t, field), 0)) { - case 'B': - return 1; - case 'C': - case 'S': - case 'Z': - return 2; - case 'D': - case 'J': - return 8; - case 'F': - case 'I': - return 4; - case 'L': - case '[': + unsigned code = fieldCode(t, field); + if (code == ObjectField) { return BytesPerWord; - - default: abort(t); + } else { + return primitiveSize(code); } } @@ -1343,18 +1431,20 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) s.skip(s.read4()); } - object value = makeField(t, - flags, - 0, // offset - arrayBody(t, pool, name - 1), - arrayBody(t, pool, spec - 1), - class_); + object value = makeField + (t, + flags, + 0, // offset + fieldCode(byteArrayBody(t, arrayBody(t, pool, spec - 1), 0)), + arrayBody(t, pool, name - 1), + arrayBody(t, pool, spec - 1), + class_); if (flags & ACC_STATIC) { fieldOffset(t, value) = staticOffset++; } else { unsigned excess = memberOffset % BytesPerWord; - if (excess and isReferenceField(t, value)) { + if (excess and fieldCode(t, value) == ObjectField) { memberOffset += BytesPerWord - excess; } @@ -1385,7 +1475,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) if (fieldTable) { for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) { object field = arrayBody(t, fieldTable, i); - if (isReferenceField(t, field)) { + if (fieldCode(t, field) == ObjectField) { unsigned index = fieldOffset(t, field) / BytesPerWord; intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32); sawReferenceField = true; @@ -1682,6 +1772,12 @@ resolveClass(Thread* t, object spec) PROTECT(t, class_); + object initializer = hashMapFind + (t, t->vm->bootstrapInitializers, spec, byteArrayHash, byteArrayEqual); + if (initializer) { + static_cast(pointerValue(t, initializer))(t, class_); + } + hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash); } else { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); @@ -1752,6 +1848,89 @@ resolveMethod(Thread* t, object pool, unsigned index) return resolve(t, pool, index, findMethodInClass); } +inline object +resolveNativeMethodData(Thread* t, object method) +{ + if (objectClass(methodCode(t, method)) + == arrayBody(t, t->vm->types, Machine::ByteArrayType)) + { + 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 + parameterCount, + 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(*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(code), 4); + ++ s; + break; + } + } + + nativeMethodDataArgumentTableSize(t, data) = argumentTableSize; + nativeMethodReturnCode(t, data) = fieldCode(s[1]); + + set(t, methodCode(t, method), data); + return data; + } + } + + return 0; + } else { + return methodCode(t, method); + } +} + +void +bsiVM(Thread* t, object class_) +{ + // todo +} + +object +bootstrapInitializers(Thread* t) +{ + object map = makeHashMap(t, 0, 0); + PROTECT(t, map); + object key = 0; + PROTECT(t, key); + object value; + + key = makeByteArray(t, "vm/VM"); + value = makePointer(t, bsiVM); + hashMapInsert(t, map, key, value, hashByteArray); + + return map; +} + object run(Thread* t) { @@ -3119,25 +3298,74 @@ run(Thread* t) exception = makeStackOverflowError(t); goto throw_; } - + + unsigned base = sp - parameterCount; + if (methodFlags(t, code) & ACC_NATIVE) { - // todo - abort(t); + 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 = makeUnsatifiedLinkError(t, message); + 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); + + if (code == ObjectField) { + size[i] = 4; + args[offset++] = sp + i + 1; + } else { + size[i] = primitiveSize(code); + uint64_t v = primitiveValue(t, code, stack[sp + i]); + if (size[i] == 8) { + args[offset++] = v & 0xFFFFFFFF; + args[offset++] = v >> 32; + } else { + args[offset++] = v; + } + } + } + + unsigned returnCode = nativeMethodDataReturnCode(t, data); + unsigned returnSize + = (code == ObjectField ? 4 : primitiveSize(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)); + } } else { frameIp(t, frame) = ip; ip = 0; - sp -= parameterCount; - - frame = makeFrame(t, code, frame, 0, sp, + frame = makeFrame(t, code, frame, 0, base, codeMaxLocals(t, methodCode(t, code)), false); code = methodCode(t, code); - memcpy(&frameLocals(t, frame, 0), stack + sp, + memcpy(&frameLocals(t, frame, 0), stack + base, parameterCount * BytesPerWord); memset(&frameLocals(t, frame, 0) + parameterCount, 0, (frameLength(t, frame) - parameterCount) * BytesPerWord); + + sp = base; } goto loop;