mirror of
https://github.com/corda/corda.git
synced 2025-06-15 21:58:17 +00:00
support runtime-visible annotations and java.lang.reflect.Proxy
This commit is contained in:
449
src/builtin.cpp
449
src/builtin.cpp
@ -79,6 +79,242 @@ runOnLoadIfFound(Thread* t, System::Library* library)
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL
|
||||
proxyConstruct(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
set(t, reinterpret_cast<object>(arguments[0]), ProxyH,
|
||||
reinterpret_cast<object>(arguments[1]));
|
||||
}
|
||||
|
||||
int64_t JNICALL
|
||||
proxyInvoke(Thread* t, object method, uintptr_t* arguments)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
unsigned size = methodParameterFootprint(t, method);
|
||||
RUNTIME_ARRAY(bool, objectMask, size);
|
||||
|
||||
assert(t, (methodFlags(t, method) & ACC_STATIC) == 0);
|
||||
|
||||
unsigned i = 0;
|
||||
RUNTIME_ARRAY_BODY(objectMask)[i++] = true;
|
||||
|
||||
unsigned argumentCount = 0;
|
||||
for (MethodSpecIterator it
|
||||
(t, reinterpret_cast<char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0)));
|
||||
it.hasNext();)
|
||||
{
|
||||
++ argumentCount;
|
||||
|
||||
switch (*it.next()) {
|
||||
case 'L':
|
||||
case '[':
|
||||
RUNTIME_ARRAY_BODY(objectMask)[i++] = true;
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
|
||||
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
RUNTIME_ARRAY_BODY(objectMask)[i++] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class MyProtector: public Thread::Protector {
|
||||
public:
|
||||
MyProtector(Thread* t, uintptr_t* array, bool* mask, unsigned count):
|
||||
Protector(t), array(array), mask(mask), count(count) { }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
if (mask[i]) {
|
||||
v->visit(reinterpret_cast<object*>(array + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t* array;
|
||||
bool* mask;
|
||||
unsigned count;
|
||||
} protector(t, arguments, RUNTIME_ARRAY_BODY(objectMask), i);
|
||||
|
||||
object array = makeObjectArray
|
||||
(t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType),
|
||||
argumentCount);
|
||||
PROTECT(t, array);
|
||||
|
||||
i = 0;
|
||||
unsigned ai = 1;
|
||||
for (MethodSpecIterator it
|
||||
(t, reinterpret_cast<char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0)));
|
||||
it.hasNext();)
|
||||
{
|
||||
object a;
|
||||
unsigned size;
|
||||
switch (*it.next()) {
|
||||
case 'L':
|
||||
case '[':
|
||||
a = reinterpret_cast<object>(arguments[ai]);
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
a = makeBoolean(t, static_cast<int8_t>(arguments[ai]));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
a = makeByte(t, static_cast<int8_t>(arguments[ai]));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
a = makeShort(t, static_cast<int16_t>(arguments[ai]));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
a = makeChar(t, static_cast<uint16_t>(arguments[ai]));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
a = makeInt(t, static_cast<int32_t>(arguments[ai]));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
a = makeFloat(t, bitsToFloat(static_cast<int32_t>(arguments[ai])));
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case 'J': {
|
||||
int64_t v; memcpy(&v, arguments + ai, 8);
|
||||
a = makeLong(t, v);
|
||||
size = 2;
|
||||
} break;
|
||||
|
||||
case 'D': {
|
||||
double v; memcpy(&v, arguments + ai, 8);
|
||||
a = makeDouble(t, v);
|
||||
size = 2;
|
||||
} break;
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
|
||||
set(t, array, ArrayBody + (i * BytesPerWord), a);
|
||||
|
||||
++ i;
|
||||
ai += size;
|
||||
}
|
||||
|
||||
if (t->m->invokeMethod == 0) {
|
||||
object m = resolveMethod
|
||||
(t, t->m->loader, "java/lang/reflect/InvocationHandler", "invoke",
|
||||
"(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)"
|
||||
"Ljava/lang/Object;");
|
||||
|
||||
if (m) {
|
||||
t->m->invokeMethod = m;
|
||||
}
|
||||
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
}
|
||||
|
||||
object invoke = findInterfaceMethod
|
||||
(t, t->m->invokeMethod, objectClass
|
||||
(t, proxyH(t, reinterpret_cast<object>(arguments[0]))));
|
||||
PROTECT(t, invoke);
|
||||
|
||||
object result = t->m->processor->invoke
|
||||
(t, invoke, proxyH(t, reinterpret_cast<object>(arguments[0])),
|
||||
reinterpret_cast<object>(arguments[0]), method, array);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
switch (methodReturnCode(t, method)) {
|
||||
case BooleanField:
|
||||
return booleanValue(t, result);
|
||||
|
||||
case ByteField:
|
||||
return byteValue(t, result);
|
||||
|
||||
case CharField:
|
||||
return charValue(t, result);
|
||||
|
||||
case ShortField:
|
||||
return shortValue(t, result);
|
||||
|
||||
case FloatField:
|
||||
return floatToBits(floatValue(t, result));
|
||||
|
||||
case IntField:
|
||||
return intValue(t, result);
|
||||
|
||||
case LongField:
|
||||
return longValue(t, result);
|
||||
|
||||
case DoubleField:
|
||||
return doubleToBits(doubleValue(t, result));
|
||||
|
||||
case ObjectField:
|
||||
return reinterpret_cast<int64_t>(result);
|
||||
|
||||
case VoidField:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
addInterface(Thread* t, object map, object interface)
|
||||
{
|
||||
hashMapInsertMaybe
|
||||
(t, map, className(t, interface), interface, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
}
|
||||
|
||||
object
|
||||
allInterfaces(Thread* t, object array)
|
||||
{
|
||||
PROTECT(t, array);
|
||||
|
||||
object map = makeHashMap(t, 0, 0);
|
||||
PROTECT(t, map);
|
||||
|
||||
for (unsigned i = 0; i < objectArrayLength(t, array); ++i) {
|
||||
addInterface(t, map, objectArrayBody(t, array, i));
|
||||
|
||||
object itable = classInterfaceTable(t, objectArrayBody(t, array, i));
|
||||
if (itable) {
|
||||
PROTECT(t, itable);
|
||||
|
||||
for (unsigned j = 0; j < arrayLength(t, itable); ++j) {
|
||||
addInterface(t, map, arrayBody(t, itable, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object result = makeArray(t, hashMapSize(t, map));
|
||||
|
||||
unsigned i = 0;
|
||||
for (HashMapIterator it(t, map); it.hasMore();) {
|
||||
set(t, result, ArrayBody + (i * BytesPerWord), tripleSecond(t, it.next()));
|
||||
++ i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
@ -199,16 +435,6 @@ Avian_java_lang_ClassLoader_defineClass
|
||||
return reinterpret_cast<int64_t>(c);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_ClassLoader_resolveClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
object class_ = reinterpret_cast<object>(arguments[1]);
|
||||
|
||||
linkClass(t, loader, class_);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_avian_SystemClassLoader_findLoadedClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
@ -302,13 +528,17 @@ Avian_java_lang_Class_initialize
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Class_link
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
Avian_java_lang_Class_acquireClassLock
|
||||
(Thread* t, object)
|
||||
{
|
||||
object this_ = reinterpret_cast<object>(arguments[0]);
|
||||
object loader = reinterpret_cast<object>(arguments[1]);
|
||||
acquire(t, t->m->classLock);
|
||||
}
|
||||
|
||||
linkClass(t, loader, this_);
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Avian_java_lang_Class_releaseClassLock
|
||||
(Thread* t, object)
|
||||
{
|
||||
release(t, t->m->classLock);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
@ -499,6 +729,195 @@ Avian_java_lang_reflect_Array_makeObjectArray
|
||||
(makeObjectArray(t, classLoader(t, elementType), elementType, length));
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_reflect_Proxy_makeClass
|
||||
(Thread* t, object, uintptr_t* arguments)
|
||||
{
|
||||
object loader = reinterpret_cast<object>(arguments[0]);
|
||||
PROTECT(t, loader);
|
||||
|
||||
object interfaces = allInterfaces(t, reinterpret_cast<object>(arguments[1]));
|
||||
PROTECT(t, interfaces);
|
||||
|
||||
object name = reinterpret_cast<object>(arguments[2]);
|
||||
PROTECT(t, name);
|
||||
|
||||
object virtualMap = makeHashMap(t, 0, 0);
|
||||
PROTECT(t, virtualMap);
|
||||
|
||||
object superVtable = classVirtualTable
|
||||
(t, arrayBody(t, t->m->types, Machine::ProxyType));
|
||||
PROTECT(t, superVtable);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, superVtable); ++i) {
|
||||
object method = arrayBody(t, superVtable, i);
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
}
|
||||
|
||||
unsigned virtualCount = arrayLength(t, superVtable);
|
||||
|
||||
object newVirtuals = makeList(t, 0, 0, 0);
|
||||
PROTECT(t, newVirtuals);
|
||||
|
||||
object ivtable = 0;
|
||||
PROTECT(t, ivtable);
|
||||
|
||||
object method = 0;
|
||||
PROTECT(t, method);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
|
||||
ivtable = classVirtualTable(t, arrayBody(t, interfaces, i));
|
||||
|
||||
if (ivtable) {
|
||||
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
||||
method = arrayBody(t, ivtable, j);
|
||||
|
||||
method = makeMethod
|
||||
(t,
|
||||
methodVmFlags(t, method) | FastNative,
|
||||
methodReturnCode(t, method),
|
||||
methodParameterCount(t, method),
|
||||
methodParameterFootprint(t, method),
|
||||
methodFlags(t, method) | ACC_NATIVE,
|
||||
0,
|
||||
0,
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
reinterpret_cast<int64_t>(proxyInvoke));
|
||||
|
||||
object p = hashMapFindNode
|
||||
(t, virtualMap, method, methodHash, methodEqual);
|
||||
|
||||
if (p) {
|
||||
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
|
||||
|
||||
set(t, p, TripleSecond, method);
|
||||
} else {
|
||||
methodOffset(t, method) = virtualCount++;
|
||||
|
||||
listAppend(t, newVirtuals, method);
|
||||
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object vtable = makeArray(t, virtualCount);
|
||||
PROTECT(t, vtable);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < arrayLength(t, superVtable); ++i) {
|
||||
method = hashMapFind
|
||||
(t, virtualMap, arrayBody(t, superVtable, i), methodHash, methodEqual);
|
||||
|
||||
set(t, vtable, ArrayBody + (i * BytesPerWord), method);
|
||||
}
|
||||
|
||||
object methodTable = makeArray(t, listSize(t, newVirtuals) + 1);
|
||||
PROTECT(t, methodTable);
|
||||
|
||||
unsigned mti = 0;
|
||||
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
||||
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
|
||||
++ i;
|
||||
|
||||
set(t, methodTable, ArrayBody + (mti * BytesPerWord), pairFirst(t, p));
|
||||
++ mti;
|
||||
}
|
||||
|
||||
#define NAME "<init>"
|
||||
object constructorName = makeByteArray(t, sizeof(NAME));
|
||||
PROTECT(t, constructorName);
|
||||
memcpy(&byteArrayBody(t, constructorName, 0), NAME, sizeof(NAME));
|
||||
|
||||
#define SPEC "(Ljava/lang/reflect/InvocationHandler;)V"
|
||||
object constructorSpec = makeByteArray(t, sizeof(SPEC));
|
||||
PROTECT(t, constructorSpec);
|
||||
memcpy(&byteArrayBody(t, constructorSpec, 0), SPEC, sizeof(SPEC));
|
||||
|
||||
object constructor = makeMethod
|
||||
(t,
|
||||
methodVmFlags(t, method) | FastNative,
|
||||
VoidField,
|
||||
1,
|
||||
2,
|
||||
methodFlags(t, method) | ACC_NATIVE,
|
||||
0,
|
||||
0,
|
||||
constructorName,
|
||||
constructorSpec,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
reinterpret_cast<int64_t>(proxyConstruct));
|
||||
|
||||
set(t, methodTable, ArrayBody + (mti * BytesPerWord), constructor);
|
||||
++ mti;
|
||||
|
||||
assert(t, arrayLength(t, vtable) == i);
|
||||
assert(t, arrayLength(t, methodTable) == mti);
|
||||
|
||||
object itable = makeArray(t, arrayLength(t, interfaces) * 2);
|
||||
PROTECT(t, itable);
|
||||
|
||||
object newIVTable = 0;
|
||||
PROTECT(t, newIVTable);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, interfaces); ++i) {
|
||||
object interface = arrayBody(t, interfaces, i);
|
||||
|
||||
set(t, itable, ArrayBody + ((i * 2) * BytesPerWord), interface);
|
||||
|
||||
ivtable = classVirtualTable(t, interface);
|
||||
if (ivtable) {
|
||||
newIVTable = makeArray(t, arrayLength(t, ivtable));
|
||||
|
||||
set(t, itable, ArrayBody + (((i * 2) + 1) * BytesPerWord), newIVTable);
|
||||
|
||||
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
||||
method = hashMapFind
|
||||
(t, virtualMap, arrayBody(t, ivtable, j), methodHash, methodEqual);
|
||||
assert(t, method);
|
||||
|
||||
set(t, newIVTable, ArrayBody + (j * BytesPerWord), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object c = t->m->processor->makeClass
|
||||
(t,
|
||||
0,
|
||||
0,
|
||||
classFixedSize(t, arrayBody(t, t->m->types, Machine::ProxyType)),
|
||||
0,
|
||||
0,
|
||||
classObjectMask(t, arrayBody(t, t->m->types, Machine::ProxyType)),
|
||||
name,
|
||||
0,
|
||||
arrayBody(t, t->m->types, Machine::ProxyType),
|
||||
itable,
|
||||
vtable,
|
||||
0,
|
||||
methodTable,
|
||||
0,
|
||||
0,
|
||||
loader,
|
||||
arrayLength(t, vtable));
|
||||
PROTECT(t, c);
|
||||
|
||||
t->m->processor->initVtable(t, c);
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
||||
set(t, arrayBody(t, methodTable, i), MethodClass, c);
|
||||
}
|
||||
|
||||
return reinterpret_cast<int64_t>(c);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT int64_t JNICALL
|
||||
Avian_java_lang_Float_floatToRawIntBits
|
||||
(Thread*, object, uintptr_t* arguments)
|
||||
|
@ -6331,7 +6331,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
};
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -6450,12 +6450,13 @@ class MyProcessor: public Processor {
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object addendum,
|
||||
object class_,
|
||||
object code)
|
||||
{
|
||||
return vm::makeMethod
|
||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||
offset, 0, name, spec, class_, code,
|
||||
offset, 0, name, spec, addendum, class_, code,
|
||||
local::defaultThunk(static_cast<MyThread*>(t)));
|
||||
}
|
||||
|
||||
@ -6475,13 +6476,14 @@ class MyProcessor: public Processor {
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object addendum,
|
||||
object loader,
|
||||
unsigned vtableLength)
|
||||
{
|
||||
return vm::makeClass
|
||||
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
|
||||
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
|
||||
fieldTable, methodTable, staticTable, loader, vtableLength);
|
||||
fieldTable, methodTable, staticTable, addendum, loader, vtableLength);
|
||||
}
|
||||
|
||||
virtual void
|
||||
@ -7656,6 +7658,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext,
|
||||
methodNativeID(t, method),
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
methodAddendum(t, method),
|
||||
methodClass(t, method),
|
||||
methodCode(t, method),
|
||||
reinterpret_cast<intptr_t>(compiled));
|
||||
|
@ -3093,11 +3093,12 @@ class MyProcessor: public Processor {
|
||||
object name,
|
||||
object spec,
|
||||
object class_,
|
||||
object addendum,
|
||||
object code)
|
||||
{
|
||||
return vm::makeMethod
|
||||
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
|
||||
offset, 0, name, spec, class_, code, 0);
|
||||
offset, 0, name, spec, addendum, class_, code, 0);
|
||||
}
|
||||
|
||||
virtual object
|
||||
@ -3116,13 +3117,14 @@ class MyProcessor: public Processor {
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object staticTable,
|
||||
object addendum,
|
||||
object loader,
|
||||
unsigned vtableLength UNUSED)
|
||||
{
|
||||
return vm::makeClass
|
||||
(t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions,
|
||||
objectMask, name, sourceFile, super, interfaceTable, virtualTable,
|
||||
fieldTable, methodTable, staticTable, loader, 0);
|
||||
fieldTable, methodTable, addendum, staticTable, loader, 0);
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
274
src/machine.cpp
274
src/machine.cpp
@ -68,9 +68,8 @@ dispose(Thread* t, Thread* o, bool remove)
|
||||
expect(t, find(t->m->rootThread, o));
|
||||
|
||||
unsigned c = count(t->m->rootThread, o);
|
||||
Thread** threads = static_cast<Thread**>
|
||||
(allocate(t->m->system, c * sizeof(Thread*)));
|
||||
fill(t->m->rootThread, o, threads);
|
||||
RUNTIME_ARRAY(Thread*, threads, c);
|
||||
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
|
||||
#endif
|
||||
|
||||
if (o->parent) {
|
||||
@ -115,7 +114,7 @@ dispose(Thread* t, Thread* o, bool remove)
|
||||
expect(t, not find(t->m->rootThread, o));
|
||||
|
||||
for (unsigned i = 0; i < c; ++i) {
|
||||
expect(t, find(t->m->rootThread, threads[i]));
|
||||
expect(t, find(t->m->rootThread, RUNTIME_ARRAY_BODY(threads)[i]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -604,51 +603,6 @@ makeByteArray(Thread* t, const char* format, va_list a)
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned
|
||||
resolveSpec(Thread* t, object loader, object spec, unsigned offset)
|
||||
{
|
||||
int8_t* s = &byteArrayBody(t, spec, offset);
|
||||
unsigned result;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
++ offset;
|
||||
while (*s and *s != ';') ++ s;
|
||||
result = s + 1 - &byteArrayBody(t, spec, 0);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
result = s - &byteArrayBody(t, spec, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
PROTECT(t, spec);
|
||||
PROTECT(t, loader);
|
||||
|
||||
unsigned length = s - &byteArrayBody(t, spec, offset);
|
||||
|
||||
object name = makeByteArray(t, length + 1);
|
||||
memcpy(&byteArrayBody(t, name, 0),
|
||||
&byteArrayBody(t, spec, offset),
|
||||
length);
|
||||
resolveClass(t, loader, name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned
|
||||
readByte(Stream& s, unsigned* value)
|
||||
{
|
||||
@ -983,7 +937,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
object interfaceTable = 0;
|
||||
if (hashMapSize(t, map)) {
|
||||
unsigned length = hashMapSize(t, map) ;
|
||||
unsigned length = hashMapSize(t, map);
|
||||
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
||||
length *= 2;
|
||||
}
|
||||
@ -1016,6 +970,122 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
set(t, class_, ClassInterfaceTable, interfaceTable);
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotation(Thread* t, Stream& s, object pool);
|
||||
|
||||
object
|
||||
parseAnnotationValue(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
unsigned tag = s.read1();
|
||||
switch (tag) {
|
||||
case 'Z':
|
||||
return makeBoolean(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'B':
|
||||
return makeByte(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'C':
|
||||
return makeChar(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'S':
|
||||
return makeShort(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'I':
|
||||
return makeInt(t, singletonValue(t, pool, s.read2() - 1));
|
||||
|
||||
case 'F':
|
||||
return makeFloat(t, bitsToFloat(singletonValue(t, pool, s.read2() - 1)));
|
||||
|
||||
case 'J': {
|
||||
int64_t v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
|
||||
return makeLong(t, v);
|
||||
}
|
||||
|
||||
case 'D': {
|
||||
double v; memcpy(&v, &singletonValue(t, pool, s.read2() - 1), 8);
|
||||
return makeDouble(t, v);
|
||||
}
|
||||
|
||||
case 's': {
|
||||
object value = singletonObject(t, pool, s.read2() - 1);
|
||||
return intern
|
||||
(t, makeString(t, value, 0, byteArrayLength(t, value) - 1, 0));
|
||||
}
|
||||
|
||||
case 'e': {
|
||||
unsigned typeNameIndex = s.read2() - 1;
|
||||
unsigned nameIndex = s.read2() - 1;
|
||||
return makePair(t, singletonObject(t, pool, typeNameIndex),
|
||||
singletonObject(t, pool, nameIndex));
|
||||
}
|
||||
|
||||
case 'c':
|
||||
return singletonObject(t, pool, s.read2() - 1);
|
||||
|
||||
case '@':
|
||||
return parseAnnotation(t, s, pool);
|
||||
|
||||
case '[': {
|
||||
unsigned count = s.read2();
|
||||
object array = makeObjectArray(t, count);
|
||||
PROTECT(t, array);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
object value = parseAnnotationValue(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, array, ArrayBody + (i * BytesPerWord), value);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotation(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
unsigned typeIndex = s.read2() - 1;
|
||||
unsigned elementCount = s.read2();
|
||||
object array = makeObjectArray(t, (elementCount * 2) + 2);
|
||||
PROTECT(t, array);
|
||||
|
||||
set(t, array, ArrayBody + BytesPerWord, singletonObject(t, pool, typeIndex));
|
||||
|
||||
for (unsigned i = 0; i < elementCount; ++i) {
|
||||
set(t, array, ArrayBody + (((i * 2) + 2) * BytesPerWord),
|
||||
singletonObject(t, pool, s.read2() - 1));
|
||||
|
||||
object value = parseAnnotationValue(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, array, ArrayBody + (((i * 2) + 3) * BytesPerWord), value);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
object
|
||||
parseAnnotationTable(Thread* t, Stream& s, object pool)
|
||||
{
|
||||
PROTECT(t, pool);
|
||||
|
||||
unsigned annotationCount = s.read2();
|
||||
object annotations = makeArray(t, annotationCount);
|
||||
PROTECT(t, annotations);
|
||||
|
||||
for (unsigned i = 0; i < annotationCount; ++i) {
|
||||
object annotation = parseAnnotation(t, s, pool);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
set(t, annotations, ArrayBody + (i * BytesPerWord), annotation);
|
||||
}
|
||||
|
||||
return annotations;
|
||||
}
|
||||
|
||||
void
|
||||
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
{
|
||||
@ -1038,6 +1108,9 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object staticValueTable = makeIntArray(t, count);
|
||||
PROTECT(t, staticValueTable);
|
||||
|
||||
object addendum = 0;
|
||||
PROTECT(t, addendum);
|
||||
|
||||
RUNTIME_ARRAY(uint8_t, staticTypes, count);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
@ -1059,6 +1132,11 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
value = s.read2();
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
addendum = makeFieldAddendum(t, parseAnnotationTable(t, s, pool));
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1072,6 +1150,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
||||
0, // offset
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
addendum,
|
||||
class_);
|
||||
|
||||
if (flags & ACC_STATIC) {
|
||||
@ -1318,6 +1397,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap,
|
||||
0,
|
||||
methodName(t, method),
|
||||
methodSpec(t, method),
|
||||
0,
|
||||
class_,
|
||||
0,
|
||||
0);
|
||||
@ -1380,12 +1460,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object methodTable = makeArray(t, count);
|
||||
PROTECT(t, methodTable);
|
||||
|
||||
object addendum = 0;
|
||||
PROTECT(t, addendum);
|
||||
|
||||
object code = 0;
|
||||
PROTECT(t, code);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
unsigned flags = s.read2();
|
||||
unsigned name = s.read2();
|
||||
unsigned spec = s.read2();
|
||||
|
||||
object code = 0;
|
||||
code = 0;
|
||||
|
||||
unsigned attributeCount = s.read2();
|
||||
for (unsigned j = 0; j < attributeCount; ++j) {
|
||||
object name = singletonObject(t, pool, s.read2() - 1);
|
||||
@ -1395,6 +1482,11 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
code = parseCode(t, s, pool);
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
addendum = makeMethodAddendum(t, parseAnnotationTable(t, s, pool));
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1417,6 +1509,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
0, // offset
|
||||
singletonObject(t, pool, name - 1),
|
||||
singletonObject(t, pool, spec - 1),
|
||||
addendum,
|
||||
class_,
|
||||
code);
|
||||
|
||||
@ -1493,7 +1586,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
|
||||
if (classInterfaceTable(t, classSuper(t, class_))
|
||||
and arrayLength(t, classInterfaceTable(t, class_))
|
||||
== arrayLength(t, classInterfaceTable(t, classSuper(t, class_))))
|
||||
== arrayLength
|
||||
(t, classInterfaceTable(t, classSuper(t, class_))))
|
||||
{
|
||||
// inherit interface table from superclass
|
||||
set(t, class_, ClassInterfaceTable,
|
||||
@ -1541,6 +1635,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
}
|
||||
|
||||
if (abstractVirtuals) {
|
||||
PROTECT(t, vtable);
|
||||
PROTECT(t, abstractVirtuals);
|
||||
|
||||
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
||||
@ -1592,7 +1687,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
(t, virtualMap, method, methodHash, methodEqual);
|
||||
assert(t, method);
|
||||
|
||||
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
||||
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1612,6 +1707,14 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1));
|
||||
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
||||
("RuntimeVisibleAnnotations"),
|
||||
&byteArrayBody(t, name, 0)) == 0)
|
||||
{
|
||||
object addendum = makeClassAddendum
|
||||
(t, parseAnnotationTable(t, s, pool), 0);
|
||||
|
||||
set(t, class_, ClassAddendum, addendum);
|
||||
} else {
|
||||
s.skip(length);
|
||||
}
|
||||
@ -1702,6 +1805,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
|
||||
vtable,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
elementClass,
|
||||
loader,
|
||||
arrayLength(t, vtable));
|
||||
@ -1832,7 +1936,7 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
||||
|
||||
object class_ = t->m->processor->makeClass
|
||||
(t, 0, BootstrapFlag, fixedSize, arrayElementSize, 0, mask, 0, 0, super, 0,
|
||||
0, 0, 0, 0, t->m->loader, vtableLength);
|
||||
0, 0, 0, 0, 0, t->m->loader, vtableLength);
|
||||
|
||||
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
|
||||
}
|
||||
@ -1945,7 +2049,7 @@ boot(Thread* t)
|
||||
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1);
|
||||
codeBody(t, bootCode, 0) = impdep1;
|
||||
object bootMethod = makeMethod
|
||||
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
|
||||
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
|
||||
PROTECT(t, bootMethod);
|
||||
|
||||
#include "type-java-initializations.cpp"
|
||||
@ -2084,6 +2188,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||
tenuredWeakReferences(0),
|
||||
shutdownHooks(0),
|
||||
objectsToFinalize(0),
|
||||
invokeMethod(0),
|
||||
unsafe(false),
|
||||
triedBuiltinOnLoad(false),
|
||||
heapPoolIndex(0)
|
||||
@ -2824,12 +2929,13 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
||||
0, // object mask
|
||||
referenceName
|
||||
(t, singletonObject(t, pool, name - 1)),
|
||||
0,
|
||||
0, // source file
|
||||
0, // super
|
||||
0, // interfaces
|
||||
0, // vtable
|
||||
0, // fields
|
||||
0, // methods
|
||||
0, // addendum
|
||||
0, // static table
|
||||
loader,
|
||||
0);// vtable length
|
||||
@ -2878,6 +2984,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
|
||||
classVirtualTable(t, class_),
|
||||
classFieldTable(t, class_),
|
||||
classMethodTable(t, class_),
|
||||
classAddendum(t, class_),
|
||||
classStaticTable(t, class_),
|
||||
classLoader(t, class_),
|
||||
vtableLength);
|
||||
@ -3032,60 +3139,6 @@ resolveClass(Thread* t, object loader, object spec)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
linkClass(Thread* t, object loader, object class_)
|
||||
{
|
||||
PROTECT(t, loader);
|
||||
PROTECT(t, class_);
|
||||
|
||||
ACQUIRE(t, t->m->classLock);
|
||||
|
||||
if ((classVmFlags(t, class_) & LinkFlag) == 0) {
|
||||
if (classSuper(t, class_)) {
|
||||
linkClass(t, loader, classSuper(t, class_));
|
||||
}
|
||||
|
||||
if (classInterfaceTable(t, class_)) {
|
||||
unsigned increment = 2;
|
||||
if (classFlags(t, class_) & ACC_INTERFACE) {
|
||||
increment = 1;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < arrayLength(t, classInterfaceTable(t, class_));
|
||||
i += increment)
|
||||
{
|
||||
linkClass(t, loader, arrayBody(t, classInterfaceTable(t, class_), i));
|
||||
}
|
||||
}
|
||||
|
||||
if (classMethodTable(t, class_)) {
|
||||
for (unsigned i = 0;
|
||||
i < arrayLength(t, classMethodTable(t, class_)); ++i)
|
||||
{
|
||||
object spec = methodSpec
|
||||
(t, arrayBody(t, classMethodTable(t, class_), i));
|
||||
PROTECT(t, spec);
|
||||
|
||||
for (unsigned j = 1; j < byteArrayLength(t, spec);) {
|
||||
j = resolveSpec(t, loader, spec, j);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classFieldTable(t, class_)) {
|
||||
for (unsigned i = 0; i < arrayLength(t, classFieldTable(t, class_)); ++i)
|
||||
{
|
||||
resolveSpec(t, loader, fieldSpec
|
||||
(t, arrayBody(t, classFieldTable(t, class_), i)), 0);
|
||||
if (UNLIKELY(t->exception)) return;
|
||||
}
|
||||
}
|
||||
|
||||
classVmFlags(t, class_) |= LinkFlag;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
resolveMethod(Thread* t, object class_, const char* methodName,
|
||||
const char* methodSpec)
|
||||
@ -3573,6 +3626,7 @@ visitRoots(Machine* m, Heap::Visitor* v)
|
||||
v->visit(&(m->jniMethodTable));
|
||||
v->visit(&(m->shutdownHooks));
|
||||
v->visit(&(m->objectsToFinalize));
|
||||
v->visit(&(m->invokeMethod));
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
|
@ -1204,6 +1204,7 @@ class Machine {
|
||||
object tenuredWeakReferences;
|
||||
object shutdownHooks;
|
||||
object objectsToFinalize;
|
||||
object invokeMethod;
|
||||
bool unsafe;
|
||||
bool triedBuiltinOnLoad;
|
||||
JavaVMVTable javaVMVTable;
|
||||
@ -1846,6 +1847,12 @@ makeExceptionInInitializerError(Thread* t, object cause)
|
||||
return makeExceptionInInitializerError(t, 0, trace, cause, cause);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIncompatibleClassChangeError(Thread* t)
|
||||
{
|
||||
return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeNew(Thread* t, object class_)
|
||||
{
|
||||
@ -2194,6 +2201,13 @@ initClass(Thread* t, object c);
|
||||
object
|
||||
makeObjectArray(Thread* t, object loader, object elementClass, unsigned count);
|
||||
|
||||
inline object
|
||||
makeObjectArray(Thread* t, unsigned count)
|
||||
{
|
||||
return makeObjectArray
|
||||
(t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType), count);
|
||||
}
|
||||
|
||||
object
|
||||
findInTable(Thread* t, object table, object name, object spec,
|
||||
object& (*getName)(Thread*, object),
|
||||
@ -2232,6 +2246,22 @@ findVirtualMethod(Thread* t, object method, object class_)
|
||||
methodOffset(t, method));
|
||||
}
|
||||
|
||||
inline object
|
||||
findInterfaceMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
|
||||
|
||||
object interface = methodClass(t, method);
|
||||
object itable = classInterfaceTable(t, class_);
|
||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||
if (arrayBody(t, itable, i) == interface) {
|
||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
}
|
||||
abort(t);
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
objectArrayLength(Thread* t UNUSED, object array)
|
||||
{
|
||||
@ -2248,7 +2278,7 @@ objectArrayBody(Thread* t UNUSED, object array, unsigned index)
|
||||
assert(t, classObjectMask(t, objectClass(t, array))
|
||||
== classObjectMask(t, arrayBody
|
||||
(t, t->m->types, Machine::ArrayType)));
|
||||
return cast<object>(array, (2 + index) * BytesPerWord);
|
||||
return cast<object>(array, ArrayBody + (index * BytesPerWord));
|
||||
}
|
||||
|
||||
unsigned
|
||||
|
@ -59,22 +59,6 @@ isSpecialMethod(Thread* t, object method, object class_)
|
||||
void*
|
||||
resolveNativeMethod(Thread* t, object method);
|
||||
|
||||
inline object
|
||||
findInterfaceMethod(Thread* t, object method, object class_)
|
||||
{
|
||||
assert(t, (classVmFlags(t, class_) & BootstrapFlag) == 0);
|
||||
|
||||
object interface = methodClass(t, method);
|
||||
object itable = classInterfaceTable(t, class_);
|
||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||
if (arrayBody(t, itable, i) == interface) {
|
||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
||||
methodOffset(t, method));
|
||||
}
|
||||
}
|
||||
abort(t);
|
||||
}
|
||||
|
||||
inline void
|
||||
populateMultiArray(Thread* t, object array, int32_t* counts,
|
||||
unsigned index, unsigned dimensions)
|
||||
|
@ -54,6 +54,7 @@ class Processor {
|
||||
uint16_t offset,
|
||||
object name,
|
||||
object spec,
|
||||
object addendum,
|
||||
object class_,
|
||||
object code) = 0;
|
||||
|
||||
@ -72,6 +73,7 @@ class Processor {
|
||||
object virtualTable,
|
||||
object fieldTable,
|
||||
object methodTable,
|
||||
object addendum,
|
||||
object staticTable,
|
||||
object loader,
|
||||
unsigned vtableLength) = 0;
|
||||
|
@ -13,10 +13,20 @@
|
||||
|
||||
(type accessibleObject java/lang/reflect/AccessibleObject)
|
||||
|
||||
(type classAddendum java/lang/Class$Addendum)
|
||||
|
||||
(type field java/lang/reflect/Field)
|
||||
|
||||
(type fieldAddendum java/lang/reflect/Field$Addendum)
|
||||
|
||||
(type method java/lang/reflect/Method)
|
||||
|
||||
(type methodAddendum java/lang/reflect/Method$Addendum)
|
||||
|
||||
(type proxy java/lang/reflect/Proxy)
|
||||
|
||||
(type pair avian/Pair)
|
||||
|
||||
(type nativeMethodData
|
||||
(void* function)
|
||||
(uint16_t argumentTableSize)
|
||||
@ -54,10 +64,6 @@
|
||||
(object name)
|
||||
(object spec))
|
||||
|
||||
(type pair
|
||||
(object first)
|
||||
(object second))
|
||||
|
||||
(type triple
|
||||
(object first)
|
||||
(object second)
|
||||
|
Reference in New Issue
Block a user