mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +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
|
classpath = classpath
|
||||||
test = test
|
test = test
|
||||||
|
|
||||||
input = $(test-build)/References.class
|
input = $(test-build)/List.class
|
||||||
|
|
||||||
build-cxx = g++
|
build-cxx = g++
|
||||||
build-cc = gcc
|
build-cc = gcc
|
||||||
|
@ -2051,36 +2051,33 @@ interpret(Thread* t)
|
|||||||
index = codeReadInt16(t, code, ip);
|
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)
|
if (singletonIsObject(t, pool, index - 1)) {
|
||||||
or objectClass(t, v) == arrayBody(t, t->m->types, Machine::FloatType))
|
object v = singletonObject(t, pool, index - 1);
|
||||||
{
|
if (objectClass(t, v)
|
||||||
pushInt(t, intValue(t, v));
|
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||||
} else if (objectClass(t, v)
|
{
|
||||||
== arrayBody(t, t->m->types, Machine::StringType))
|
object class_ = resolveClassInPool(t, pool, index - 1);
|
||||||
{
|
if (UNLIKELY(exception)) goto throw_;
|
||||||
pushObject(t, v);
|
|
||||||
|
pushObject(t, class_);
|
||||||
|
} else {
|
||||||
|
pushObject(t, v);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
|
pushInt(t, singletonValue(t, pool, index - 1));
|
||||||
if (UNLIKELY(exception)) goto throw_;
|
|
||||||
|
|
||||||
pushObject(t, class_);
|
|
||||||
}
|
}
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case ldc2_w: {
|
case ldc2_w: {
|
||||||
uint16_t index = codeReadInt16(t, code, ip);
|
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)
|
uint64_t v;
|
||||||
or objectClass(t, v) == arrayBody(t, t->m->types, Machine::DoubleType))
|
memcpy(&v, &singletonValue(t, pool, index - 1), 8);
|
||||||
{
|
pushLong(t, v);
|
||||||
pushLong(t, longValue(t, v));
|
|
||||||
} else {
|
|
||||||
abort(t);
|
|
||||||
}
|
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case ldiv_: {
|
case ldiv_: {
|
||||||
@ -2863,15 +2860,45 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual object
|
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
|
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
|
virtual unsigned
|
||||||
|
@ -197,15 +197,15 @@ IsInstanceOf(Thread* t, jobject o, jclass c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
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);
|
object n = makeByteArray(t, "%s", name);
|
||||||
PROTECT(t, n);
|
PROTECT(t, n);
|
||||||
|
|
||||||
object s = makeByteArray(t, "%s", spec);
|
object s = makeByteArray(t, "%s", spec);
|
||||||
return vm::findMethod(t, class_, n, s);
|
return vm::findMethod(t, c, n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID JNICALL
|
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) {
|
} else if (classVmFlags(t, class_) & SingletonFlag) {
|
||||||
unsigned length = singletonLength(t, o);
|
unsigned length = singletonLength(t, o);
|
||||||
if (length) {
|
if (length) {
|
||||||
unsigned maskSize = ceiling(length + 2, BitsPerWord + 1);
|
walk(t, w, singletonMask(t, o),
|
||||||
|
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0);
|
||||||
uint32_t mask[maskSize * (BytesPerWord / 4)];
|
|
||||||
memcpy(mask, &singletonBody(t, o, length - maskSize),
|
|
||||||
maskSize * BytesPerWord);
|
|
||||||
|
|
||||||
walk(t, w, mask, (length + 2) * BytesPerWord, 0, 0);
|
|
||||||
} else {
|
} else {
|
||||||
w->visit(0);
|
w->visit(0);
|
||||||
}
|
}
|
||||||
@ -617,127 +612,151 @@ parseUtf8(Thread* t, Stream& s, unsigned length)
|
|||||||
return value;
|
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
|
object
|
||||||
parsePool(Thread* t, Stream& s)
|
parsePool(Thread* t, Stream& s)
|
||||||
{
|
{
|
||||||
unsigned poolCount = s.read2() - 1;
|
unsigned count = s.read2() - 1;
|
||||||
object pool = makeArray(t, poolCount, true);
|
|
||||||
|
|
||||||
PROTECT(t, pool);
|
object pool = makeSingleton(t, count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < poolCount; ++i) {
|
if (count) {
|
||||||
unsigned c = s.read1();
|
uint32_t* index = static_cast<uint32_t*>
|
||||||
|
(t->m->system->allocate(count * 4));
|
||||||
|
|
||||||
switch (c) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
case CONSTANT_Integer: {
|
index[i] = s.position();
|
||||||
object value = makeInt(t, s.read4());
|
|
||||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case CONSTANT_Float: {
|
switch (s.read1()) {
|
||||||
object value = makeInt(t, s.readFloat());
|
case CONSTANT_Class:
|
||||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
case CONSTANT_String:
|
||||||
} break;
|
singletonMarkObject(t, pool, i);
|
||||||
|
s.skip(2);
|
||||||
|
break;
|
||||||
|
|
||||||
case CONSTANT_Long: {
|
case CONSTANT_Integer:
|
||||||
object value = makeLong(t, s.read8());
|
case CONSTANT_Float:
|
||||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
s.skip(4);
|
||||||
++i;
|
break;
|
||||||
} break;
|
|
||||||
|
|
||||||
case CONSTANT_Double: {
|
case CONSTANT_NameAndType:
|
||||||
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_Fieldref:
|
case CONSTANT_Fieldref:
|
||||||
case CONSTANT_Methodref:
|
case CONSTANT_Methodref:
|
||||||
case CONSTANT_InterfaceMethodref: {
|
case CONSTANT_InterfaceMethodref:
|
||||||
object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
singletonMarkObject(t, pool, i);
|
||||||
object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
|
s.skip(4);
|
||||||
object value = makeReference
|
break;
|
||||||
(t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
|
|
||||||
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
case CONSTANT_Long:
|
||||||
} break;
|
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;
|
return pool;
|
||||||
@ -780,7 +799,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
|
|
||||||
unsigned count = s.read2();
|
unsigned count = s.read2();
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
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);
|
PROTECT(t, name);
|
||||||
|
|
||||||
object interface = resolveClass(t, name);
|
object interface = resolveClass(t, name);
|
||||||
@ -861,31 +880,53 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
object value = 0;
|
object value = 0;
|
||||||
PROTECT(t, value);
|
PROTECT(t, value);
|
||||||
|
|
||||||
|
unsigned code = fieldCode
|
||||||
|
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
|
||||||
|
|
||||||
unsigned attributeCount = s.read2();
|
unsigned attributeCount = s.read2();
|
||||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
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();
|
unsigned length = s.read4();
|
||||||
|
|
||||||
if (strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
|
if (strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
|
||||||
&byteArrayBody(t, name, 0)) == 0)
|
&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 {
|
} else {
|
||||||
s.skip(length);
|
s.skip(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned code = fieldCode
|
|
||||||
(t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0));
|
|
||||||
|
|
||||||
object field = makeField
|
object field = makeField
|
||||||
(t,
|
(t,
|
||||||
0, // vm flags
|
0, // vm flags
|
||||||
code,
|
code,
|
||||||
flags,
|
flags,
|
||||||
0, // offset
|
0, // offset
|
||||||
arrayBody(t, pool, name - 1),
|
singletonObject(t, pool, name - 1),
|
||||||
arrayBody(t, pool, spec - 1),
|
singletonObject(t, pool, spec - 1),
|
||||||
class_);
|
class_);
|
||||||
|
|
||||||
if (flags & ACC_STATIC) {
|
if (flags & ACC_STATIC) {
|
||||||
@ -925,19 +966,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
if (staticCount) {
|
if (staticCount) {
|
||||||
unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2),
|
unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2),
|
||||||
BytesPerWord);
|
BytesPerWord);
|
||||||
unsigned maskSize = ceiling(footprint + 2, BitsPerWord);
|
object staticTable = makeSingleton(t, footprint);
|
||||||
object staticTable = makeSingleton(t, footprint + maskSize, false);
|
|
||||||
|
|
||||||
uint8_t* body = reinterpret_cast<uint8_t*>
|
uint8_t* body = reinterpret_cast<uint8_t*>
|
||||||
(&singletonBody(t, staticTable, 0));
|
(&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) {
|
for (unsigned i = 0, offset = 0; i < staticCount; ++i) {
|
||||||
unsigned size = fieldSize(t, staticTypes[i]);
|
unsigned size = fieldSize(t, staticTypes[i]);
|
||||||
unsigned excess = offset % size;
|
unsigned excess = offset % size;
|
||||||
@ -979,8 +1012,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (staticTypes[i] == ObjectField) {
|
if (staticTypes[i] == ObjectField) {
|
||||||
unsigned index = (offset / BytesPerWord) + 2;
|
singletonMarkObject(t, staticTable, offset / BytesPerWord);
|
||||||
mask[index / 32] |= static_cast<uint32_t>(1) << (index % 32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
@ -1064,7 +1096,7 @@ parseCode(Thread* t, Stream& s, object pool)
|
|||||||
|
|
||||||
unsigned attributeCount = s.read2();
|
unsigned attributeCount = s.read2();
|
||||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
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();
|
unsigned length = s.read4();
|
||||||
|
|
||||||
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
||||||
@ -1181,7 +1213,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
object code = 0;
|
object code = 0;
|
||||||
unsigned attributeCount = s.read2();
|
unsigned attributeCount = s.read2();
|
||||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
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();
|
unsigned length = s.read4();
|
||||||
|
|
||||||
if (strcmp(reinterpret_cast<const int8_t*>("Code"),
|
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*>
|
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 parameterCount;
|
||||||
unsigned returnCode;
|
unsigned returnCode;
|
||||||
@ -1203,25 +1235,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|||||||
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
||||||
(t, specString, flags & ACC_STATIC);
|
(t, specString, flags & ACC_STATIC);
|
||||||
|
|
||||||
object compiled;
|
object method = t->m->processor->makeMethod
|
||||||
if (flags & ACC_NATIVE) {
|
(t,
|
||||||
compiled = t->m->processor->nativeInvoker(t);
|
0, // vm flags
|
||||||
} else {
|
returnCode,
|
||||||
compiled = t->m->processor->methodStub(t);
|
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);
|
PROTECT(t, method);
|
||||||
|
|
||||||
if (methodVirtual(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
|
void
|
||||||
updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
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
|
// verify that the classes have the same layout
|
||||||
expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_));
|
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,
|
expect(t,
|
||||||
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
|
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
|
||||||
or (classObjectMask(t, bootstrapClass) == 0
|
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, ClassMethodTable, classMethodTable(t, class_));
|
||||||
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
|
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
|
||||||
|
|
||||||
object fieldTable = classFieldTable(t, class_);
|
updateClassTables(t, bootstrapClass, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -1408,7 +1454,10 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec,
|
|||||||
object elementClass)
|
object elementClass)
|
||||||
{
|
{
|
||||||
// todo: arrays should implement Cloneable and Serializable
|
// 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,
|
(t,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -1419,11 +1468,12 @@ makeArrayClass(Thread* t, unsigned dimensions, object spec,
|
|||||||
spec,
|
spec,
|
||||||
arrayBody(t, t->m->types, Machine::JobjectType),
|
arrayBody(t, t->m->types, Machine::JobjectType),
|
||||||
0,
|
0,
|
||||||
classVirtualTable(t, arrayBody(t, t->m->types, Machine::JobjectType)),
|
vtable,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
elementClass,
|
elementClass,
|
||||||
t->m->loader);
|
t->m->loader,
|
||||||
|
arrayLength(t, vtable));
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
@ -1517,7 +1567,7 @@ invoke(Thread* t, const char* className, int argc, const char** argv)
|
|||||||
|
|
||||||
void
|
void
|
||||||
bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
||||||
unsigned fixedSize, unsigned arrayElementSize)
|
unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength)
|
||||||
{
|
{
|
||||||
object mask;
|
object mask;
|
||||||
if (objectMask) {
|
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 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,
|
(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_);
|
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
|
||||||
}
|
}
|
||||||
@ -2517,7 +2567,7 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
|||||||
public:
|
public:
|
||||||
Client(Thread* t): t(t) { }
|
Client(Thread* t): t(t) { }
|
||||||
|
|
||||||
virtual void NO_RETURN handleEOS() {
|
virtual void NO_RETURN handleError() {
|
||||||
abort(t);
|
abort(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2545,19 +2595,21 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
|||||||
0, // fixed size
|
0, // fixed size
|
||||||
0, // array size
|
0, // array size
|
||||||
0, // object mask
|
0, // object mask
|
||||||
arrayBody(t, pool, name - 1),
|
singletonObject(t, pool, name - 1),
|
||||||
0, // super
|
0, // super
|
||||||
0, // interfaces
|
0, // interfaces
|
||||||
0, // vtable
|
0, // vtable
|
||||||
0, // fields
|
0, // fields
|
||||||
0, // methods
|
0, // methods
|
||||||
0, // static table
|
0, // static table
|
||||||
t->m->loader);
|
t->m->loader,
|
||||||
|
0, // vtable length
|
||||||
|
false);
|
||||||
PROTECT(t, class_);
|
PROTECT(t, class_);
|
||||||
|
|
||||||
unsigned super = s.read2();
|
unsigned super = s.read2();
|
||||||
if (super) {
|
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;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
set(t, class_, ClassSuper, sc);
|
set(t, class_, ClassSuper, sc);
|
||||||
@ -2575,7 +2627,30 @@ parseClass(Thread* t, const uint8_t* data, unsigned size)
|
|||||||
parseMethodTable(t, s, class_, pool);
|
parseMethodTable(t, s, class_, pool);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
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
|
object
|
||||||
@ -2616,7 +2691,9 @@ resolveClass(Thread* t, object spec)
|
|||||||
|
|
||||||
if (LIKELY(t->exception == 0)) {
|
if (LIKELY(t->exception == 0)) {
|
||||||
if (Verbose) {
|
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
|
object bootstrapClass = hashMapFind
|
||||||
|
@ -2188,6 +2188,79 @@ methodVirtual(Thread* t, object method)
|
|||||||
and byteArrayBody(t, methodName(t, method), 0) != '<';
|
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
|
} // namespace vm
|
||||||
|
|
||||||
#endif//MACHINE_H
|
#endif//MACHINE_H
|
||||||
|
@ -45,7 +45,7 @@ resolveClassInObject(Thread* t, object container, unsigned classOffset)
|
|||||||
inline object
|
inline object
|
||||||
resolveClassInPool(Thread* t, object pool, unsigned index)
|
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))
|
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||||
{
|
{
|
||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
@ -53,7 +53,7 @@ resolveClassInPool(Thread* t, object pool, unsigned index)
|
|||||||
o = resolveClass(t, o);
|
o = resolveClass(t, o);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
set(t, pool, ArrayBody + (index * BytesPerWord), o);
|
set(t, pool, SingletonBody + (index * BytesPerWord), o);
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ resolve(Thread* t, object pool, unsigned index,
|
|||||||
object (*find)(vm::Thread*, object, object, object),
|
object (*find)(vm::Thread*, object, object, object),
|
||||||
object (*makeError)(vm::Thread*, 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))
|
if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType))
|
||||||
{
|
{
|
||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
@ -79,7 +79,7 @@ resolve(Thread* t, object pool, unsigned index,
|
|||||||
find, makeError);
|
find, makeError);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
set(t, pool, ArrayBody + (index * BytesPerWord), o);
|
set(t, pool, SingletonBody + (index * BytesPerWord), o);
|
||||||
}
|
}
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
|
@ -15,10 +15,35 @@ class Processor {
|
|||||||
makeThread(Machine* m, object javaThread, Thread* parent) = 0;
|
makeThread(Machine* m, object javaThread, Thread* parent) = 0;
|
||||||
|
|
||||||
virtual object
|
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
|
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
|
virtual unsigned
|
||||||
parameterFootprint(Thread* t, const char* spec, bool static_) = 0;
|
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 {
|
class Client {
|
||||||
public:
|
public:
|
||||||
virtual ~Client() { }
|
virtual ~Client() { }
|
||||||
virtual void NO_RETURN handleEOS() = 0;
|
virtual void NO_RETURN handleError() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Stream(Client* client, const uint8_t* data, unsigned size):
|
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) {
|
void skip(unsigned size) {
|
||||||
if (size > this->size - position) {
|
if (size > this->size - position_) {
|
||||||
client->handleEOS();
|
client->handleError();
|
||||||
} else {
|
} else {
|
||||||
position += size;
|
position_ += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void read(uint8_t* data, unsigned size) {
|
void read(uint8_t* data, unsigned size) {
|
||||||
if (size > this->size - position) {
|
if (size > this->size - position_) {
|
||||||
client->handleEOS();
|
client->handleError();
|
||||||
} else {
|
} else {
|
||||||
memcpy(data, this->data + position, size);
|
memcpy(data, this->data + position_, size);
|
||||||
position += size;
|
position_ += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +78,7 @@ class Stream {
|
|||||||
Client* client;
|
Client* client;
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
unsigned position;
|
unsigned position_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vm
|
} // 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)) {
|
if (typeSuper(type)) {
|
||||||
for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) {
|
for (Object* p = typeMethods(typeSuper(type)); p; p = cdr(p)) {
|
||||||
addMethod(type, car(p));
|
addMethod(type, car(p));
|
||||||
@ -2114,6 +2120,9 @@ writeInitialization(Output* out, Object* type)
|
|||||||
out->write(", ");
|
out->write(", ");
|
||||||
|
|
||||||
out->write(typeArrayElementSize(type));
|
out->write(typeArrayElementSize(type));
|
||||||
|
out->write(", ");
|
||||||
|
|
||||||
|
out->write(methodCount(type));
|
||||||
out->write(");\n");
|
out->write(");\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user