mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
finish support for inline vtables in class objects; convert constant pools from arrays to singletons to reduce memory footprint
This commit is contained in:
parent
f1bc2be9f9
commit
fe0e542afe
2
makefile
2
makefile
@ -28,7 +28,7 @@ src = src
|
||||
classpath = classpath
|
||||
test = test
|
||||
|
||||
input = $(test-build)/References.class
|
||||
input = $(test-build)/List.class
|
||||
|
||||
build-cxx = g++
|
||||
build-cc = gcc
|
||||
|
@ -2051,36 +2051,33 @@ interpret(Thread* t)
|
||||
index = codeReadInt16(t, code, ip);
|
||||
}
|
||||
|
||||
object v = arrayBody(t, codePool(t, code), index - 1);
|
||||
object pool = codePool(t, code);
|
||||
|
||||
if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::IntType)
|
||||
or objectClass(t, v) == arrayBody(t, t->m->types, Machine::FloatType))
|
||||
{
|
||||
pushInt(t, intValue(t, v));
|
||||
} else if (objectClass(t, v)
|
||||
== arrayBody(t, t->m->types, Machine::StringType))
|
||||
{
|
||||
pushObject(t, v);
|
||||
if (singletonIsObject(t, pool, index - 1)) {
|
||||
object v = singletonObject(t, pool, index - 1);
|
||||
if (objectClass(t, v)
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
object class_ = resolveClassInPool(t, pool, index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
|
||||
pushObject(t, class_);
|
||||
} else {
|
||||
pushObject(t, v);
|
||||
}
|
||||
} else {
|
||||
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
|
||||
pushObject(t, class_);
|
||||
pushInt(t, singletonValue(t, pool, index - 1));
|
||||
}
|
||||
} goto loop;
|
||||
|
||||
case ldc2_w: {
|
||||
uint16_t index = codeReadInt16(t, code, ip);
|
||||
|
||||
object v = arrayBody(t, codePool(t, code), index - 1);
|
||||
object pool = codePool(t, code);
|
||||
|
||||
if (objectClass(t, v) == arrayBody(t, t->m->types, Machine::LongType)
|
||||
or objectClass(t, v) == arrayBody(t, t->m->types, Machine::DoubleType))
|
||||
{
|
||||
pushLong(t, longValue(t, v));
|
||||
} else {
|
||||
abort(t);
|
||||
}
|
||||
uint64_t v;
|
||||
memcpy(&v, &singletonValue(t, pool, index - 1), 8);
|
||||
pushLong(t, v);
|
||||
} goto loop;
|
||||
|
||||
case ldiv_: {
|
||||
@ -2863,15 +2860,45 @@ class MyProcessor: public Processor {
|
||||
}
|
||||
|
||||
virtual object
|
||||
methodStub(vm::Thread*)
|
||||
makeMethod(vm::Thread* t,
|
||||
uint8_t vmFlags,
|
||||
uint8_t returnCode,
|
||||
uint8_t parameterCount,
|
||||
uint8_t parameterFootprint,
|
||||
uint16_t flags,
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object class_,
|
||||
object code)
|
||||
{
|
||||
return 0;
|
||||
return vm::makeMethod
|
||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||
offset, name, spec, class_, code, 0);
|
||||
}
|
||||
|
||||
virtual object
|
||||
nativeInvoker(vm::Thread*)
|
||||
makeClass(vm::Thread* t,
|
||||
uint16_t flags,
|
||||
uint8_t vmFlags,
|
||||
uint8_t arrayDimensions,
|
||||
uint16_t fixedSize,
|
||||
uint16_t arrayElementSize,
|
||||
object objectMask,
|
||||
object name,
|
||||
object super,
|
||||
object interfaceTable,
|
||||
object virtualTable,
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object loader,
|
||||
unsigned vtableLength UNUSED)
|
||||
{
|
||||
return 0;
|
||||
return vm::makeClass
|
||||
(t, flags, vmFlags, arrayDimensions, fixedSize, arrayElementSize,
|
||||
objectMask, name, super, interfaceTable, virtualTable, fieldTable,
|
||||
methodTable, staticTable, loader, 0, false);
|
||||
}
|
||||
|
||||
virtual unsigned
|
||||
|
@ -197,15 +197,15 @@ IsInstanceOf(Thread* t, jobject o, jclass c)
|
||||
}
|
||||
|
||||
object
|
||||
findMethod(Thread* t, object class_, const char* name, const char* spec)
|
||||
findMethod(Thread* t, object c, const char* name, const char* spec)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
PROTECT(t, c);
|
||||
|
||||
object n = makeByteArray(t, "%s", name);
|
||||
PROTECT(t, n);
|
||||
|
||||
object s = makeByteArray(t, "%s", spec);
|
||||
return vm::findMethod(t, class_, n, s);
|
||||
return vm::findMethod(t, c, n, s);
|
||||
}
|
||||
|
||||
jmethodID JNICALL
|
||||
|
439
src/machine.cpp
439
src/machine.cpp
@ -204,13 +204,8 @@ walk(Thread* t, Heap::Walker* w, object o)
|
||||
} 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 + 2) * BytesPerWord, 0, 0);
|
||||
walk(t, w, singletonMask(t, o),
|
||||
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0);
|
||||
} else {
|
||||
w->visit(0);
|
||||
}
|
||||
@ -617,127 +612,151 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned
|
||||
parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
s.setPosition(index[i]);
|
||||
|
||||
switch (s.read1()) {
|
||||
case CONSTANT_Integer:
|
||||
case CONSTANT_Float: {
|
||||
singletonValue(t, pool, i) = s.read4();
|
||||
} return 1;
|
||||
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double: {
|
||||
uint64_t v = s.read8();
|
||||
memcpy(&singletonValue(t, pool, i), &v, 8);
|
||||
} return 2;
|
||||
|
||||
case CONSTANT_Utf8: {
|
||||
if (singletonObject(t, pool, i) == 0) {
|
||||
object value = parseUtf8(t, s, s.read2());
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case CONSTANT_Class: {
|
||||
if (singletonObject(t, pool, i) == 0) {
|
||||
unsigned si = s.read2() - 1;
|
||||
parsePoolEntry(t, s, index, pool, si);
|
||||
|
||||
object value = singletonObject(t, pool, si);
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case CONSTANT_String: {
|
||||
if (singletonObject(t, pool, i) == 0) {
|
||||
unsigned si = s.read2() - 1;
|
||||
parsePoolEntry(t, s, index, pool, si);
|
||||
|
||||
object value = singletonObject(t, pool, si);
|
||||
value = makeString(t, value, 0, byteArrayLength(t, value) - 1, 0);
|
||||
value = intern(t, value);
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case CONSTANT_NameAndType: {
|
||||
if (singletonObject(t, pool, i) == 0) {
|
||||
unsigned ni = s.read2() - 1;
|
||||
unsigned ti = s.read2() - 1;
|
||||
|
||||
parsePoolEntry(t, s, index, pool, ni);
|
||||
parsePoolEntry(t, s, index, pool, ti);
|
||||
|
||||
object name = singletonObject(t, pool, ni);
|
||||
object type = singletonObject(t, pool, ti);
|
||||
object value = makePair(t, name, type);
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
case CONSTANT_Fieldref:
|
||||
case CONSTANT_Methodref:
|
||||
case CONSTANT_InterfaceMethodref: {
|
||||
if (singletonObject(t, pool, i) == 0) {
|
||||
unsigned ci = s.read2() - 1;
|
||||
unsigned nti = s.read2() - 1;
|
||||
|
||||
parsePoolEntry(t, s, index, pool, ci);
|
||||
parsePoolEntry(t, s, index, pool, nti);
|
||||
|
||||
object class_ = singletonObject(t, pool, ci);
|
||||
object nameAndType = singletonObject(t, pool, nti);
|
||||
object value = makeReference
|
||||
(t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
|
||||
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
||||
}
|
||||
} return 1;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
parsePool(Thread* t, Stream& s)
|
||||
{
|
||||
unsigned poolCount = s.read2() - 1;
|
||||
object pool = makeArray(t, poolCount, true);
|
||||
unsigned count = s.read2() - 1;
|
||||
|
||||
PROTECT(t, pool);
|
||||
object pool = makeSingleton(t, count);
|
||||
|
||||
for (unsigned i = 0; i < poolCount; ++i) {
|
||||
unsigned c = s.read1();
|
||||
if (count) {
|
||||
uint32_t* index = static_cast<uint32_t*>
|
||||
(t->m->system->allocate(count * 4));
|
||||
|
||||
switch (c) {
|
||||
case CONSTANT_Integer: {
|
||||
object value = makeInt(t, s.read4());
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
index[i] = s.position();
|
||||
|
||||
case CONSTANT_Float: {
|
||||
object value = makeInt(t, s.readFloat());
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
switch (s.read1()) {
|
||||
case CONSTANT_Class:
|
||||
case CONSTANT_String:
|
||||
singletonMarkObject(t, pool, i);
|
||||
s.skip(2);
|
||||
break;
|
||||
|
||||
case CONSTANT_Long: {
|
||||
object value = makeLong(t, s.read8());
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
++i;
|
||||
} break;
|
||||
case CONSTANT_Integer:
|
||||
case CONSTANT_Float:
|
||||
s.skip(4);
|
||||
break;
|
||||
|
||||
case CONSTANT_Double: {
|
||||
object value = makeLong(t, s.readDouble());
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
++i;
|
||||
} break;
|
||||
|
||||
case CONSTANT_Utf8: {
|
||||
object value = parseUtf8(t, s, s.read2());
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
|
||||
case CONSTANT_Class: {
|
||||
object value = makeIntArray(t, 2, false);
|
||||
intArrayBody(t, value, 0) = c;
|
||||
intArrayBody(t, value, 1) = s.read2();
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
|
||||
case CONSTANT_String: {
|
||||
object value = makeIntArray(t, 2, false);
|
||||
intArrayBody(t, value, 0) = c;
|
||||
intArrayBody(t, value, 1) = s.read2();
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), 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, pool, ArrayBody + (i * BytesPerWord), 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, pool, ArrayBody + (i * BytesPerWord), 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->m->types, Machine::IntArrayType))
|
||||
{
|
||||
switch (intArrayBody(t, o, 0)) {
|
||||
case CONSTANT_Class: {
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord),
|
||||
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);
|
||||
value = intern(t, value);
|
||||
set(t, pool, ArrayBody + (i * BytesPerWord), 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, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < poolCount; ++i) {
|
||||
object o = arrayBody(t, pool, i);
|
||||
if (o and objectClass(t, o)
|
||||
== arrayBody(t, t->m->types, Machine::IntArrayType))
|
||||
{
|
||||
switch (intArrayBody(t, o, 0)) {
|
||||
case CONSTANT_NameAndType:
|
||||
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, pool, ArrayBody + (i * BytesPerWord), value);
|
||||
} break;
|
||||
case CONSTANT_InterfaceMethodref:
|
||||
singletonMarkObject(t, pool, i);
|
||||
s.skip(4);
|
||||
break;
|
||||
|
||||
case CONSTANT_Long:
|
||||
case CONSTANT_Double:
|
||||
s.skip(8);
|
||||
++ i;
|
||||
break;
|
||||
|
||||
case CONSTANT_Utf8:
|
||||
singletonMarkObject(t, pool, i);
|
||||
s.skip(s.read2());
|
||||
break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned end = s.position();
|
||||
|
||||
PROTECT(t, pool);
|
||||
|
||||
for (unsigned i = 0; i < count;) {
|
||||
i += parsePoolEntry(t, s, index, pool, i);
|
||||
}
|
||||
|
||||
t->m->system->free(index);
|
||||
|
||||
s.setPosition(end);
|
||||
}
|
||||
|
||||
return pool;
|
||||
@ -780,7 +799,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
unsigned count = s.read2();
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
object name = arrayBody(t, pool, s.read2() - 1);
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
PROTECT(t, name);
|
||||
|
||||
object interface = resolveClass(t, name);
|
||||
@ -861,31 +880,53 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object value = 0;
|
||||
PROTECT(t, value);
|
||||
|
||||
unsigned code = fieldCode
|
||||
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
|
||||
|
||||
unsigned attributeCount = s.read2();
|
||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||
object name = arrayBody(t, pool, s.read2() - 1);
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
unsigned length = s.read4();
|
||||
|
||||
if (strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
value = arrayBody(t, pool, s.read2() - 1);
|
||||
switch (code) {
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
case CharField:
|
||||
case ShortField:
|
||||
case IntField:
|
||||
case FloatField:
|
||||
value = makeInt(t, singletonValue(t, pool, s.read2() - 1));
|
||||
break;
|
||||
|
||||
case LongField:
|
||||
case DoubleField: {
|
||||
uint64_t v;
|
||||
memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
|
||||
value = makeLong(t, v);
|
||||
} break;
|
||||
|
||||
case ObjectField:
|
||||
value = singletonObject(t, pool, s.read2() - 1);
|
||||
break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned code = fieldCode
|
||||
(t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0));
|
||||
|
||||
object field = makeField
|
||||
(t,
|
||||
0, // vm flags
|
||||
code,
|
||||
flags,
|
||||
0, // offset
|
||||
arrayBody(t, pool, name - 1),
|
||||
arrayBody(t, pool, spec - 1),
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
class_);
|
||||
|
||||
if (flags & ACC_STATIC) {
|
||||
@ -925,19 +966,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
if (staticCount) {
|
||||
unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2),
|
||||
BytesPerWord);
|
||||
unsigned maskSize = ceiling(footprint + 2, BitsPerWord);
|
||||
object staticTable = makeSingleton(t, footprint + maskSize, false);
|
||||
object staticTable = makeSingleton(t, footprint);
|
||||
|
||||
uint8_t* body = reinterpret_cast<uint8_t*>
|
||||
(&singletonBody(t, staticTable, 0));
|
||||
|
||||
uint32_t* mask = reinterpret_cast<uint32_t*>
|
||||
(&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;
|
||||
@ -979,8 +1012,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
|
||||
if (staticTypes[i] == ObjectField) {
|
||||
unsigned index = (offset / BytesPerWord) + 2;
|
||||
mask[index / 32] |= static_cast<uint32_t>(1) << (index % 32);
|
||||
singletonMarkObject(t, staticTable, offset / BytesPerWord);
|
||||
}
|
||||
|
||||
offset += size;
|
||||
@ -1064,7 +1096,7 @@ parseCode(Thread* t, Stream& s, object pool)
|
||||
|
||||
unsigned attributeCount = s.read2();
|
||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||
object name = arrayBody(t, pool, s.read2() - 1);
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
unsigned length = s.read4();
|
||||
|
||||
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
||||
@ -1181,7 +1213,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object code = 0;
|
||||
unsigned attributeCount = s.read2();
|
||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||
object name = arrayBody(t, pool, s.read2() - 1);
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
unsigned length = s.read4();
|
||||
|
||||
if (strcmp(reinterpret_cast<const int8_t*>("Code"),
|
||||
@ -1194,7 +1226,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
|
||||
const char* specString = reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, arrayBody(t, pool, spec - 1), 0));
|
||||
(&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
|
||||
|
||||
unsigned parameterCount;
|
||||
unsigned returnCode;
|
||||
@ -1203,25 +1235,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
||||
(t, specString, flags & ACC_STATIC);
|
||||
|
||||
object compiled;
|
||||
if (flags & ACC_NATIVE) {
|
||||
compiled = t->m->processor->nativeInvoker(t);
|
||||
} else {
|
||||
compiled = t->m->processor->methodStub(t);
|
||||
}
|
||||
object method = t->m->processor->makeMethod
|
||||
(t,
|
||||
0, // vm flags
|
||||
returnCode,
|
||||
parameterCount,
|
||||
parameterFootprint,
|
||||
flags,
|
||||
0, // offset
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
class_,
|
||||
code);
|
||||
|
||||
object method = makeMethod(t,
|
||||
0, // vm flags
|
||||
returnCode,
|
||||
parameterCount,
|
||||
parameterFootprint,
|
||||
flags,
|
||||
0, // offset
|
||||
arrayBody(t, pool, name - 1),
|
||||
arrayBody(t, pool, spec - 1),
|
||||
class_,
|
||||
code,
|
||||
compiled);
|
||||
PROTECT(t, method);
|
||||
|
||||
if (methodVirtual(t, method)) {
|
||||
@ -1357,6 +1383,35 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
updateClassTables(Thread* t, object newClass, object oldClass)
|
||||
{
|
||||
object fieldTable = classFieldTable(t, newClass);
|
||||
if (fieldTable) {
|
||||
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
|
||||
set(t, arrayBody(t, fieldTable, i), FieldClass, newClass);
|
||||
}
|
||||
}
|
||||
|
||||
if (classFlags(t, newClass) & ACC_INTERFACE) {
|
||||
object virtualTable = classVirtualTable(t, newClass);
|
||||
if (virtualTable) {
|
||||
for (unsigned i = 0; i < arrayLength(t, virtualTable); ++i) {
|
||||
if (methodClass(t, arrayBody(t, virtualTable, i)) == oldClass) {
|
||||
set(t, arrayBody(t, virtualTable, i), MethodClass, newClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object methodTable = classMethodTable(t, newClass);
|
||||
if (methodTable) {
|
||||
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
||||
set(t, arrayBody(t, methodTable, i), MethodClass, newClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
||||
{
|
||||
@ -1364,7 +1419,10 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object 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, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType)
|
||||
or classFixedSize(t, bootstrapClass) == classFixedSize(t, class_));
|
||||
|
||||
expect(t,
|
||||
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
|
||||
or (classObjectMask(t, bootstrapClass) == 0
|
||||
@ -1388,19 +1446,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
||||
set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_));
|
||||
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
|
||||
|
||||
object fieldTable = classFieldTable(t, class_);
|
||||
if (fieldTable) {
|
||||
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
|
||||
set(t, arrayBody(t, fieldTable, i), FieldClass, bootstrapClass);
|
||||
}
|
||||
}
|
||||
|
||||
object methodTable = classMethodTable(t, class_);
|
||||
if (methodTable) {
|
||||
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
||||
set(t, arrayBody(t, methodTable, i), MethodClass, bootstrapClass);
|
||||
}
|
||||
}
|
||||
updateClassTables(t, bootstrapClass, class_);
|
||||
}
|
||||
|
||||
object
|
||||
@ -1408,7 +1454,10 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec,
|
||||
object elementClass)
|
||||
{
|
||||
// todo: arrays should implement Cloneable and Serializable
|
||||
return makeClass
|
||||
object vtable = classVirtualTable
|
||||
(t, arrayBody(t, t->m->types, Machine::JobjectType));
|
||||
|
||||
return t->m->processor->makeClass
|
||||
(t,
|
||||
0,
|
||||
0,
|
||||
@ -1419,11 +1468,12 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec,
|
||||
spec,
|
||||
arrayBody(t, t->m->types, Machine::JobjectType),
|
||||
0,
|
||||
classVirtualTable(t, arrayBody(t, t->m->types, Machine::JobjectType)),
|
||||
vtable,
|
||||
0,
|
||||
0,
|
||||
elementClass,
|
||||
t->m->loader);
|
||||
t->m->loader,
|
||||
arrayLength(t, vtable));
|
||||
}
|
||||
|
||||
object
|
||||
@ -1517,7 +1567,7 @@ invoke(Thread* t, const char* className, int argc, const char** argv)
|
||||
|
||||
void
|
||||
bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
||||
unsigned fixedSize, unsigned arrayElementSize)
|
||||
unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength)
|
||||
{
|
||||
object mask;
|
||||
if (objectMask) {
|
||||
@ -1529,9 +1579,9 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
||||
|
||||
object super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0);
|
||||
|
||||
object class_ = makeClass
|
||||
object class_ = t->m->processor->makeClass
|
||||
(t, 0, BootstrapFlag, 0, fixedSize, arrayElementSize, mask, 0, super, 0, 0,
|
||||
0, 0, 0, t->m->loader);
|
||||
0, 0, 0, t->m->loader, vtableLength);
|
||||
|
||||
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
|
||||
}
|
||||
@ -2517,7 +2567,7 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
||||
public:
|
||||
Client(Thread* t): t(t) { }
|
||||
|
||||
virtual void NO_RETURN handleEOS() {
|
||||
virtual void NO_RETURN handleError() {
|
||||
abort(t);
|
||||
}
|
||||
|
||||
@ -2545,19 +2595,21 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
||||
0, // fixed size
|
||||
0, // array size
|
||||
0, // object mask
|
||||
arrayBody(t, pool, name - 1),
|
||||
singletonObject(t, pool, name - 1),
|
||||
0, // super
|
||||
0, // interfaces
|
||||
0, // vtable
|
||||
0, // fields
|
||||
0, // methods
|
||||
0, // static table
|
||||
t->m->loader);
|
||||
t->m->loader,
|
||||
0, // vtable length
|
||||
false);
|
||||
PROTECT(t, class_);
|
||||
|
||||
unsigned super = s.read2();
|
||||
if (super) {
|
||||
object sc = resolveClass(t, arrayBody(t, pool, super - 1));
|
||||
object sc = resolveClass(t, singletonObject(t, pool, super - 1));
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, class_, ClassSuper, sc);
|
||||
@ -2575,7 +2627,30 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
||||
parseMethodTable(t, s, class_, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
return class_;
|
||||
object vtable = classVirtualTable(t, class_);
|
||||
unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0);
|
||||
|
||||
object real = t->m->processor->makeClass
|
||||
(t,
|
||||
classFlags(t, class_),
|
||||
classVmFlags(t, class_),
|
||||
classArrayDimensions(t, class_),
|
||||
classFixedSize(t, class_),
|
||||
classArrayElementSize(t, class_),
|
||||
classObjectMask(t, class_),
|
||||
className(t, class_),
|
||||
classSuper(t, class_),
|
||||
classInterfaceTable(t, class_),
|
||||
classVirtualTable(t, class_),
|
||||
classFieldTable(t, class_),
|
||||
classMethodTable(t, class_),
|
||||
classStaticTable(t, class_),
|
||||
classLoader(t, class_),
|
||||
vtableLength);
|
||||
|
||||
updateClassTables(t, real, class_);
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
object
|
||||
@ -2616,7 +2691,9 @@ resolveClass(Thread* t, object spec)
|
||||
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "done parsing %s\n", &byteArrayBody(t, spec, 0));
|
||||
fprintf(stderr, "done parsing %s: %p\n",
|
||||
&byteArrayBody(t, spec, 0),
|
||||
class_);
|
||||
}
|
||||
|
||||
object bootstrapClass = hashMapFind
|
||||
|
@ -2188,6 +2188,79 @@ methodVirtual(Thread* t, object method)
|
||||
and byteArrayBody(t, methodName(t, method), 0) != '<';
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
singletonMaskSize(unsigned count)
|
||||
{
|
||||
if (count) {
|
||||
return ceiling(count + 2, BitsPerWord);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
singletonMaskSize(Thread* t, object singleton)
|
||||
{
|
||||
unsigned length = singletonLength(t, singleton);
|
||||
if (length) {
|
||||
return ceiling(length + 2, BitsPerWord + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
singletonCount(Thread* t, object singleton)
|
||||
{
|
||||
return singletonLength(t, singleton) - singletonMaskSize(t, singleton);
|
||||
}
|
||||
|
||||
inline uint32_t*
|
||||
singletonMask(Thread* t, object singleton)
|
||||
{
|
||||
assert(t, singletonLength(t, singleton));
|
||||
return reinterpret_cast<uint32_t*>
|
||||
(&singletonBody(t, singleton, singletonCount(t, singleton)));
|
||||
}
|
||||
|
||||
inline void
|
||||
singletonMarkObject(Thread* t, object singleton, unsigned index)
|
||||
{
|
||||
singletonMask(t, singleton)[(index + 2) / 32]
|
||||
|= (static_cast<uint32_t>(1) << ((index + 2) % 32));
|
||||
}
|
||||
|
||||
inline bool
|
||||
singletonIsObject(Thread* t, object singleton, unsigned index)
|
||||
{
|
||||
assert(t, index < singletonCount(t, singleton));
|
||||
|
||||
return (singletonMask(t, singleton)[(index + 2) / 32]
|
||||
& (static_cast<uint32_t>(1) << ((index + 2) % 32))) != 0;
|
||||
}
|
||||
|
||||
inline object
|
||||
singletonObject(Thread* t, object singleton, unsigned index)
|
||||
{
|
||||
assert(t, singletonIsObject(t, singleton, index));
|
||||
return reinterpret_cast<object>(singletonBody(t, singleton, index));
|
||||
}
|
||||
|
||||
inline uintptr_t&
|
||||
singletonValue(Thread* t, object singleton, unsigned index)
|
||||
{
|
||||
assert(t, not singletonIsObject(t, singleton, index));
|
||||
return singletonBody(t, singleton, index);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeSingleton(Thread* t, unsigned count)
|
||||
{
|
||||
object o = makeSingleton(t, count + singletonMaskSize(count), true);
|
||||
if (count) {
|
||||
singletonMask(t, o)[0] = 1;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//MACHINE_H
|
||||
|
@ -45,7 +45,7 @@ resolveClassInObject(Thread* t, object container, unsigned classOffset)
|
||||
inline object
|
||||
resolveClassInPool(Thread* t, object pool, unsigned index)
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
object o = singletonObject(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
@ -53,7 +53,7 @@ resolveClassInPool(Thread* t, object pool, unsigned index)
|
||||
o = resolveClass(t, o);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, pool, ArrayBody + (index * BytesPerWord), o);
|
||||
set(t, pool, SingletonBody + (index * BytesPerWord), o);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
@ -63,7 +63,7 @@ resolve(Thread* t, object pool, unsigned index,
|
||||
object (*find)(vm::Thread*, object, object, object),
|
||||
object (*makeError)(vm::Thread*, object))
|
||||
{
|
||||
object o = arrayBody(t, pool, index);
|
||||
object o = singletonObject(t, pool, index);
|
||||
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType))
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
@ -79,7 +79,7 @@ resolve(Thread* t, object pool, unsigned index,
|
||||
find, makeError);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, pool, ArrayBody + (index * BytesPerWord), o);
|
||||
set(t, pool, SingletonBody + (index * BytesPerWord), o);
|
||||
}
|
||||
|
||||
return o;
|
||||
|
@ -15,10 +15,35 @@ class Processor {
|
||||
makeThread(Machine* m, object javaThread, Thread* parent) = 0;
|
||||
|
||||
virtual object
|
||||
methodStub(Thread* t) = 0;
|
||||
makeMethod(Thread* t,
|
||||
uint8_t vmFlags,
|
||||
uint8_t returnCode,
|
||||
uint8_t parameterCount,
|
||||
uint8_t parameterFootprint,
|
||||
uint16_t flags,
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object class_,
|
||||
object code) = 0;
|
||||
|
||||
virtual object
|
||||
nativeInvoker(Thread* t) = 0;
|
||||
makeClass(Thread* t,
|
||||
uint16_t flags,
|
||||
uint8_t vmFlags,
|
||||
uint8_t arrayDimensions,
|
||||
uint16_t fixedSize,
|
||||
uint16_t arrayElementSize,
|
||||
object objectMask,
|
||||
object name,
|
||||
object super,
|
||||
object interfaceTable,
|
||||
object virtualTable,
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object loader,
|
||||
unsigned vtableLength) = 0;
|
||||
|
||||
virtual unsigned
|
||||
parameterFootprint(Thread* t, const char* spec, bool static_) = 0;
|
||||
|
28
src/stream.h
28
src/stream.h
@ -10,27 +10,35 @@ class Stream {
|
||||
class Client {
|
||||
public:
|
||||
virtual ~Client() { }
|
||||
virtual void NO_RETURN handleEOS() = 0;
|
||||
virtual void NO_RETURN handleError() = 0;
|
||||
};
|
||||
|
||||
Stream(Client* client, const uint8_t* data, unsigned size):
|
||||
client(client), data(data), size(size), position(0)
|
||||
client(client), data(data), size(size), position_(0)
|
||||
{ }
|
||||
|
||||
unsigned position() {
|
||||
return position_;
|
||||
}
|
||||
|
||||
void setPosition(unsigned p) {
|
||||
position_ = p;
|
||||
}
|
||||
|
||||
void skip(unsigned size) {
|
||||
if (size > this->size - position) {
|
||||
client->handleEOS();
|
||||
if (size > this->size - position_) {
|
||||
client->handleError();
|
||||
} else {
|
||||
position += size;
|
||||
position_ += size;
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint8_t* data, unsigned size) {
|
||||
if (size > this->size - position) {
|
||||
client->handleEOS();
|
||||
if (size > this->size - position_) {
|
||||
client->handleError();
|
||||
} else {
|
||||
memcpy(data, this->data + position, size);
|
||||
position += size;
|
||||
memcpy(data, this->data + position_, size);
|
||||
position_ += size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +78,7 @@ class Stream {
|
||||
Client* client;
|
||||
const uint8_t* data;
|
||||
unsigned size;
|
||||
unsigned position;
|
||||
unsigned position_;
|
||||
};
|
||||
|
||||
} // namespace vm
|
||||
|
@ -1351,6 +1351,12 @@ parseJavaClass(Object* type, Stream* s, Object* declarations)
|
||||
}
|
||||
}
|
||||
|
||||
if (equal(typeJavaName(type), "java/lang/Class")) {
|
||||
// add inline vtable
|
||||
addMember(type, Array::make
|
||||
(type, 0, "void*", "vtable", sizeOf("void*", 0)));
|
||||
}
|
||||
|
||||
if (typeSuper(type)) {
|
||||
for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) {
|
||||
addMethod(type, car(p));
|
||||
@ -2114,6 +2120,9 @@ writeInitialization(Output* out, Object* type)
|
||||
out->write(", ");
|
||||
|
||||
out->write(typeArrayElementSize(type));
|
||||
out->write(", ");
|
||||
|
||||
out->write(methodCount(type));
|
||||
out->write(");\n");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user