From 2df8a60a782a2b90a1909b65be979cbcb5c4420b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 14 Jul 2007 11:31:01 -0600 Subject: [PATCH] support object arrays of various element types and dimensions; clean up weak hash map support --- classpath/java/lang/Class.java | 3 +- src/builtin.cpp | 31 +- src/machine.cpp | 1234 ++++++++++++++++++++++++++++++-- src/machine.h | 74 +- src/run.cpp | 1049 +-------------------------- src/type-generator.cpp | 2 +- src/types.def | 9 +- 7 files changed, 1274 insertions(+), 1128 deletions(-) diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 48f56acde8..96930813af 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -2,7 +2,8 @@ package java.lang; public final class Class { private short flags; - private short vmFlags; + private byte vmFlags; + private byte arrayDimensions; private short fixedSize; private short arrayElementSize; private int[] objectMask; diff --git a/src/builtin.cpp b/src/builtin.cpp index d73839eb05..1f92bd848a 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -84,28 +84,13 @@ arraycopy(Thread* t, jobject src, jint srcOffset, jobject dst, jint dstOffset, unsigned elementSize = classArrayElementSize(t, objectClass(t, s)); if (LIKELY(elementSize)) { - unsigned offset = 1; - - if (objectClass(t, s) - == arrayBody(t, t->vm->types, Machine::ObjectArrayType)) - { - if (LIKELY(objectArrayElementClass(t, s) - == objectArrayElementClass(t, d))) - { - offset = 2; - } else { - t->exception = makeArrayStoreException(t); - return; - } - } - - intptr_t sl = cast(s, offset * BytesPerWord); - intptr_t dl = cast(d, offset * BytesPerWord); + intptr_t sl = cast(s, BytesPerWord); + intptr_t dl = cast(d, BytesPerWord); if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and dstOffset >= 0 and dstOffset + length <= dl)) { - uint8_t* sbody = &cast(s, (offset + 1) * BytesPerWord); - uint8_t* dbody = &cast(d, (offset + 1) * BytesPerWord); + uint8_t* sbody = &cast(s, 2 * BytesPerWord); + uint8_t* dbody = &cast(d, 2 * BytesPerWord); memcpy(dbody + (dstOffset * elementSize), sbody + (srcOffset * elementSize), length * elementSize); @@ -121,7 +106,7 @@ arraycopy(Thread* t, jobject src, jint srcOffset, jobject dst, jint dstOffset, t->exception = makeArrayStoreException(t); } -jarray +jobject trace(Thread* t, jint skipCount) { int frame = t->frame; @@ -144,6 +129,12 @@ trace(Thread* t, jint skipCount) return pushReference(t, makeTrace(t, frame)); } +jarray +resolveTrace(Thread* t, object trace) +{ + // todo +} + void start(Thread* t, jobject this_) { diff --git a/src/machine.cpp b/src/machine.cpp index 3ebd65e958..075246c537 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1,6 +1,8 @@ #include "jnienv.h" #include "builtin.h" #include "machine.h" +#include "stream.h" +#include "constants.h" using namespace vm; @@ -442,6 +444,958 @@ makeByteArray(Thread* t, const char* format, va_list a) return s; } +unsigned +mangledSize(int8_t c) +{ + switch (c) { + case '_': + case ';': + case '[': + return 2; + + case '$': + return 6; + + default: + return 1; + } +} + +unsigned +mangle(int8_t c, int8_t* dst) +{ + switch (c) { + case '/': + dst[0] = '_'; + return 1; + + case '_': + dst[0] = '_'; + dst[1] = '1'; + return 2; + + case ';': + dst[0] = '_'; + dst[1] = '2'; + return 2; + + case '[': + dst[0] = '_'; + dst[1] = '3'; + return 2; + + case '$': + memcpy(dst, "_00024", 6); + return 6; + + default: + dst[0] = c; + return 1; + } +} + +object +makeJNIName(Thread* t, object method, bool decorate) +{ + unsigned size = 5; + object className = ::className(t, methodClass(t, method)); + PROTECT(t, className); + for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { + size += mangledSize(byteArrayBody(t, className, i)); + } + + ++ size; + + object methodName = ::methodName(t, method); + PROTECT(t, methodName); + for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { + size += mangledSize(byteArrayBody(t, methodName, i)); + } + + object methodSpec = ::methodSpec(t, method); + PROTECT(t, methodSpec); + if (decorate) { + size += 2; + for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 + and byteArrayBody(t, methodSpec, i) != ')'; ++i) + { + size += mangledSize(byteArrayBody(t, methodSpec, i)); + } + } + + object name = makeByteArray(t, size + 1, false); + unsigned index = 0; + + memcpy(&byteArrayBody(t, name, index), "Java_", 5); + index += 5; + + for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { + index += mangle(byteArrayBody(t, className, i), + &byteArrayBody(t, name, index)); + } + + byteArrayBody(t, name, index++) = '_'; + + for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { + index += mangle(byteArrayBody(t, methodName, i), + &byteArrayBody(t, name, index)); + } + + if (decorate) { + byteArrayBody(t, name, index++) = '_'; + byteArrayBody(t, name, index++) = '_'; + for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 + and byteArrayBody(t, methodSpec, i) != ')'; ++i) + { + index += mangle(byteArrayBody(t, className, i), + &byteArrayBody(t, name, index)); + } + } + + byteArrayBody(t, name, index++) = 0; + + assert(t, index == size + 1); + + return name; +} + +unsigned +parameterFootprint(Thread* t, object spec) +{ + unsigned footprint = 0; + const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); + ++ s; // skip '(' + while (*s and *s != ')') { + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + case '[': + while (*s == '[') ++ s; + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + default: + ++ s; + break; + } + break; + + case 'J': + case 'D': + ++ s; + ++ footprint; + break; + + default: + ++ s; + break; + } + + ++ footprint; + } + + return footprint; +} + +unsigned +parameterCount(Thread* t, object spec) +{ + unsigned count = 0; + const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); + ++ s; // skip '(' + while (*s and *s != ')') { + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + case '[': + while (*s == '[') ++ s; + switch (*s) { + case 'L': + while (*s and *s != ';') ++ s; + ++ s; + break; + + default: + ++ s; + break; + } + break; + + default: + ++ s; + break; + } + + ++ count; + } + + return count; +} + +object +parsePool(Thread* t, Stream& s) +{ + unsigned poolCount = s.read2() - 1; + object pool = makeArray(t, poolCount, true); + + PROTECT(t, pool); + + for (unsigned i = 0; i < poolCount; ++i) { + unsigned c = s.read1(); + + switch (c) { + case CONSTANT_Integer: { + object value = makeInt(t, s.read4()); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_Float: { + object value = makeFloat(t, s.readFloat()); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_Long: { + object value = makeLong(t, s.read8()); + set(t, arrayBody(t, pool, i), value); + ++i; + } break; + + case CONSTANT_Double: { + object value = makeLong(t, s.readDouble()); + set(t, arrayBody(t, pool, i), value); + ++i; + } break; + + case CONSTANT_Utf8: { + unsigned length = s.read2(); + object value = makeByteArray(t, length + 1, false); + s.read(reinterpret_cast(&byteArrayBody(t, value, 0)), length); + byteArrayBody(t, value, length) = 0; + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_Class: { + object value = makeIntArray(t, 2, false); + intArrayBody(t, value, 0) = c; + intArrayBody(t, value, 1) = s.read2(); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_String: { + object value = makeIntArray(t, 2, false); + intArrayBody(t, value, 0) = c; + intArrayBody(t, value, 1) = s.read2(); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_NameAndType: { + object value = makeIntArray(t, 3, false); + intArrayBody(t, value, 0) = c; + intArrayBody(t, value, 1) = s.read2(); + intArrayBody(t, value, 2) = s.read2(); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + object value = makeIntArray(t, 3, false); + intArrayBody(t, value, 0) = c; + intArrayBody(t, value, 1) = s.read2(); + intArrayBody(t, value, 2) = s.read2(); + set(t, arrayBody(t, pool, i), value); + } break; + + default: abort(t); + } + } + + for (unsigned i = 0; i < poolCount; ++i) { + object o = arrayBody(t, pool, i); + if (o and objectClass(t, o) + == arrayBody(t, t->vm->types, Machine::IntArrayType)) + { + switch (intArrayBody(t, o, 0)) { + case CONSTANT_Class: { + set(t, arrayBody(t, pool, i), + arrayBody(t, pool, intArrayBody(t, o, 1) - 1)); + } break; + + case CONSTANT_String: { + object bytes = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); + object value = makeString + (t, bytes, 0, byteArrayLength(t, bytes) - 1, 0); + set(t, arrayBody(t, pool, i), value); + } break; + + case CONSTANT_NameAndType: { + object name = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); + object type = arrayBody(t, pool, intArrayBody(t, o, 2) - 1); + object value = makePair(t, name, type); + set(t, arrayBody(t, pool, i), value); + } break; + } + } + } + + for (unsigned i = 0; i < poolCount; ++i) { + object o = arrayBody(t, pool, i); + if (o and objectClass(t, o) + == arrayBody(t, t->vm->types, Machine::IntArrayType)) + { + switch (intArrayBody(t, o, 0)) { + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: { + object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); + object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1); + object value = makeReference + (t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); + set(t, arrayBody(t, pool, i), value); + } break; + } + } + } + + return pool; +} + +void +addInterfaces(Thread* t, object class_, object map) +{ + object table = classInterfaceTable(t, class_); + if (table) { + unsigned increment = 2; + if (classFlags(t, class_) & ACC_INTERFACE) { + increment = 1; + } + + PROTECT(t, map); + PROTECT(t, table); + + for (unsigned i = 0; i < arrayLength(t, table); i += increment) { + object interface = arrayBody(t, table, i); + object name = className(t, interface); + hashMapInsertMaybe(t, map, name, interface, byteArrayHash, + byteArrayEqual); + } + } +} + +void +parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) +{ + PROTECT(t, class_); + PROTECT(t, pool); + + object map = makeHashMap(t, NormalMap, 0, 0); + PROTECT(t, map); + + if (classSuper(t, class_)) { + addInterfaces(t, classSuper(t, class_), map); + } + + unsigned count = s.read2(); + for (unsigned i = 0; i < count; ++i) { + object name = arrayBody(t, pool, s.read2() - 1); + PROTECT(t, name); + + object interface = resolveClass(t, name); + PROTECT(t, interface); + + hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual); + + addInterfaces(t, interface, map); + } + + object interfaceTable = 0; + if (hashMapSize(t, map)) { + unsigned length = hashMapSize(t, map) ; + if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { + length *= 2; + } + interfaceTable = makeArray(t, length, true); + PROTECT(t, interfaceTable); + + unsigned i = 0; + object it = hashMapIterator(t, map); + PROTECT(t, it); + + for (; it; it = hashMapIteratorNext(t, it)) { + object interface = resolveClass + (t, tripleFirst(t, hashMapIteratorNode(t, it))); + if (UNLIKELY(t->exception)) return; + + set(t, arrayBody(t, interfaceTable, i++), interface); + + if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { + // we'll fill in this table in parseMethodTable(): + object vtable = makeArray + (t, arrayLength(t, classVirtualTable(t, interface)), true); + + set(t, arrayBody(t, interfaceTable, i++), vtable); + } + } + } + + set(t, classInterfaceTable(t, class_), interfaceTable); +} + +void +parseFieldTable(Thread* t, Stream& s, object class_, object pool) +{ + PROTECT(t, class_); + PROTECT(t, pool); + + unsigned memberOffset = BytesPerWord; + if (classSuper(t, class_)) { + memberOffset = classFixedSize(t, classSuper(t, class_)); + } + + unsigned count = s.read2(); + if (count) { + unsigned staticOffset = 0; + + object fieldTable = makeArray(t, count, true); + PROTECT(t, fieldTable); + + for (unsigned i = 0; i < count; ++i) { + unsigned flags = s.read2(); + unsigned name = s.read2(); + unsigned spec = s.read2(); + + unsigned attributeCount = s.read2(); + for (unsigned j = 0; j < attributeCount; ++j) { + s.read2(); + s.skip(s.read4()); + } + + object field = makeField + (t, + flags, + 0, // offset + fieldCode(t, 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, field) = staticOffset++; + } else { + unsigned excess = memberOffset % BytesPerWord; + if (excess and fieldCode(t, field) == ObjectField) { + memberOffset += BytesPerWord - excess; + } + + fieldOffset(t, field) = memberOffset; + memberOffset += fieldSize(t, field); + } + + set(t, arrayBody(t, fieldTable, i), field); + } + + set(t, classFieldTable(t, class_), fieldTable); + + if (staticOffset) { + object staticTable = makeArray(t, staticOffset, true); + + set(t, classStaticTable(t, class_), staticTable); + } + } + + classFixedSize(t, class_) = pad(memberOffset); + + if (classSuper(t, class_) + and memberOffset == classFixedSize(t, classSuper(t, class_))) + { + set(t, classObjectMask(t, class_), + classObjectMask(t, classSuper(t, class_))); + } else { + object mask = makeIntArray + (t, divide(classFixedSize(t, class_), BitsPerWord * BytesPerWord), true); + intArrayBody(t, mask, 0) = 1; + + bool sawReferenceField = false; + for (object c = class_; c; c = classSuper(t, c)) { + object fieldTable = classFieldTable(t, c); + if (fieldTable) { + for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) { + object field = arrayBody(t, fieldTable, i); + if (fieldCode(t, field) == ObjectField) { + unsigned index = fieldOffset(t, field) / BytesPerWord; + intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32); + sawReferenceField = true; + } + } + } + } + + if (sawReferenceField) { + set(t, classObjectMask(t, class_), mask); + } + } +} + +object +parseCode(Thread* t, Stream& s, object pool) +{ + unsigned maxStack = s.read2(); + unsigned maxLocals = s.read2(); + unsigned length = s.read4(); + + object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false); + s.read(&codeBody(t, code, 0), length); + + unsigned ehtLength = s.read2(); + if (ehtLength) { + PROTECT(t, code); + + object eht = makeExceptionHandlerTable(t, ehtLength, false); + for (unsigned i = 0; i < ehtLength; ++i) { + ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); + exceptionHandlerStart(eh) = s.read2(); + exceptionHandlerEnd(eh) = s.read2(); + exceptionHandlerIp(eh) = s.read2(); + exceptionHandlerCatchType(eh) = s.read2(); + } + + set(t, codeExceptionHandlerTable(t, code), eht); + } + + unsigned attributeCount = s.read2(); + for (unsigned j = 0; j < attributeCount; ++j) { + object name = arrayBody(t, pool, s.read2() - 1); + unsigned length = s.read4(); + + if (strcmp(reinterpret_cast("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; +} + +void +parseMethodTable(Thread* t, Stream& s, object class_, object pool) +{ + PROTECT(t, class_); + PROTECT(t, pool); + + object virtualMap = makeHashMap(t, NormalMap, 0, 0); + PROTECT(t, virtualMap); + + object nativeMap = makeHashMap(t, NormalMap, 0, 0); + PROTECT(t, nativeMap); + + unsigned virtualCount = 0; + unsigned declaredVirtualCount = 0; + + object superVirtualTable = 0; + PROTECT(t, superVirtualTable); + + if (classFlags(t, class_) & ACC_INTERFACE) { + object itable = classInterfaceTable(t, class_); + if (itable) { + for (unsigned i = 0; i < arrayLength(t, itable); ++i) { + object vtable = classVirtualTable(t, arrayBody(t, itable, i)); + for (unsigned j = 0; j < virtualCount; ++j) { + object method = arrayBody(t, vtable, j); + if (hashMapInsertMaybe(t, virtualMap, method, method, methodHash, + methodEqual)) + { + ++ virtualCount; + } + } + } + } + } else { + if (classSuper(t, class_)) { + superVirtualTable = classVirtualTable(t, classSuper(t, class_)); + } + + if (superVirtualTable) { + virtualCount = arrayLength(t, superVirtualTable); + for (unsigned i = 0; i < virtualCount; ++i) { + object method = arrayBody(t, superVirtualTable, i); + hashMapInsert(t, virtualMap, method, method, methodHash); + } + } + } + + object newVirtuals = makeList(t, 0, 0, 0); + PROTECT(t, newVirtuals); + + unsigned count = s.read2(); + if (count) { + object methodTable = makeArray(t, count, true); + PROTECT(t, methodTable); + + for (unsigned i = 0; i < count; ++i) { + unsigned flags = s.read2(); + unsigned name = s.read2(); + unsigned spec = s.read2(); + + object code = 0; + unsigned attributeCount = s.read2(); + for (unsigned j = 0; j < attributeCount; ++j) { + object name = arrayBody(t, pool, s.read2() - 1); + unsigned length = s.read4(); + + if (strcmp(reinterpret_cast("Code"), + &byteArrayBody(t, name, 0)) == 0) + { + code = parseCode(t, s, pool); + } else { + s.skip(length); + } + } + + unsigned parameterCount = ::parameterCount + (t, arrayBody(t, pool, spec - 1)); + + unsigned parameterFootprint = ::parameterFootprint + (t, arrayBody(t, pool, spec - 1)); + + if ((flags & ACC_STATIC) == 0) { + ++ parameterCount; + ++ parameterFootprint; + } + + object method = makeMethod(t, + flags, + 0, // offset + parameterCount, + parameterFootprint, + arrayBody(t, pool, name - 1), + arrayBody(t, pool, spec - 1), + class_, + code); + PROTECT(t, method); + + if (flags & ACC_STATIC) { + if (strcmp(reinterpret_cast(""), + &byteArrayBody(t, methodName(t, method), 0)) == 0) + { + set(t, classInitializer(t, class_), method); + } + } else { + ++ declaredVirtualCount; + + object p = hashMapFindNode + (t, virtualMap, method, methodHash, methodEqual); + + if (p) { + methodOffset(t, method) = methodOffset(t, tripleFirst(t, p)); + + set(t, tripleSecond(t, p), method); + } else { + methodOffset(t, method) = virtualCount++; + + listAppend(t, newVirtuals, method); + + hashMapInsert(t, virtualMap, method, method, methodHash); + } + } + + if (flags & ACC_NATIVE) { + object p = hashMapFindNode + (t, nativeMap, method, methodHash, methodEqual); + + if (p) { + set(t, tripleSecond(t, p), method); + } else { + hashMapInsert(t, virtualMap, method, 0, methodHash); + } + } + + set(t, arrayBody(t, methodTable, i), method); + } + + for (unsigned i = 0; i < count; ++i) { + object method = arrayBody(t, methodTable, i); + + if (methodFlags(t, method) & ACC_NATIVE) { + object overloaded = hashMapFind + (t, nativeMap, method, methodHash, methodEqual); + + object jniName = makeJNIName(t, method, overloaded); + set(t, methodCode(t, method), jniName); + } + } + + set(t, classMethodTable(t, class_), methodTable); + } + + if (declaredVirtualCount == 0) { + // inherit interface table and virtual table from superclass + + set(t, classInterfaceTable(t, class_), + classInterfaceTable(t, classSuper(t, class_))); + + set(t, classVirtualTable(t, class_), superVirtualTable); + } else if (virtualCount) { + // generate class vtable + + unsigned i = 0; + object vtable = makeArray(t, virtualCount, false); + + if (classFlags(t, class_) & ACC_INTERFACE) { + object it = hashMapIterator(t, virtualMap); + + for (; it; it = hashMapIteratorNext(t, it)) { + object method = tripleFirst(t, hashMapIteratorNode(t, it)); + set(t, arrayBody(t, vtable, i++), method); + } + } else { + if (superVirtualTable) { + for (; i < arrayLength(t, superVirtualTable); ++i) { + object method = arrayBody(t, superVirtualTable, i); + method = hashMapFind(t, virtualMap, method, methodHash, methodEqual); + + set(t, arrayBody(t, vtable, i), method); + } + } + + for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) { + set(t, arrayBody(t, vtable, i++), pairFirst(t, p)); + } + } + + set(t, classVirtualTable(t, class_), vtable); + + if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { + // generate interface vtables + + object itable = classInterfaceTable(t, class_); + if (itable) { + PROTECT(t, itable); + + for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { + object ivtable = classVirtualTable(t, arrayBody(t, itable, i)); + object vtable = arrayBody(t, itable, i + 1); + + for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) { + object method = arrayBody(t, ivtable, j); + method = hashMapFind + (t, virtualMap, method, methodHash, methodEqual); + assert(t, method); + + set(t, arrayBody(t, vtable, j), method); + } + } + } + } + } +} + +object +parseClass(Thread* t, const uint8_t* data, unsigned size) +{ + class Client : public Stream::Client { + public: + Client(Thread* t): t(t) { } + + virtual void NO_RETURN handleEOS() { + abort(t); + } + + private: + Thread* t; + } client(t); + + Stream s(&client, data, size); + + uint32_t magic = s.read4(); + assert(t, magic == 0xCAFEBABE); + s.read2(); // minor version + s.read2(); // major version + + object pool = parsePool(t, s); + + unsigned flags = s.read2(); + unsigned name = s.read2(); + + object class_ = makeClass(t, + flags, + 0, // VM flags + 0, // array dimensions + 0, // fixed size + 0, // array size + 0, // object mask + arrayBody(t, pool, name - 1), + 0, // super + 0, // interfaces + 0, // vtable + 0, // fields + 0, // methods + 0, // static table + 0); // initializer + PROTECT(t, class_); + + unsigned super = s.read2(); + if (super) { + object sc = resolveClass(t, arrayBody(t, pool, super - 1)); + if (UNLIKELY(t->exception)) return 0; + + set(t, classSuper(t, class_), sc); + + classVmFlags(t, class_) |= classVmFlags(t, sc); + } + + parseInterfaceTable(t, s, class_, pool); + if (UNLIKELY(t->exception)) return 0; + + parseFieldTable(t, s, class_, pool); + if (UNLIKELY(t->exception)) return 0; + + parseMethodTable(t, s, class_, pool); + if (UNLIKELY(t->exception)) return 0; + + return class_; +} + +void +updateBootstrapClass(Thread* t, object bootstrapClass, object class_) +{ + expect(t, bootstrapClass != class_); + + // verify that the classes have the same layout + expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); + expect(t, classFixedSize(t, bootstrapClass) == classFixedSize(t, class_)); + expect(t, (classObjectMask(t, bootstrapClass) == 0 + and classObjectMask(t, class_) == 0) + or intArrayEqual(t, classObjectMask(t, bootstrapClass), + classObjectMask(t, class_))); + + PROTECT(t, bootstrapClass); + PROTECT(t, class_); + + ENTER(t, Thread::ExclusiveState); + + classVmFlags(t, class_) |= classVmFlags(t, bootstrapClass); + + memcpy(bootstrapClass, + class_, + extendedSize(t, class_, baseSize(t, class_, objectClass(t, class_))) + * BytesPerWord); + + object fieldTable = classFieldTable(t, class_); + if (fieldTable) { + for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) { + set(t, fieldClass(t, arrayBody(t, fieldTable, i)), bootstrapClass); + } + } + + object methodTable = classMethodTable(t, class_); + if (methodTable) { + for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) { + set(t, methodClass(t, arrayBody(t, methodTable, i)), bootstrapClass); + } + } +} + +object +makeArrayClass(Thread* t, unsigned dimensions, object spec, + object elementClass) +{ + return makeClass + (t, + 0, + 0, + dimensions, + 2 * BytesPerWord, + BytesPerWord, + classObjectMask(t, arrayBody(t, t->vm->types, Machine::ArrayType)), + spec, + arrayBody(t, t->vm->types, Machine::JobjectType), + elementClass, + classVirtualTable(t, arrayBody(t, t->vm->types, Machine::JobjectType)), + 0, + 0, + 0, + 0); +} + +object +makeArrayClass(Thread* t, object spec) +{ + PROTECT(t, spec); + + const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); + const char* start = s; + unsigned dimensions = 0; + for (; *s == '['; ++s) ++ dimensions; + + object elementSpec; + switch (*s) { + case 'L': { + ++ s; + const char* elementSpecStart = s; + while (*s and *s != ';') ++ s; + + elementSpec = makeByteArray(t, s - elementSpecStart + 1, false); + memcpy(&byteArrayBody(t, elementSpec, 0), + &byteArrayBody(t, spec, elementSpecStart - start), + s - elementSpecStart); + byteArrayBody(t, elementSpec, s - elementSpecStart) = 0; + } break; + + default: + if (dimensions > 1) { + char c = *s; + elementSpec = makeByteArray(t, 3, false); + byteArrayBody(t, elementSpec, 0) = '['; + byteArrayBody(t, elementSpec, 1) = c; + byteArrayBody(t, elementSpec, 2) = 0; + -- dimensions; + } else { + abort(t); + } + } + + object elementClass = resolveClass(t, elementSpec); + if (UNLIKELY(t->exception)) return 0; + + return makeArrayClass(t, dimensions, spec, elementClass); +} + +void +removeMonitor(Thread* t, object o) +{ + object p = hashMapRemove(t, t->vm->monitorMap, o, objectHash, objectEqual); + + assert(t, p); + + if (DebugMonitors) { + fprintf(stderr, "dispose monitor %p for object %x\n", + static_cast(pointerValue(t, p)), + objectHash(t, o)); + } + + static_cast(pointerValue(t, p))->dispose(); +} + } // namespace namespace vm { @@ -549,16 +1503,16 @@ Thread::Thread(Machine* m, Allocator* allocator, object javaThread, m->unsafe = false; - m->bootstrapClassMap = makeHashMap(this, 0, 0); + m->bootstrapClassMap = makeHashMap(this, NormalMap, 0, 0); #include "type-java-initializations.cpp" classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) |= WeakReferenceFlag; - m->classMap = makeHashMap(this, 0, 0); - m->builtinMap = makeHashMap(this, 0, 0); - m->monitorMap = makeHashMap(this, 0, 0); + m->classMap = makeHashMap(this, NormalMap, 0, 0); + m->builtinMap = makeHashMap(this, NormalMap, 0, 0); + m->monitorMap = makeHashMap(this, WeakMap, 0, 0); builtin::populate(t, m->builtinMap); @@ -795,11 +1749,17 @@ hashMapFindNode(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { + bool weak = hashMapType(t, map) == WeakMap; object array = hashMapArray(t, map); if (array) { unsigned index = hash(t, key) & (arrayLength(t, array) - 1); for (object n = arrayBody(t, array, index); n; n = tripleThird(t, n)) { - if (equal(t, key, tripleFirst(t, n))) { + object k = tripleFirst(t, n); + if (weak) { + k = jreferenceTarget(t, k); + } + + if (equal(t, key, k)) { return n; } } @@ -823,13 +1783,19 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), newArray = makeArray(t, newLength, true); if (oldArray) { + bool weak = hashMapType(t, map) == WeakMap; + for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) { object next; for (object p = arrayBody(t, oldArray, i); p; p = next) { next = tripleThird(t, p); - object key = tripleFirst(t, p); - unsigned index = hash(t, key) & (newLength - 1); + object k = tripleFirst(t, p); + if (weak) { + k = jreferenceTarget(t, k); + } + + unsigned index = hash(t, k) & (newLength - 1); set(t, tripleThird(t, p), arrayBody(t, newArray, index)); set(t, arrayBody(t, newArray, index), p); @@ -842,9 +1808,10 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), } void -hashMapInsert2(Thread* t, object map, object key, object value, uint32_t h, +hashMapInsert(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object)) { + bool weak = hashMapType(t, map) == WeakMap; object array = hashMapArray(t, map); PROTECT(t, array); @@ -859,32 +1826,37 @@ hashMapInsert2(Thread* t, object map, object key, object value, uint32_t h, array = hashMapArray(t, map); } - unsigned index = h & (arrayLength(t, array) - 1); + unsigned index = hash(t, key) & (arrayLength(t, array) - 1); object n = arrayBody(t, array, index); + if (weak) { + PROTECT(t, value); + key = makeWeakReference(t, key, t->vm->weakReferences); + t->vm->weakReferences = key; + } + n = makeTriple(t, key, value, n); set(t, arrayBody(t, array, index), n); } -void -hashMapInsert(Thread* t, object map, object key, object value, - uint32_t (*hash)(Thread*, object)) -{ - hashMapInsert2(t, map, key, value, hash(t, key), hash); -} - object -hashMapRemove2(Thread* t, object map, object key, uint32_t h, - uint32_t (*hash)(Thread*, object), - bool (*equal)(Thread*, object, object)) +hashMapRemove(Thread* t, object map, object key, + uint32_t (*hash)(Thread*, object), + bool (*equal)(Thread*, object, object)) { + bool weak = hashMapType(t, map) == WeakMap; object array = hashMapArray(t, map); object o = 0; if (array) { - unsigned index = h & (arrayLength(t, array) - 1); + unsigned index = hash(t, key) & (arrayLength(t, array) - 1); for (object* n = &arrayBody(t, array, index); *n;) { - if (equal(t, key, tripleFirst(t, *n))) { + object k = tripleFirst(t, *n); + if (weak) { + k = jreferenceTarget(t, k); + } + + if (equal(t, key, k)) { o = tripleSecond(t, *n); set(t, *n, tripleThird(t, *n)); -- hashMapSize(t, map); @@ -901,14 +1873,6 @@ hashMapRemove2(Thread* t, object map, object key, uint32_t h, return o; } -object -hashMapRemove(Thread* t, object map, object key, - uint32_t (*hash)(Thread*, object), - bool (*equal)(Thread*, object, object)) -{ - return hashMapRemove2(t, map, key, hash(t, key), hash, equal); -} - object makeTrace(Thread* t, int frame) { @@ -917,15 +1881,13 @@ makeTrace(Thread* t, int frame) ++ count; } - object trace = makeObjectArray - (t, arrayBody(t, t->vm->types, Machine::StackTraceElementType), - count, true); + object trace = makeArray(t, count, true); PROTECT(t, trace); unsigned index = 0; for (int f = frame; f >= 0; f = frameNext(t, f)) { object e = makeStackTraceElement(t, frameMethod(t, f), frameIp(t, f)); - set(t, objectArrayBody(t, trace, index++), e); + set(t, arrayBody(t, trace, index++), e); } return trace; @@ -981,6 +1943,184 @@ listAppend(Thread* t, object list, object value) set(t, listRear(t, list), p); } +unsigned +fieldCode(Thread* t, unsigned javaCode) +{ + switch (javaCode) { + case 'B': + return ByteField; + case 'C': + return CharField; + case 'D': + return DoubleField; + case 'F': + return FloatField; + case 'I': + return IntField; + case 'J': + return LongField; + case 'S': + return ShortField; + case 'V': + return VoidField; + case 'Z': + return BooleanField; + case 'L': + case '[': + return ObjectField; + + default: abort(t); + } +} + +unsigned +fieldType(Thread* t, unsigned code) +{ + switch (code) { + case VoidField: + return VOID_TYPE; + case ByteField: + case BooleanField: + return INT8_TYPE; + case CharField: + case ShortField: + return INT16_TYPE; + case DoubleField: + return DOUBLE_TYPE; + case FloatField: + return FLOAT_TYPE; + case IntField: + return INT32_TYPE; + case LongField: + return INT64_TYPE; + case ObjectField: + return POINTER_TYPE; + + default: abort(t); + } +} + +unsigned +primitiveSize(Thread* t, unsigned code) +{ + switch (code) { + case VoidField: + return 0; + case ByteField: + case BooleanField: + return 1; + case CharField: + case ShortField: + return 2; + case FloatField: + case IntField: + return 4; + case DoubleField: + case LongField: + return 8; + + default: abort(t); + } +} + +object +resolveClass(Thread* t, object spec) +{ + PROTECT(t, spec); + ACQUIRE(t, t->vm->classLock); + + object class_ = hashMapFind + (t, t->vm->classMap, spec, byteArrayHash, byteArrayEqual); + if (class_ == 0) { + if (byteArrayBody(t, spec, 0) == '[') { + class_ = hashMapFind + (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + + if (class_ == 0) { + class_ = makeArrayClass(t, spec); + } + } else { + ClassFinder::Data* data = t->vm->classFinder->find + (reinterpret_cast(&byteArrayBody(t, spec, 0))); + + if (data) { + if (Verbose) { + 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)); + } + + PROTECT(t, class_); + + object bootstrapClass = hashMapFind + (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + + if (bootstrapClass) { + PROTECT(t, bootstrapClass); + + updateBootstrapClass(t, bootstrapClass, class_); + class_ = bootstrapClass; + } + } + } + + if (class_) { + hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash); + } else if (t->exception == 0) { + object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); + t->exception = makeClassNotFoundException(t, message); + } + } + + return class_; +} + +object +resolveObjectArrayClass(Thread* t, object elementSpec) +{ + PROTECT(t, elementSpec); + + object spec; + if (byteArrayBody(t, elementSpec, 0) == '[') { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1, false); + byteArrayBody(t, elementSpec, 0) = '['; + memcpy(&byteArrayBody(t, spec, 1), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec)); + } else { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3, false); + byteArrayBody(t, spec, 0) = '['; + byteArrayBody(t, spec, 1) = 'L'; + memcpy(&byteArrayBody(t, spec, 2), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec) - 1); + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; + } + + return resolveClass(t, spec); +} + +object +makeObjectArray(Thread* t, object elementClass, unsigned count, bool clear) +{ + object arrayClass = resolveObjectArrayClass(t, className(t, elementClass)); + PROTECT(t, arrayClass); + + object array = makeArray(t, count, clear); + setObjectClass(t, array, arrayClass); + + return array; +} + void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) { @@ -992,27 +2132,10 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) (t, target, reinterpret_cast(finalize), t->vm->finalizers); } -void -removeMonitor(Thread* t, object o) -{ - object p = hashMapRemove2 - (t, t->vm->monitorMap, o, objectHash(t, o), referenceHash, referenceEqual); - - assert(t, p); - - if (DebugMonitors) { - fprintf(stderr, "dispose monitor %p for object %x\n", - static_cast(pointerValue(t, p)), - objectHash(t, o)); - } - - static_cast(pointerValue(t, p))->dispose(); -} - System::Monitor* objectMonitor(Thread* t, object o) { - object p = hashMapFind(t, t->vm->monitorMap, o, objectHash, referenceEqual); + object p = hashMapFind(t, t->vm->monitorMap, o, objectHash, objectEqual); if (p) { if (DebugMonitors) { @@ -1031,19 +2154,14 @@ objectMonitor(Thread* t, object o) System::Status s = t->vm->system->make(&m); expect(t, t->vm->system->success(s)); - p = makePointer(t, m); - PROTECT(t, p); - - object wr = makeWeakReference(t, o, t->vm->weakReferences); - t->vm->weakReferences = wr; - if (DebugMonitors) { fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o)); } - hashMapInsert(t, t->vm->monitorMap, wr, p, referenceHash); + p = makePointer(t, m); + hashMapInsert(t, t->vm->monitorMap, o, p, objectHash); addFinalizer(t, o, removeMonitor); diff --git a/src/machine.h b/src/machine.h index 479d6bcbcb..d9efcef815 100644 --- a/src/machine.h +++ b/src/machine.h @@ -53,6 +53,11 @@ enum StackTag { ObjectTag }; +enum MapType { + NormalMap, + WeakMap +}; + const int NativeLine = -1; const int UnknownLine = -2; @@ -1289,6 +1294,15 @@ set(Thread* t, object& target, object value) } } +inline void +setObjectClass(Thread* t, object o, object value) +{ + set(t, cast(o, 0), + reinterpret_cast + (reinterpret_cast(value) + | reinterpret_cast(cast(o, 0)) & (~PointerMask))); +} + object& arrayBodyUnsafe(Thread*, object, unsigned); @@ -1705,18 +1719,6 @@ objectEqual(Thread*, object a, object b) return a == b; } -inline uint32_t -referenceHash(Thread* t, object o) -{ - return objectHash(t, jreferenceTarget(t, o)); -} - -inline bool -referenceEqual(Thread* t, object a, object b) -{ - return a == jreferenceTarget(t, b); -} - inline uint32_t byteArrayHash(Thread* t, object array) { @@ -1821,6 +1823,54 @@ hashMapIteratorNext(Thread* t, object it); void listAppend(Thread* t, object list, object value); +unsigned +fieldCode(Thread* t, unsigned javaCode); + +unsigned +fieldType(Thread* t, unsigned code); + +unsigned +primitiveSize(Thread* t, unsigned code); + +inline unsigned +fieldSize(Thread* t, object field) +{ + unsigned code = fieldCode(t, field); + if (code == ObjectField) { + return BytesPerWord; + } else { + return primitiveSize(t, code); + } +} + +object +resolveClass(Thread* t, object spec); + +object +resolveObjectArrayClass(Thread* t, object elementSpec); + +object +makeObjectArray(Thread* t, object elementClass, unsigned count, bool clear); + +inline unsigned +objectArrayLength(Thread* t, object array) +{ + assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2); + assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord); + return cast(array, BytesPerWord); +} + +inline object& +objectArrayBody(Thread* t, object array, unsigned index) +{ + assert(t, classFixedSize(t, objectClass(t, array)) == BytesPerWord * 2); + assert(t, classArrayElementSize(t, objectClass(t, array)) == BytesPerWord); + assert(t, classObjectMask(t, objectClass(t, array)) + == classObjectMask(t, arrayBody + (t, t->vm->types, Machine::ArrayType))); + return cast(array, (1 + index) * BytesPerWord); +} + void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); diff --git a/src/run.cpp b/src/run.cpp index 945f9fd493..feae106f07 100644 --- a/src/run.cpp +++ b/src/run.cpp @@ -2,7 +2,6 @@ #include "system.h" #include "heap.h" #include "class-finder.h" -#include "stream.h" #include "constants.h" #include "run.h" #include "jnienv.h" @@ -90,86 +89,6 @@ make(Thread* t, object class_) return instance; } -unsigned -fieldCode(Thread* t, unsigned javaCode) -{ - switch (javaCode) { - case 'B': - return ByteField; - case 'C': - return CharField; - case 'D': - return DoubleField; - case 'F': - return FloatField; - case 'I': - return IntField; - case 'J': - return LongField; - case 'S': - return ShortField; - case 'V': - return VoidField; - case 'Z': - return BooleanField; - case 'L': - case '[': - return ObjectField; - - default: abort(t); - } -} - -unsigned -fieldType(Thread* t, unsigned code) -{ - switch (code) { - case VoidField: - return VOID_TYPE; - case ByteField: - case BooleanField: - return INT8_TYPE; - case CharField: - case ShortField: - return INT16_TYPE; - case DoubleField: - return DOUBLE_TYPE; - case FloatField: - return FLOAT_TYPE; - case IntField: - return INT32_TYPE; - case LongField: - return INT64_TYPE; - case ObjectField: - return POINTER_TYPE; - - default: abort(t); - } -} - -unsigned -primitiveSize(Thread* t, unsigned code) -{ - switch (code) { - case VoidField: - return 0; - case ByteField: - case BooleanField: - return 1; - case CharField: - case ShortField: - return 2; - case FloatField: - case IntField: - return 4; - case DoubleField: - case LongField: - return 8; - - default: abort(t); - } -} - inline void setStatic(Thread* t, object field, object value) { @@ -218,9 +137,6 @@ findInterfaceMethod(Thread* t, object method, object o) abort(t); } -object -resolveClass(Thread*, object); - inline object findMethod(Thread* t, object method, object class_) { @@ -283,447 +199,6 @@ findMethodInClass(Thread* t, object class_, object reference) methodSpec); } -object -parsePool(Thread* t, Stream& s) -{ - unsigned poolCount = s.read2() - 1; - object pool = makeArray(t, poolCount, true); - - PROTECT(t, pool); - - for (unsigned i = 0; i < poolCount; ++i) { - unsigned c = s.read1(); - - switch (c) { - case CONSTANT_Integer: { - object value = makeInt(t, s.read4()); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_Float: { - object value = makeFloat(t, s.readFloat()); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_Long: { - object value = makeLong(t, s.read8()); - set(t, arrayBody(t, pool, i), value); - ++i; - } break; - - case CONSTANT_Double: { - object value = makeLong(t, s.readDouble()); - set(t, arrayBody(t, pool, i), value); - ++i; - } break; - - case CONSTANT_Utf8: { - unsigned length = s.read2(); - object value = makeByteArray(t, length + 1, false); - s.read(reinterpret_cast(&byteArrayBody(t, value, 0)), length); - byteArrayBody(t, value, length) = 0; - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_Class: { - object value = makeIntArray(t, 2, false); - intArrayBody(t, value, 0) = c; - intArrayBody(t, value, 1) = s.read2(); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_String: { - object value = makeIntArray(t, 2, false); - intArrayBody(t, value, 0) = c; - intArrayBody(t, value, 1) = s.read2(); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_NameAndType: { - object value = makeIntArray(t, 3, false); - intArrayBody(t, value, 0) = c; - intArrayBody(t, value, 1) = s.read2(); - intArrayBody(t, value, 2) = s.read2(); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: { - object value = makeIntArray(t, 3, false); - intArrayBody(t, value, 0) = c; - intArrayBody(t, value, 1) = s.read2(); - intArrayBody(t, value, 2) = s.read2(); - set(t, arrayBody(t, pool, i), value); - } break; - - default: abort(t); - } - } - - for (unsigned i = 0; i < poolCount; ++i) { - object o = arrayBody(t, pool, i); - if (o and objectClass(t, o) - == arrayBody(t, t->vm->types, Machine::IntArrayType)) - { - switch (intArrayBody(t, o, 0)) { - case CONSTANT_Class: { - set(t, arrayBody(t, pool, i), - arrayBody(t, pool, intArrayBody(t, o, 1) - 1)); - } break; - - case CONSTANT_String: { - object bytes = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); - object value = makeString - (t, bytes, 0, byteArrayLength(t, bytes) - 1, 0); - set(t, arrayBody(t, pool, i), value); - } break; - - case CONSTANT_NameAndType: { - object name = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); - object type = arrayBody(t, pool, intArrayBody(t, o, 2) - 1); - object value = makePair(t, name, type); - set(t, arrayBody(t, pool, i), value); - } break; - } - } - } - - for (unsigned i = 0; i < poolCount; ++i) { - object o = arrayBody(t, pool, i); - if (o and objectClass(t, o) - == arrayBody(t, t->vm->types, Machine::IntArrayType)) - { - switch (intArrayBody(t, o, 0)) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: { - object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1); - object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1); - object value = makeReference - (t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType)); - set(t, arrayBody(t, pool, i), value); - } break; - } - } - } - - return pool; -} - -void -addInterfaces(Thread* t, object class_, object map) -{ - object table = classInterfaceTable(t, class_); - if (table) { - unsigned increment = 2; - if (classFlags(t, class_) & ACC_INTERFACE) { - increment = 1; - } - - PROTECT(t, map); - PROTECT(t, table); - - for (unsigned i = 0; i < arrayLength(t, table); i += increment) { - object interface = arrayBody(t, table, i); - object name = className(t, interface); - hashMapInsertMaybe(t, map, name, interface, byteArrayHash, - byteArrayEqual); - } - } -} - -void -parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) -{ - PROTECT(t, class_); - PROTECT(t, pool); - - object map = makeHashMap(t, 0, 0); - PROTECT(t, map); - - if (classSuper(t, class_)) { - addInterfaces(t, classSuper(t, class_), map); - } - - unsigned count = s.read2(); - for (unsigned i = 0; i < count; ++i) { - object name = arrayBody(t, pool, s.read2() - 1); - PROTECT(t, name); - - object interface = resolveClass(t, name); - PROTECT(t, interface); - - hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual); - - addInterfaces(t, interface, map); - } - - object interfaceTable = 0; - if (hashMapSize(t, map)) { - unsigned length = hashMapSize(t, map) ; - if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { - length *= 2; - } - interfaceTable = makeArray(t, length, true); - PROTECT(t, interfaceTable); - - unsigned i = 0; - object it = hashMapIterator(t, map); - PROTECT(t, it); - - for (; it; it = hashMapIteratorNext(t, it)) { - object interface = resolveClass - (t, tripleFirst(t, hashMapIteratorNode(t, it))); - if (UNLIKELY(t->exception)) return; - - set(t, arrayBody(t, interfaceTable, i++), interface); - - if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { - // we'll fill in this table in parseMethodTable(): - object vtable = makeArray - (t, arrayLength(t, classVirtualTable(t, interface)), true); - - set(t, arrayBody(t, interfaceTable, i++), vtable); - } - } - } - - set(t, classInterfaceTable(t, class_), interfaceTable); -} - -inline unsigned -fieldSize(Thread* t, object field) -{ - unsigned code = fieldCode(t, field); - if (code == ObjectField) { - return BytesPerWord; - } else { - return primitiveSize(t, code); - } -} - -void -parseFieldTable(Thread* t, Stream& s, object class_, object pool) -{ - PROTECT(t, class_); - PROTECT(t, pool); - - unsigned memberOffset = BytesPerWord; - if (classSuper(t, class_)) { - memberOffset = classFixedSize(t, classSuper(t, class_)); - } - - unsigned count = s.read2(); - if (count) { - unsigned staticOffset = 0; - - object fieldTable = makeArray(t, count, true); - PROTECT(t, fieldTable); - - for (unsigned i = 0; i < count; ++i) { - unsigned flags = s.read2(); - unsigned name = s.read2(); - unsigned spec = s.read2(); - - unsigned attributeCount = s.read2(); - for (unsigned j = 0; j < attributeCount; ++j) { - s.read2(); - s.skip(s.read4()); - } - - object field = makeField - (t, - flags, - 0, // offset - fieldCode(t, 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, field) = staticOffset++; - } else { - unsigned excess = memberOffset % BytesPerWord; - if (excess and fieldCode(t, field) == ObjectField) { - memberOffset += BytesPerWord - excess; - } - - fieldOffset(t, field) = memberOffset; - memberOffset += fieldSize(t, field); - } - - set(t, arrayBody(t, fieldTable, i), field); - } - - set(t, classFieldTable(t, class_), fieldTable); - - if (staticOffset) { - object staticTable = makeArray(t, staticOffset, true); - - set(t, classStaticTable(t, class_), staticTable); - } - } - - classFixedSize(t, class_) = pad(memberOffset); - - object mask = makeIntArray - (t, divide(classFixedSize(t, class_), BitsPerWord * BytesPerWord), true); - intArrayBody(t, mask, 0) = 1; - - bool sawReferenceField = false; - for (object c = class_; c; c = classSuper(t, c)) { - object fieldTable = classFieldTable(t, c); - if (fieldTable) { - for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) { - object field = arrayBody(t, fieldTable, i); - if (fieldCode(t, field) == ObjectField) { - unsigned index = fieldOffset(t, field) / BytesPerWord; - intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32); - sawReferenceField = true; - } - } - } - } - - if (sawReferenceField) { - set(t, classObjectMask(t, class_), mask); - } -} - -object -parseCode(Thread* t, Stream& s, object pool) -{ - unsigned maxStack = s.read2(); - unsigned maxLocals = s.read2(); - unsigned length = s.read4(); - - object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false); - s.read(&codeBody(t, code, 0), length); - - unsigned ehtLength = s.read2(); - if (ehtLength) { - PROTECT(t, code); - - object eht = makeExceptionHandlerTable(t, ehtLength, false); - for (unsigned i = 0; i < ehtLength; ++i) { - ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i); - exceptionHandlerStart(eh) = s.read2(); - exceptionHandlerEnd(eh) = s.read2(); - exceptionHandlerIp(eh) = s.read2(); - exceptionHandlerCatchType(eh) = s.read2(); - } - - set(t, codeExceptionHandlerTable(t, code), eht); - } - - unsigned attributeCount = s.read2(); - for (unsigned j = 0; j < attributeCount; ++j) { - object name = arrayBody(t, pool, s.read2() - 1); - unsigned length = s.read4(); - - if (strcmp(reinterpret_cast("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; -} - -unsigned -parameterFootprint(Thread* t, object spec) -{ - unsigned footprint = 0; - const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); - ++ s; // skip '(' - while (*s and *s != ')') { - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - case '[': - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } - break; - - case 'J': - case 'D': - ++ s; - ++ footprint; - break; - - default: - ++ s; - break; - } - - ++ footprint; - } - - return footprint; -} - -unsigned -parameterCount(Thread* t, object spec) -{ - unsigned count = 0; - const char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); - ++ s; // skip '(' - while (*s and *s != ')') { - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - case '[': - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } - break; - - default: - ++ s; - break; - } - - ++ count; - } - - return count; -} - int lineNumber(Thread* t, object method, unsigned ip) { @@ -748,485 +223,6 @@ lineNumber(Thread* t, object method, unsigned ip) } } -unsigned -mangledSize(int8_t c) -{ - switch (c) { - case '_': - case ';': - case '[': - return 2; - - case '$': - return 6; - - default: - return 1; - } -} - -unsigned -mangle(int8_t c, int8_t* dst) -{ - switch (c) { - case '/': - dst[0] = '_'; - return 1; - - case '_': - dst[0] = '_'; - dst[1] = '1'; - return 2; - - case ';': - dst[0] = '_'; - dst[1] = '2'; - return 2; - - case '[': - dst[0] = '_'; - dst[1] = '3'; - return 2; - - case '$': - memcpy(dst, "_00024", 6); - return 6; - - default: - dst[0] = c; - return 1; - } -} - -object -makeJNIName(Thread* t, object method, bool decorate) -{ - unsigned size = 5; - object className = ::className(t, methodClass(t, method)); - PROTECT(t, className); - for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { - size += mangledSize(byteArrayBody(t, className, i)); - } - - ++ size; - - object methodName = ::methodName(t, method); - PROTECT(t, methodName); - for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { - size += mangledSize(byteArrayBody(t, methodName, i)); - } - - object methodSpec = ::methodSpec(t, method); - PROTECT(t, methodSpec); - if (decorate) { - size += 2; - for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 - and byteArrayBody(t, methodSpec, i) != ')'; ++i) - { - size += mangledSize(byteArrayBody(t, methodSpec, i)); - } - } - - object name = makeByteArray(t, size + 1, false); - unsigned index = 0; - - memcpy(&byteArrayBody(t, name, index), "Java_", 5); - index += 5; - - for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) { - index += mangle(byteArrayBody(t, className, i), - &byteArrayBody(t, name, index)); - } - - byteArrayBody(t, name, index++) = '_'; - - for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) { - index += mangle(byteArrayBody(t, methodName, i), - &byteArrayBody(t, name, index)); - } - - if (decorate) { - byteArrayBody(t, name, index++) = '_'; - byteArrayBody(t, name, index++) = '_'; - for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1 - and byteArrayBody(t, methodSpec, i) != ')'; ++i) - { - index += mangle(byteArrayBody(t, className, i), - &byteArrayBody(t, name, index)); - } - } - - byteArrayBody(t, name, index++) = 0; - - assert(t, index == size + 1); - - return name; -} - -void -parseMethodTable(Thread* t, Stream& s, object class_, object pool) -{ - PROTECT(t, class_); - PROTECT(t, pool); - - object virtualMap = makeHashMap(t, 0, 0); - PROTECT(t, virtualMap); - - object nativeMap = makeHashMap(t, 0, 0); - PROTECT(t, nativeMap); - - unsigned virtualCount = 0; - - object superVirtualTable = 0; - PROTECT(t, superVirtualTable); - - if (classFlags(t, class_) & ACC_INTERFACE) { - object itable = classInterfaceTable(t, class_); - if (itable) { - for (unsigned i = 0; i < arrayLength(t, itable); ++i) { - object vtable = classVirtualTable(t, arrayBody(t, itable, i)); - for (unsigned j = 0; j < virtualCount; ++j) { - object method = arrayBody(t, vtable, j); - if (hashMapInsertMaybe(t, virtualMap, method, method, methodHash, - methodEqual)) - { - ++ virtualCount; - } - } - } - } - } else { - if (classSuper(t, class_)) { - superVirtualTable = classVirtualTable(t, classSuper(t, class_)); - } - - if (superVirtualTable) { - virtualCount = arrayLength(t, superVirtualTable); - for (unsigned i = 0; i < virtualCount; ++i) { - object method = arrayBody(t, superVirtualTable, i); - hashMapInsert(t, virtualMap, method, method, methodHash); - } - } - } - - object newVirtuals = makeList(t, 0, 0, 0); - PROTECT(t, newVirtuals); - - unsigned count = s.read2(); - if (count) { - object methodTable = makeArray(t, count, true); - PROTECT(t, methodTable); - - for (unsigned i = 0; i < count; ++i) { - unsigned flags = s.read2(); - unsigned name = s.read2(); - unsigned spec = s.read2(); - - object code = 0; - unsigned attributeCount = s.read2(); - for (unsigned j = 0; j < attributeCount; ++j) { - object name = arrayBody(t, pool, s.read2() - 1); - unsigned length = s.read4(); - - if (strcmp(reinterpret_cast("Code"), - &byteArrayBody(t, name, 0)) == 0) - { - code = parseCode(t, s, pool); - } else { - s.skip(length); - } - } - - unsigned parameterCount = ::parameterCount - (t, arrayBody(t, pool, spec - 1)); - - unsigned parameterFootprint = ::parameterFootprint - (t, arrayBody(t, pool, spec - 1)); - - if ((flags & ACC_STATIC) == 0) { - ++ parameterCount; - ++ parameterFootprint; - } - - object method = makeMethod(t, - flags, - 0, // offset - parameterCount, - parameterFootprint, - arrayBody(t, pool, name - 1), - arrayBody(t, pool, spec - 1), - class_, - code); - PROTECT(t, method); - - if (flags & ACC_STATIC) { - if (strcmp(reinterpret_cast(""), - &byteArrayBody(t, methodName(t, method), 0)) == 0) - { - set(t, classInitializer(t, class_), method); - } - } else { - object p = hashMapFindNode - (t, virtualMap, method, methodHash, methodEqual); - - if (p) { - methodOffset(t, method) = methodOffset(t, tripleFirst(t, p)); - - set(t, tripleSecond(t, p), method); - } else { - methodOffset(t, method) = virtualCount++; - - listAppend(t, newVirtuals, method); - - hashMapInsert(t, virtualMap, method, method, methodHash); - } - } - - if (flags & ACC_NATIVE) { - object p = hashMapFindNode - (t, nativeMap, method, methodHash, methodEqual); - - if (p) { - set(t, tripleSecond(t, p), method); - } else { - hashMapInsert(t, virtualMap, method, 0, methodHash); - } - } - - set(t, arrayBody(t, methodTable, i), method); - } - - for (unsigned i = 0; i < count; ++i) { - object method = arrayBody(t, methodTable, i); - - if (methodFlags(t, method) & ACC_NATIVE) { - object overloaded = hashMapFind - (t, nativeMap, method, methodHash, methodEqual); - - object jniName = makeJNIName(t, method, overloaded); - set(t, methodCode(t, method), jniName); - } - } - - set(t, classMethodTable(t, class_), methodTable); - } - - if (virtualCount) { - // generate class vtable - - unsigned i = 0; - object vtable = makeArray(t, virtualCount, false); - - if (classFlags(t, class_) & ACC_INTERFACE) { - object it = hashMapIterator(t, virtualMap); - - for (; it; it = hashMapIteratorNext(t, it)) { - object method = tripleFirst(t, hashMapIteratorNode(t, it)); - set(t, arrayBody(t, vtable, i++), method); - } - } else { - if (superVirtualTable) { - for (; i < arrayLength(t, superVirtualTable); ++i) { - object method = arrayBody(t, superVirtualTable, i); - method = hashMapFind(t, virtualMap, method, methodHash, methodEqual); - - set(t, arrayBody(t, vtable, i), method); - } - } - - for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) { - set(t, arrayBody(t, vtable, i++), pairFirst(t, p)); - } - } - - set(t, classVirtualTable(t, class_), vtable); - - if ((classFlags(t, class_) & ACC_INTERFACE) == 0) { - // generate interface vtables - - object itable = classInterfaceTable(t, class_); - if (itable) { - PROTECT(t, itable); - - for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { - object ivtable = classVirtualTable(t, arrayBody(t, itable, i)); - object vtable = arrayBody(t, itable, i + 1); - - for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) { - object method = arrayBody(t, ivtable, j); - method = hashMapFind - (t, virtualMap, method, methodHash, methodEqual); - assert(t, method); - - set(t, arrayBody(t, vtable, j), method); - } - } - } - } - } -} - -object -parseClass(Thread* t, const uint8_t* data, unsigned size) -{ - class Client : public Stream::Client { - public: - Client(Thread* t): t(t) { } - - virtual void NO_RETURN handleEOS() { - abort(t); - } - - private: - Thread* t; - } client(t); - - Stream s(&client, data, size); - - uint32_t magic = s.read4(); - assert(t, magic == 0xCAFEBABE); - s.read2(); // minor version - s.read2(); // major version - - object pool = parsePool(t, s); - - unsigned flags = s.read2(); - unsigned name = s.read2(); - - object class_ = makeClass(t, - flags, - 0, // VM flags - 0, // fixed size - 0, // array size - 0, // object mask - arrayBody(t, pool, name - 1), - 0, // super - 0, // interfaces - 0, // vtable - 0, // fields - 0, // methods - 0, // static table - 0); // initializer - PROTECT(t, class_); - - unsigned super = s.read2(); - if (super) { - object sc = resolveClass(t, arrayBody(t, pool, super - 1)); - if (UNLIKELY(t->exception)) return 0; - - set(t, classSuper(t, class_), sc); - - classVmFlags(t, class_) |= classVmFlags(t, sc); - } - - parseInterfaceTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; - - parseFieldTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; - - parseMethodTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; - - return class_; -} - -void -updateBootstrapClass(Thread* t, object bootstrapClass, object class_) -{ - expect(t, bootstrapClass != class_); - - // verify that the classes have the same layout - expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); - expect(t, classFixedSize(t, bootstrapClass) == classFixedSize(t, class_)); - expect(t, (classObjectMask(t, bootstrapClass) == 0 - and classObjectMask(t, class_) == 0) - or intArrayEqual(t, classObjectMask(t, bootstrapClass), - classObjectMask(t, class_))); - - PROTECT(t, bootstrapClass); - PROTECT(t, class_); - - ENTER(t, Thread::ExclusiveState); - - classVmFlags(t, class_) |= classVmFlags(t, bootstrapClass); - - memcpy(bootstrapClass, - class_, - extendedSize(t, class_, baseSize(t, class_, objectClass(t, class_))) - * BytesPerWord); - - object fieldTable = classFieldTable(t, class_); - if (fieldTable) { - for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) { - set(t, fieldClass(t, arrayBody(t, fieldTable, i)), bootstrapClass); - } - } - - object methodTable = classMethodTable(t, class_); - if (methodTable) { - for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) { - set(t, methodClass(t, arrayBody(t, methodTable, i)), bootstrapClass); - } - } -} - -object -resolveClass(Thread* t, object spec) -{ - PROTECT(t, spec); - ACQUIRE(t, t->vm->classLock); - - object class_ = hashMapFind - (t, t->vm->classMap, spec, byteArrayHash, byteArrayEqual); - if (class_ == 0) { - ClassFinder::Data* data = t->vm->classFinder->find - (reinterpret_cast(&byteArrayBody(t, spec, 0))); - - if (byteArrayBody(t, spec, 0) == '[') { - class_ = hashMapFind - (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); - } else if (data) { - if (Verbose) { - 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)); - } - - PROTECT(t, class_); - - object bootstrapClass = hashMapFind - (t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); - - if (bootstrapClass) { - PROTECT(t, bootstrapClass); - - updateBootstrapClass(t, bootstrapClass, class_); - class_ = bootstrapClass; - } - - hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash); - } - - if (class_) { - hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash); - } else { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); - } - } - - return class_; -} - inline object resolveClass(Thread* t, object pool, unsigned index) { @@ -1591,7 +587,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < objectArrayLength(t, array))) + static_cast(index) < objectArrayLength(t, array))) { pushObject(t, objectArrayBody(t, array, index)); } else { @@ -1613,7 +609,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < objectArrayLength(t, array))) + static_cast(index) < objectArrayLength(t, array))) { set(t, objectArrayBody(t, array, index), value); } else { @@ -1662,10 +658,8 @@ run(Thread* t) object class_ = resolveClass(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - - object array = makeObjectArray(t, class_, count, true); - - pushObject(t, array); + + pushObject(t, makeObjectArray(t, class_, count, true)); } else { object message = makeString(t, "%d", count); exception = makeNegativeArraySizeException(t, message); @@ -1687,14 +681,7 @@ run(Thread* t) case arraylength: { object array = popObject(t); if (LIKELY(array)) { - if (objectClass(t, array) - == arrayBody(t, t->vm->types, Machine::ObjectArrayType)) - { - pushInt(t, objectArrayLength(t, array)); - } else { - // for all other array types, the length follows the class pointer. - pushInt(t, cast(array, BytesPerWord)); - } + pushInt(t, cast(array, BytesPerWord)); } else { exception = makeNullPointerException(t); goto throw_; @@ -1734,7 +721,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < byteArrayLength(t, array))) + static_cast(index) < byteArrayLength(t, array))) { pushInt(t, byteArrayBody(t, array, index)); } else { @@ -1756,7 +743,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < byteArrayLength(t, array))) + static_cast(index) < byteArrayLength(t, array))) { byteArrayBody(t, array, index) = value; } else { @@ -1781,7 +768,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < charArrayLength(t, array))) + static_cast(index) < charArrayLength(t, array))) { pushInt(t, charArrayBody(t, array, index)); } else { @@ -1803,7 +790,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < charArrayLength(t, array))) + static_cast(index) < charArrayLength(t, array))) { charArrayBody(t, array, index) = value; } else { @@ -2039,7 +1026,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < intArrayLength(t, array))) + static_cast(index) < intArrayLength(t, array))) { pushInt(t, intArrayBody(t, array, index)); } else { @@ -2068,7 +1055,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < intArrayLength(t, array))) + static_cast(index) < intArrayLength(t, array))) { intArrayBody(t, array, index) = value; } else { @@ -2574,7 +1561,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < longArrayLength(t, array))) + static_cast(index) < longArrayLength(t, array))) { pushLong(t, longArrayBody(t, array, index)); } else { @@ -2603,7 +1590,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < longArrayLength(t, array))) + static_cast(index) < longArrayLength(t, array))) { longArrayBody(t, array, index) = value; } else { @@ -3030,7 +2017,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < shortArrayLength(t, array))) + static_cast(index) < shortArrayLength(t, array))) { pushInt(t, shortArrayBody(t, array, index)); } else { @@ -3052,7 +2039,7 @@ run(Thread* t) if (LIKELY(array)) { if (LIKELY(index >= 0 and - static_cast(index) < shortArrayLength(t, array))) + static_cast(index) < shortArrayLength(t, array))) { shortArrayBody(t, array, index) = value; } else { @@ -3226,8 +2213,8 @@ run(Thread* t) } object trace = throwableTrace(t, e); - for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { - object e = objectArrayBody(t, trace, i); + 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, stackTraceElementMethod(t, e))), 0); const int8_t* method = &byteArrayBody @@ -3384,6 +2371,8 @@ run(System* system, Heap* heap, ClassFinder* classFinder, Machine m(system, heap, classFinder); Thread t(&m, 0, 0, 0); + enter(&t, Thread::ActiveState); + ::run(&t, className, argc, argv); exit(&t); diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 008a13a91d..d9e5bdb432 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -1484,7 +1484,7 @@ writeInitialization(Output* out, Object* type) } out->write(" object class_ = makeClass"); - out->write("(t, 0, 0, "); + out->write("(t, 0, 0, 0, "); out->write(typeFixedSize(type)); out->write(", "); out->write(typeArrayElementSize(type)); diff --git a/src/types.def b/src/types.def index 68f8a86947..b79ae047c0 100644 --- a/src/types.def +++ b/src/types.def @@ -3,7 +3,8 @@ (type class java/lang/Class (extends jobject) (uint16_t flags) - (uint16_t vmFlags) + (uint8_t vmFlags) + (uint8_t arrayDimensions) (uint16_t fixedSize) (uint16_t arrayElementSize) (object objectMask) @@ -88,6 +89,7 @@ (void* next)) (type hashMap + (uint32_t type) (uint32_t size) (object array)) @@ -215,11 +217,6 @@ (type weakReference java/lang/ref/WeakReference (extends jreference)) -(type objectArray [ - (extends jobject) - (object elementClass) - (array object body)) - (type byteArray [B (extends jobject) (array int8_t body))