various fixes and additions to increase app compatiblity

The main changes here are:

  * fixes for runtime annotation support

  * proper support for runtime generic type introspection

  * throw NoClassDefFoundErrors instead of ClassNotFoundExceptions
    where appropriate
This commit is contained in:
Joel Dice 2011-03-17 21:42:15 -06:00
parent 8a28578ef5
commit 7004c0ddf3
7 changed files with 204 additions and 69 deletions

View File

@ -12,5 +12,6 @@ package avian;
public class Addendum {
public Object pool;
public Object annotationTable;
public Object annotationTable;
public Object signature;
}

View File

@ -12,4 +12,5 @@ package avian;
public class MethodAddendum extends Addendum {
public Object exceptionTable;
public Object annotationDefault;
}

View File

@ -42,7 +42,8 @@ search(Thread* t, object loader, object name,
object
resolveSystemClassThrow(Thread* t, object loader, object spec)
{
return resolveSystemClass(t, loader, spec, true);
return resolveSystemClass
(t, loader, spec, true, Machine::ClassNotFoundExceptionType);
}
} // namespace

View File

@ -610,7 +610,8 @@ Avian_avian_Classes_resolveVMClass
object loader = reinterpret_cast<object>(arguments[0]);
object spec = reinterpret_cast<object>(arguments[1]);
return reinterpret_cast<int64_t>(resolveClass(t, loader, spec));
return reinterpret_cast<int64_t>
(resolveClass(t, loader, spec, true, Machine::ClassNotFoundExceptionType));
}
extern "C" JNIEXPORT int64_t JNICALL

View File

