From e820b6a8a426b9c2bec99c64b6037e9a20f50873 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 2 Nov 2007 15:08:14 -0600 Subject: [PATCH] sketch of singleton support --- classpath/java/lang/Class.java | 4 +- classpath/java/lang/reflect/Field.java | 242 +++++++++---------------- makefile | 8 +- src/interpret.cpp | 225 ++++++++--------------- src/machine.cpp | 116 ++++++++++-- src/machine.h | 12 +- 6 files changed, 279 insertions(+), 328 deletions(-) diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index e0d46ddd99..621a8fcd28 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -24,7 +24,7 @@ public final class Class { private Method[] virtualTable; private Field[] fieldTable; private Method[] methodTable; - private Object[] staticTable; + private Object staticTable; private ClassLoader loader; private Class() { } @@ -49,7 +49,7 @@ public final class Class { (replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false); } - public Object[] staticTable() { + public Object staticTable() { return staticTable; } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 24297b4f84..bfa8d1a625 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -47,176 +47,108 @@ public class Field extends AccessibleObject { } public Object get(Object instance) throws IllegalAccessException { + Object target; if ((flags & Modifier.STATIC) != 0) { - Object v = class_.staticTable()[offset]; - switch (code) { - case ByteField: - return Byte.valueOf - ((byte) (v == null ? 0 : ((Integer) v).intValue())); - - case BooleanField: - return Boolean.valueOf - (v == null ? false : ((Integer) v) != 0); - - case CharField: - return Character.valueOf - ((char) (v == null ? 0 : ((Integer) v).intValue())); - - case ShortField: - return Short.valueOf - ((short) (v == null ? 0 : ((Integer) v).intValue())); - - case FloatField: - return Float.valueOf - (Float.intBitsToFloat(v == null ? 0 : (Integer) v)); - - case DoubleField: - return Double.valueOf - (Double.longBitsToDouble(v == null ? 0 : (Long) v)); - - case IntField: - case LongField: - case ObjectField: - return v; - - default: - throw new Error(); - } + target = class_.staticTable(); } else if (class_.isInstance(instance)) { - switch (code) { - case ByteField: - return Byte.valueOf((byte) getPrimitive(instance, code, offset)); - - case BooleanField: - return Boolean.valueOf(getPrimitive(instance, code, offset) != 0); - - case CharField: - return Character.valueOf((char) getPrimitive(instance, code, offset)); - - case ShortField: - return Short.valueOf((short) getPrimitive(instance, code, offset)); - - case IntField: - return Integer.valueOf((int) getPrimitive(instance, code, offset)); - - case LongField: - return Long.valueOf((int) getPrimitive(instance, code, offset)); - - case FloatField: - return Float.valueOf - (Float.intBitsToFloat((int) getPrimitive(instance, code, offset))); - - case DoubleField: - return Double.valueOf - (Double.longBitsToDouble(getPrimitive(instance, code, offset))); - - case ObjectField: - return getObject(instance, offset); - - default: - throw new Error(); - } + target = instance; } else { throw new IllegalArgumentException(); } + + switch (code) { + case ByteField: + return Byte.valueOf((byte) getPrimitive(target, code, offset)); + + case BooleanField: + return Boolean.valueOf(getPrimitive(target, code, offset) != 0); + + case CharField: + return Character.valueOf((char) getPrimitive(target, code, offset)); + + case ShortField: + return Short.valueOf((short) getPrimitive(target, code, offset)); + + case IntField: + return Integer.valueOf((int) getPrimitive(target, code, offset)); + + case LongField: + return Long.valueOf((int) getPrimitive(target, code, offset)); + + case FloatField: + return Float.valueOf + (Float.intBitsToFloat((int) getPrimitive(target, code, offset))); + + case DoubleField: + return Double.valueOf + (Double.longBitsToDouble(getPrimitive(target, code, offset))); + + case ObjectField: + return getObject(instance, offset); + + default: + throw new Error(); + } } public void set(Object instance, Object value) throws IllegalAccessException { + Object target; if ((flags & Modifier.STATIC) != 0) { - Object[] a = class_.staticTable(); - switch (code) { - case ByteField: - a[offset] = Integer.valueOf((Byte) value); - break; - - case BooleanField: - a[offset] = Integer.valueOf(((Boolean) value) ? 1 : 0); - break; - - case CharField: - a[offset] = Integer.valueOf((Character) value); - break; - - case ShortField: - a[offset] = Integer.valueOf((Short) value); - break; - - case FloatField: - a[offset] = Integer.valueOf(Float.floatToRawIntBits((Float) value)); - break; - - case DoubleField: - a[offset] = Long.valueOf(Double.doubleToRawLongBits((Double) value)); - break; - - case IntField: - case LongField: - a[offset] = value; - break; - - case ObjectField: - if (getType().isInstance(value)) { - a[offset] = value; - } else { - throw new IllegalArgumentException(); - } - break; - - default: - throw new Error(); - } + target = class_.staticTable(); } else if (class_.isInstance(instance)) { - switch (code) { - case ByteField: - setPrimitive(instance, code, offset, (Byte) value); - break; - - case BooleanField: - setPrimitive(instance, code, offset, ((Boolean) value) ? 1 : 0); - break; - - case CharField: - setPrimitive(instance, code, offset, (Character) value); - break; - - case ShortField: - setPrimitive(instance, code, offset, (Short) value); - break; - - case IntField: - setPrimitive(instance, code, offset, (Integer) value); - break; - - case LongField: - setPrimitive(instance, code, offset, (Long) value); - break; - - case FloatField: - setPrimitive(instance, code, offset, - Float.floatToRawIntBits((Float) value)); - break; - - case DoubleField: - setPrimitive(instance, code, offset, - Double.doubleToRawLongBits((Double) value)); - break; - - case ObjectField: - if (getType().isInstance(value)) { - setObject(instance, offset, value); - } else { - throw new IllegalArgumentException(); - } - break; - - default: - throw new Error(); - } + target = instance; } else { throw new IllegalArgumentException(); } + + switch (code) { + case ByteField: + setPrimitive(target, code, offset, (Byte) value); + break; + + case BooleanField: + setPrimitive(target, code, offset, ((Boolean) value) ? 1 : 0); + break; + + case CharField: + setPrimitive(target, code, offset, (Character) value); + break; + + case ShortField: + setPrimitive(target, code, offset, (Short) value); + break; + + case IntField: + setPrimitive(target, code, offset, (Integer) value); + break; + + case LongField: + setPrimitive(target, code, offset, (Long) value); + break; + + case FloatField: + setPrimitive(target, code, offset, + Float.floatToRawIntBits((Float) value)); + break; + + case DoubleField: + setPrimitive(target, code, offset, + Double.doubleToRawLongBits((Double) value)); + break; + + case ObjectField: + if (getType().isInstance(value)) { + setObject(target, offset, value); + } else { + throw new IllegalArgumentException(); + } + break; + + default: + throw new Error(); + } } private static native long getPrimitive diff --git a/makefile b/makefile index 1217adedcc..2c2438341b 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,7 @@ src = src classpath = classpath test = test -input = $(test-build)/GC.class +input = $(test-build)/References.class build-cxx = g++ build-cc = gcc @@ -248,9 +248,6 @@ $(native-build)/type-generator.o: \ $(classpath-build)/%.class: $(classpath)/%.java @echo $(<) -$(test-build)/%.class: $(test)/%.java - @echo $(<) - $(classpath-dep): $(classpath-sources) @echo "compiling classpath classes" @mkdir -p $(dir $(@)) @@ -258,6 +255,9 @@ $(classpath-dep): $(classpath-sources) $(shell make -s $(classpath-classes)) @touch $(@) +$(test-build)/%.class: $(test)/%.java + @echo $(<) + $(test-dep): $(test-sources) @echo "compiling test classes" @mkdir -p $(dir $(@)) diff --git a/src/interpret.cpp b/src/interpret.cpp index f4bf2a0a1b..ee5bf22475 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -733,6 +733,39 @@ findExceptionHandler(Thread* t, int frame) return 0; } +void +pushField(Thread* t, object target, object field) +{ + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + pushInt(t, cast(target, fieldOffset(t, field))); + break; + + case CharField: + case ShortField: + pushInt(t, cast(target, fieldOffset(t, field))); + break; + + case FloatField: + case IntField: + pushInt(t, cast(target, fieldOffset(t, field))); + break; + + case DoubleField: + case LongField: + pushLong(t, cast(target, fieldOffset(t, field))); + break; + + case ObjectField: + pushObject(t, cast(target, fieldOffset(t, field))); + break; + + default: + abort(t); + } +} + object interpret(Thread* t) { @@ -1399,36 +1432,7 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - object instance = popObject(t); - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - pushInt(t, cast(instance, fieldOffset(t, field))); - break; - - case CharField: - case ShortField: - pushInt(t, cast(instance, fieldOffset(t, field))); - break; - - case FloatField: - case IntField: - pushInt(t, cast(instance, fieldOffset(t, field))); - break; - - case DoubleField: - case LongField: - pushLong(t, cast(instance, fieldOffset(t, field))); - break; - - case ObjectField: - pushObject(t, cast(instance, fieldOffset(t, field))); - break; - - default: - abort(t); - } + pushField(t, popObject(t), field); } else { exception = makeNullPointerException(t); goto throw_; @@ -1444,30 +1448,7 @@ interpret(Thread* t) if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; - object v = arrayBody(t, classStaticTable(t, fieldClass(t, field)), - fieldOffset(t, field)); - - switch (fieldCode(t, field)) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: - pushInt(t, v ? intValue(t, v) : 0); - break; - - case DoubleField: - case LongField: - pushLong(t, v ? longValue(t, v) : 0); - break; - - case ObjectField: - pushObject(t, v); - break; - - default: abort(t); - } + pushField(t, classStaticTable(t, fieldClass(t, field)), field); } goto loop; case goto_: { @@ -2389,7 +2370,7 @@ interpret(Thread* t) object field = resolveField(t, codePool(t, code), index - 1); if (UNLIKELY(exception)) goto throw_; - + switch (fieldCode(t, field)) { case ByteField: case BooleanField: @@ -2458,7 +2439,7 @@ interpret(Thread* t) if (UNLIKELY(classInit(t, fieldClass(t, field), 3))) goto invoke; - object v; + object table = classStaticTable(t, fieldClass(t, field)); switch (fieldCode(t, field)) { case ByteField: @@ -2467,23 +2448,36 @@ interpret(Thread* t) case ShortField: case FloatField: case IntField: { - v = makeInt(t, popInt(t)); + int32_t value = popInt(t); + switch (fieldCode(t, field)) { + case ByteField: + case BooleanField: + cast(table, fieldOffset(t, field)) = value; + break; + + case CharField: + case ShortField: + cast(table, fieldOffset(t, field)) = value; + break; + + case FloatField: + case IntField: + cast(table, fieldOffset(t, field)) = value; + break; + } } break; case DoubleField: case LongField: { - v = makeLong(t, popLong(t)); + cast(table, fieldOffset(t, field)) = popLong(t); } break; - case ObjectField: - v = popObject(t); - break; + case ObjectField: { + set(t, table, fieldOffset(t, field), popObject(t)); + } break; default: abort(t); } - - set(t, classStaticTable(t, fieldClass(t, field)), - ArrayBody + (fieldOffset(t, field) * BytesPerWord), v); } goto loop; case ret: { @@ -2658,35 +2652,10 @@ pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects, pushObject(t, this_); } - const char* s = spec; - ++ s; // skip '(' - while (*s and *s != ')') { - switch (*s) { + for (MethodSpecIterator it(t, spec); it.hasNext();) { + switch (*it.next()) { case 'L': - while (*s and *s != ';') ++ s; - ++ s; - - if (indirectObjects) { - object* v = va_arg(a, object*); - pushObject(t, v ? *v : 0); - } else { - pushObject(t, va_arg(a, object)); - } - break; - case '[': - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } - if (indirectObjects) { object* v = va_arg(a, object*); pushObject(t, v ? *v : 0); @@ -2697,19 +2666,16 @@ pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects, case 'J': case 'D': - ++ s; pushLong(t, va_arg(a, uint64_t)); break; case 'F': { - ++ s; pushFloat(t, va_arg(a, double)); } break; - + default: - ++ s; pushInt(t, va_arg(a, uint32_t)); - break; + break; } } } @@ -2722,41 +2688,23 @@ pushArguments(Thread* t, object this_, const char* spec, object a) } unsigned index = 0; - const char* s = spec; - ++ s; // skip '(' - while (*s and *s != ')') { - switch (*s) { + for (MethodSpecIterator it(t, spec); it.hasNext();) { + switch (*it.next()) { case 'L': - while (*s and *s != ';') ++ s; - ++ s; - pushObject(t, objectArrayBody(t, a, index++)); - break; - case '[': - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } pushObject(t, objectArrayBody(t, a, index++)); break; case 'J': case 'D': - ++ s; - pushLong(t, cast(objectArrayBody(t, a, index++), BytesPerWord)); + pushLong(t, cast(objectArrayBody(t, a, index++), + BytesPerWord)); break; default: - ++ s; - pushInt(t, cast(objectArrayBody(t, a, index++), BytesPerWord)); - break; + pushInt(t, cast(objectArrayBody(t, a, index++), + BytesPerWord)); + break; } } } @@ -2899,43 +2847,20 @@ class MyProcessor: public Processor { } virtual unsigned - parameterFootprint(vm::Thread*, const char* s, bool static_) + parameterFootprint(vm::Thread* t, const char* s, bool static_) { unsigned footprint = 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; - + for (MethodSpecIterator it(t, s); it.hasNext();) { + switch (*it.next()) { case 'J': case 'D': - ++ s; - ++ footprint; + footprint += 2; break; default: - ++ s; - break; + ++ footprint; + break; } - - ++ footprint; } if (not static_) { diff --git a/src/machine.cpp b/src/machine.cpp index 3de21e477e..bd7fa63c45 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -201,9 +201,19 @@ walk(Thread* t, Heap::Walker* w, object o) intArrayLength(t, objectMask) * 4); walk(t, w, mask, fixedSize, arrayElementSize, arrayLength); -// } else if (classVmFlags(t, class_) & SingletonFlag) { -// unsigned length = singletonLength(t, o); -// walk(t, w, mask, fixedSize, 0, 0); + } else if (classVmFlags(t, class_) & SingletonFlag) { + unsigned length = singletonLength(t, o); + if (length) { + unsigned maskSize = ceiling(length + 2, BitsPerWord + 1); + + uint32_t mask[maskSize * (BytesPerWord / 4)]; + memcpy(mask, &singletonBody(t, o, length - maskSize), + maskSize * BytesPerWord); + + walk(t, w, mask, length - maskSize, 0, 0); + } else { + w->visit(0); + } } else { w->visit(0); } @@ -832,7 +842,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) unsigned count = s.read2(); if (count) { - unsigned staticOffset = 0; + unsigned staticOffset = BytesPerWord * 2; + unsigned staticCount = 0; object fieldTable = makeArray(t, count, true); PROTECT(t, fieldTable); @@ -840,6 +851,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) object staticValueTable = makeArray(t, count, true); PROTECT(t, staticValueTable); + uint8_t staticTypes[count]; + for (unsigned i = 0; i < count; ++i) { unsigned flags = s.read2(); unsigned name = s.read2(); @@ -862,10 +875,13 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) } } + unsigned code = fieldCode + (t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0)); + object field = makeField (t, 0, // vm flags - fieldCode(t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0)), + code, flags, 0, // offset arrayBody(t, pool, name - 1), @@ -873,21 +889,32 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) class_); if (flags & ACC_STATIC) { - set(t, staticValueTable, ArrayBody + (staticOffset * BytesPerWord), + unsigned size = fieldSize(t, code); + unsigned excess = staticOffset % size; + if (excess) { + staticOffset += BytesPerWord - excess; + } + + fieldOffset(t, field) = staticOffset; + + staticOffset += size; + + set(t, staticValueTable, ArrayBody + (staticCount * BytesPerWord), value); - fieldOffset(t, field) = staticOffset++; + + staticTypes[staticCount++] = code; } else { if (value) { abort(t); // todo: handle non-static field initializers } - unsigned excess = memberOffset % fieldSize(t, field); + unsigned excess = memberOffset % fieldSize(t, code); if (excess) { memberOffset += BytesPerWord - excess; } fieldOffset(t, field) = memberOffset; - memberOffset += fieldSize(t, field); + memberOffset += fieldSize(t, code); } set(t, fieldTable, ArrayBody + (i * BytesPerWord), field); @@ -895,11 +922,69 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) set(t, class_, ClassFieldTable, fieldTable); - if (staticOffset) { - object staticTable = makeArray(t, staticOffset, false); - memcpy(&arrayBody(t, staticTable, 0), - &arrayBody(t, staticValueTable, 0), - staticOffset * BytesPerWord); + if (staticCount) { + unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2), + BytesPerWord); + unsigned maskSize = ceiling(footprint + 2, BitsPerWord); + object staticTable = makeSingleton(t, footprint + maskSize, false); + + uint8_t* body = reinterpret_cast + (&singletonBody(t, staticTable, 0)); + + uint32_t* mask = reinterpret_cast + (&singletonBody(t, staticTable, footprint)); + + memset(mask, 0, maskSize * BytesPerWord); + + mask[0] |= 1; + + for (unsigned i = 0, offset = 0; i < staticCount; ++i) { + unsigned size = fieldSize(t, staticTypes[i]); + unsigned excess = offset % size; + if (excess) { + offset += BytesPerWord - excess; + } + + object value = arrayBody(t, staticValueTable, i); + if (value) { + switch (staticTypes[i]) { + case ByteField: + case BooleanField: + body[offset] = intValue(t, value); + break; + + case CharField: + case ShortField: + *reinterpret_cast(body + offset) = intValue(t, value); + break; + + case IntField: + case FloatField: + *reinterpret_cast(body + offset) = intValue(t, value); + break; + + case LongField: + case DoubleField: + memcpy(body + offset, &longValue(t, value), 8); + break; + + case ObjectField: + memcpy(body + offset, &value, BytesPerWord); + break; + + default: abort(t); + } + } else { + memset(body + offset, 0, size); + } + + if (staticTypes[i] == ObjectField) { + unsigned index = (offset / BytesPerWord) + 2; + mask[index / 32] |= 1 << (index % 32); + } + + offset += size; + } set(t, class_, ClassStaticTable, staticTable); } @@ -1665,6 +1750,9 @@ Thread::init() m->unsafe = false; + classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType)) + |= SingletonFlag; + classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType)) |= ReferenceFlag; classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) diff --git a/src/machine.h b/src/machine.h index e1265cca48..6ec7e8c5c1 100644 --- a/src/machine.h +++ b/src/machine.h @@ -27,7 +27,7 @@ namespace vm { const bool Verbose = false; const bool DebugRun = false; const bool DebugStack = false; -const bool DebugMonitors = false; +const bool DebugMonitors = true; const bool DebugReferences = false; const uintptr_t HashTakenMark = 1; @@ -62,6 +62,7 @@ const unsigned NeedInitFlag = 1 << 2; const unsigned InitFlag = 1 << 3; const unsigned PrimitiveFlag = 1 << 4; const unsigned BootstrapFlag = 1 << 5; +const unsigned SingletonFlag = 1 << 6; // method flags: const unsigned ClassInitFlag = 1 << 0; @@ -1963,9 +1964,8 @@ unsigned primitiveSize(Thread* t, unsigned code); inline unsigned -fieldSize(Thread* t, object field) +fieldSize(Thread* t, unsigned code) { - unsigned code = fieldCode(t, field); if (code == ObjectField) { return BytesPerWord; } else { @@ -1973,6 +1973,12 @@ fieldSize(Thread* t, object field) } } +inline unsigned +fieldSize(Thread* t, object field) +{ + return fieldSize(t, fieldCode(t, field)); +} + object findLoadedClass(Thread* t, object spec);