@ -277,7 +277,10 @@ class MyClasspath : public Classpath {
}
array = charArray;
} else {
expect(t, objectClass(t, array) == type(t, Machine::CharArrayType));
}
return vm::makeString(t, array, offset, length, 0);
}
@ -2118,6 +2121,16 @@ Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J
return cast<int32_t>(o, offset);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getFloat__Ljava_lang_Object_2J
(Thread*, object, uintptr_t* arguments)
{
object o = reinterpret_cast<object>(arguments[1]);
int64_t offset; memcpy(&offset, arguments + 2, 8);
return cast<int32_t>(o, offset);
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getIntVolatile
(Thread*, object, uintptr_t* arguments)
@ -2177,6 +2190,17 @@ Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI
cast<int32_t>(o, offset) = value;
}
extern "C" JNIEXPORT void JNICALL
Avian_sun_misc_Unsafe_putFloat__Ljava_lang_Object_2JF
(Thread*, object, uintptr_t* arguments)
{
object o = reinterpret_cast<object>(arguments[1]);
int64_t offset; memcpy(&offset, arguments + 2, 8);
int32_t value = arguments[4];
cast<int32_t>(o, offset) = value;
}
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getBoolean
(Thread*, object, uintptr_t* arguments)
@ -3248,21 +3272,10 @@ jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments)
jobject loader = reinterpret_cast<jobject>(arguments[2]);
jboolean throwError = arguments[3];
THREAD_RESOURCE(t, jboolean, throwError, {
if (t->exception and throwError) {
object exception = t->exception;
t->exception = 0;
t->exception = makeThrowable
(t, Machine::NoClassDefFoundErrorType,
throwableMessage(t, exception),
throwableTrace(t, exception),
throwableCause(t, exception));
}
});
object c = resolveClass
(t, loader ? *loader : root(t, Machine::BootLoader), name);
(t, loader ? *loader : root(t, Machine::BootLoader), name, true,
throwError ? Machine::NoClassDefFoundErrorType
: Machine::ClassNotFoundExceptionType);
if (init) {
PROTECT(t, c);
@ -3542,9 +3555,19 @@ EXPORT(JVM_GetDeclaringClass)(Thread*, jclass)
}
extern "C" JNIEXPORT jstring JNICALL
EXPORT(JVM_GetClassSignature)(Thread*, jclass)
EXPORT(JVM_GetClassSignature)(Thread* t, jclass c)
{
// todo: implement properly
ENTER(t, Thread::ActiveState);
object addendum = classAddendum(t, jclassVmClass(t, *c));
if (addendum) {
object signature = addendumSignature(t, addendum);
if (signature) {
return makeLocalReference
(t, t->m->classpath->makeString
(t, signature, 0, byteArrayLength(t, signature) - 1));
}
}
return 0;
}
@ -3605,16 +3628,30 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments)
methodAddendum(t, vmMethod));
PROTECT(t, exceptionTypes);
object signature = t->m->classpath->makeString
(t, methodSpec(t, vmMethod), 0, byteArrayLength
(t, methodSpec(t, vmMethod)) - 1);
object signature;
object annotationTable;
object annotationDefault;
object addendum = methodAddendum(t, vmMethod);
if (addendum) {
signature = addendumSignature(t, addendum);
if (signature) {
signature = t->m->classpath->makeString
(t, signature, 0, byteArrayLength(t, signature) - 1);
}
object annotationTable = methodAddendum(t, vmMethod) == 0
? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod));
annotationTable = addendumAnnotationTable(t, addendum);
if (annotationTable) {
annotationDefault = methodAddendumAnnotationDefault(t, addendum);
} else {
signature = 0;
annotationTable = 0;
annotationDefault = 0;
}
if (annotationTable or annotationDefault) {
PROTECT(t, signature);
PROTECT(t, annotationTable);
PROTECT(t, annotationDefault);
object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c));
@ -3624,8 +3661,8 @@ jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments)
object method = makeJmethod
(t, true, *c, i, name, returnType, parameterTypes, exceptionTypes,
methodFlags(t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0,
0, 0, 0);
methodFlags(t, vmMethod), signature, 0, annotationTable, 0,
annotationDefault, 0, 0, 0, 0, 0);
assert(t, ai < objectArrayLength(t, array));
@ -3685,12 +3722,21 @@ jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments)
type = getJClass(t, type);
object signature = t->m->classpath->makeString
(t, fieldSpec(t, vmField), 0, byteArrayLength
(t, fieldSpec(t, vmField)) - 1);
object signature;
object annotationTable;
object addendum = fieldAddendum(t, vmField);
if (addendum) {
signature = addendumSignature(t, addendum);
if (signature) {
signature = t->m->classpath->makeString
(t, signature, 0, byteArrayLength(t, signature) - 1);
}
object annotationTable = fieldAddendum(t, vmField) == 0
? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField));
annotationTable = addendumAnnotationTable(t, addendum);
} else {
signature = 0;
annotationTable = 0;
}
if (annotationTable) {
PROTECT(t, signature);
@ -3767,12 +3813,21 @@ jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments)
methodAddendum(t, vmMethod));
PROTECT(t, exceptionTypes);
object signature = t->m->classpath->makeString
(t, methodSpec(t, vmMethod), 0, byteArrayLength
(t, methodSpec(t, vmMethod)) - 1);
object signature;
object annotationTable;
object addendum = methodAddendum(t, vmMethod);
if (addendum) {
signature = addendumSignature(t, addendum);
if (signature) {
signature = t->m->classpath->makeString
(t, signature, 0, byteArrayLength(t, signature) - 1);
}
object annotationTable = methodAddendum(t, vmMethod) == 0
? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod));
annotationTable = addendumAnnotationTable(t, addendum);
} else {
signature = 0;
annotationTable = 0;
}
if (annotationTable) {
PROTECT(t, signature);
@ -4405,7 +4460,7 @@ extern "C" JNIEXPORT jint JNICALL
EXPORT(JVM_GetSockOpt)(jint socket, int level, int optionName,
char* optionValue, int* optionLength)
{
socklen_t length;
socklen_t length = *optionLength;
int rv = getsockopt(socket, level, optionName, optionValue, &length);
*optionLength = length;
return rv;

View File

@ -954,7 +954,8 @@ addInterfaces(Thread* t, object class_, object map)
}
void
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool,
Machine::Type throwType)
{
PROTECT(t, class_);
PROTECT(t, pool);
@ -971,7 +972,8 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
object name = referenceName(t, singletonObject(t, pool, s.read2() - 1));
PROTECT(t, name);
object interface = resolveClass(t, classLoader(t, class_), name);
object interface = resolveClass
(t, classLoader(t, class_), name, true, throwType);
PROTECT(t, interface);
@ -1047,6 +1049,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool)
unsigned value = 0;
addendum = 0;
unsigned code = fieldCode
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
@ -1059,14 +1063,28 @@ 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*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeFieldAddendum(t, pool, 0, 0);
}
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeFieldAddendum(t, pool, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
addendum = makeFieldAddendum(t, pool, body);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
}
@ -1387,6 +1405,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
unsigned name = s.read2();
unsigned spec = s.read2();
addendum = 0;
code = 0;
unsigned attributeCount = s.read2();
@ -1402,7 +1421,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0);
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
unsigned exceptionCount = s.read2();
object body = makeShortArray(t, exceptionCount);
@ -1410,16 +1429,40 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
shortArrayBody(t, body, i) = s.read2();
}
set(t, addendum, MethodAddendumExceptionTable, body);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("AnnotationDefault"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
set(t, addendum, MethodAddendumAnnotationDefault, body);
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeMethodAddendum(t, pool, 0, 0);
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
length);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
@ -1632,6 +1675,12 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
void
parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
object addendum = 0;
PROTECT(t, addendum);
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
@ -1641,20 +1690,33 @@ 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*>("Signature"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeClassAddendum(t, pool, 0, 0);
}
set(t, addendum, AddendumSignature,
singletonObject(t, pool, s.read2() - 1));
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
("RuntimeVisibleAnnotations"),
&byteArrayBody(t, name, 0)) == 0)
{
if (addendum == 0) {
addendum = makeClassAddendum(t, pool, 0, 0);
}
object body = makeByteArray(t, length);
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)), length);
object addendum = makeClassAddendum(t, pool, body);
set(t, class_, ClassAddendum, addendum);
set(t, addendum, AddendumAnnotationTable, body);
} else {
s.skip(length);
}
}
set(t, class_, ClassAddendum, addendum);
}
void
@ -1713,6 +1775,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
set(t, bootstrapClass, ClassFieldTable, classFieldTable(t, class_));
set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_));
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
set(t, bootstrapClass, ClassAddendum, classAddendum(t, class_));
updateClassTables(t, bootstrapClass, class_);
}
@ -1765,7 +1828,8 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
}
object
makeArrayClass(Thread* t, object loader, object spec, bool throw_)
makeArrayClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
PROTECT(t, loader);
PROTECT(t, spec);
@ -1807,7 +1871,7 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_)
byteArrayEqual);
if (elementClass == 0) {
elementClass = resolveClass(t, loader, elementSpec, throw_);
elementClass = resolveClass(t, loader, elementSpec, throw_, throwType);
if (elementClass == 0) return 0;
}
@ -1820,7 +1884,8 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_)
}
object
resolveArrayClass(Thread* t, object loader, object spec, bool throw_)
resolveArrayClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
object c = hashMapFind
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
@ -1840,7 +1905,7 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_)
if (c) {
return c;
} else {
return makeArrayClass(t, loader, spec, throw_);
return makeArrayClass(t, loader, spec, throw_, throwType);
}
}
}
@ -3145,7 +3210,8 @@ primitiveSize(Thread* t, unsigned code)
}
object
parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
Machine::Type throwType)
{
PROTECT(t, loader);
@ -3199,7 +3265,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
unsigned super = s.read2();
if (super) {
object sc = resolveClass
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)));
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)),
true, throwType);
set(t, class_, ClassSuper, sc);
@ -3208,7 +3275,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag));
}
parseInterfaceTable(t, s, class_, pool);
parseInterfaceTable(t, s, class_, pool, throwType);
parseFieldTable(t, s, class_, pool);
@ -3249,7 +3316,8 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size)
}
object
resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
PROTECT(t, loader);
PROTECT(t, spec);
@ -3269,7 +3337,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
}
if (byteArrayBody(t, spec, 0) == '[') {
class_ = resolveArrayClass(t, loader, spec, throw_);
class_ = resolveArrayClass(t, loader, spec, throw_, throwType);
} else {
THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6);
memcpy(RUNTIME_ARRAY_BODY(file),
@ -3291,7 +3359,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
// parse class file
class_ = parseClass(t, loader, region->start(), region->length());
class_ = parseClass
(t, loader, region->start(), region->length(), throwType);
}
if (Verbose) {
@ -3318,8 +3387,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_)
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
} else if (throw_) {
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
}
}
@ -3339,10 +3407,11 @@ findLoadedClass(Thread* t, object loader, object spec)
}
object
resolveClass(Thread* t, object loader, object spec, bool throw_)
resolveClass(Thread* t, object loader, object spec, bool throw_,
Machine::Type throwType)
{
if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) {
return resolveSystemClass(t, loader, spec, throw_);
return resolveSystemClass(t, loader, spec, throw_, throwType);
} else {
PROTECT(t, loader);
PROTECT(t, spec);
@ -3353,7 +3422,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
}
if (byteArrayBody(t, spec, 0) == '[') {
c = resolveArrayClass(t, loader, spec, throw_);
c = resolveArrayClass(t, loader, spec, throw_, throwType);
} else {
if (root(t, Machine::LoadClassMethod) == 0) {
object m = resolveMethod
@ -3383,6 +3452,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
(&byteArrayBody(t, spec, 0)));
object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
PROTECT(t, specString);
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(method),
reinterpret_cast<uintptr_t>(loader),
@ -3395,7 +3465,9 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
c = jclassVmClass(t, jc);
} else if (t->exception) {
if (throw_) {
object e = t->exception;
object e = type(t, throwType) == objectClass(t, t->exception)
? t->exception
: makeThrowable(t, throwType, specString, 0, t->exception);
t->exception = 0;
vm::throw_(t, e);
} else {
@ -3417,8 +3489,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_)
hashMapInsert
(t, classLoaderMap(t, loader), spec, c, byteArrayHash);
} else if (throw_) {
throwNew(t, Machine::ClassNotFoundExceptionType, "%s",
&byteArrayBody(t, spec, 0));
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
}
return c;

View File

@ -2466,21 +2466,26 @@ object
parseUtf8(Thread* t, const char* data, unsigned length);
object
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length);
parseClass(Thread* t, object loader, const uint8_t* data, unsigned length,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
object
resolveClass(Thread* t, object loader, object name, bool throw_ = true);
resolveClass(Thread* t, object loader, object name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
inline object
resolveClass(Thread* t, object loader, const char* name, bool throw_ = true)
resolveClass(Thread* t, object loader, const char* name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType)
{
PROTECT(t, loader);
object n = makeByteArray(t, "%s", name);
return resolveClass(t, loader, n, throw_);
return resolveClass(t, loader, n, throw_, throwType);
}
object
resolveSystemClass(Thread* t, object loader, object name, bool throw_ = true);
resolveSystemClass
(Thread* t, object loader, object name, bool throw_ = true,
Machine::Type throwType = Machine::NoClassDefFoundErrorType);
inline object
resolveSystemClass(Thread* t, object loader, const char* name)