diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index ce9cdcd7a3..4792d6a0c5 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -74,6 +74,21 @@ public class SystemClassLoader extends ClassLoader { return null; } + protected Package getPackage(String name) { + Package p = super.getPackage(name); + if (p == null) { + String source = getPackageSource(name); + if (source != null) { + // todo: load attributes from JAR manifest + definePackage(name, null, null, null, null, null, null, null); + } + } + + return super.getPackage(name); + } + + protected static native String getPackageSource(String name); + // OpenJDK's java.lang.ClassLoader.getResource makes use of // sun.misc.Launcher to load bootstrap resources, which is not // appropriate for the Avian build, so we override it to ensure we diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index d5672c7183..cf21288e3f 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -559,8 +559,7 @@ public final class Class implements Type, AnnotatedElement { String name = getCanonicalName(); int index = name.lastIndexOf('.'); if (index >= 0) { - return new Package(name.substring(0, index), - null, null, null, null, null, null, null, null); + return getClassLoader().getPackage(name.substring(0, index)); } else { return null; } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 013903b1dd..daf46aecc4 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -17,9 +17,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; +import java.util.Map; +import java.util.HashMap; public abstract class ClassLoader { private final ClassLoader parent; + private Map packages; protected ClassLoader(ClassLoader parent) { if (parent == null) { @@ -33,6 +36,45 @@ public abstract class ClassLoader { this(getSystemClassLoader()); } + private Map packages() { + if (packages == null) { + packages = new HashMap(); + } + return packages; + } + + protected Package getPackage(String name) { + synchronized (this) { + return packages().get(name); + } + } + + protected Package[] getPackages() { + synchronized (this) { + return packages().values().toArray(new Package[packages().size()]); + } + } + + protected Package definePackage(String name, + String specificationTitle, + String specificationVersion, + String specificationVendor, + String implementationTitle, + String implementationVersion, + String implementationVendor, + URL sealBase) + { + Package p = new Package + (name, implementationTitle, implementationVersion, + implementationVendor, specificationTitle, specificationVersion, + specificationVendor, sealBase, this); + + synchronized (this) { + packages().put(name, p); + return p; + } + } + public static ClassLoader getSystemClassLoader() { return ClassLoader.class.getClassLoader(); } diff --git a/src/avian/machine.h b/src/avian/machine.h index 7450a18587..ae8fe8e749 100644 --- a/src/avian/machine.h +++ b/src/avian/machine.h @@ -1577,9 +1577,6 @@ class Classpath { virtual const char* bootClasspath() = 0; - virtual void - updatePackageMap(Thread* t, object class_) = 0; - virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) = 0; diff --git a/src/builtin.cpp b/src/builtin.cpp index 54b2e73076..6bcc4f5e16 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -238,6 +238,36 @@ Avian_avian_SystemClassLoader_getClass (getJClass(t, reinterpret_cast(arguments[0]))); } +extern "C" AVIAN_EXPORT int64_t JNICALL +Avian_avian_SystemClassLoader_getPackageSource +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + ACQUIRE(t, t->m->classLock); + + THREAD_RUNTIME_ARRAY(t, char, chars, stringLength(t, name) + 2); + stringChars(t, name, RUNTIME_ARRAY_BODY(chars)); + replace('.', '/', RUNTIME_ARRAY_BODY(chars)); + RUNTIME_ARRAY_BODY(chars)[stringLength(t, name)] = '/'; + RUNTIME_ARRAY_BODY(chars)[stringLength(t, name) + 1] = 0; + + object key = makeByteArray(t, RUNTIME_ARRAY_BODY(chars)); + + object array = hashMapFind + (t, root(t, Machine::PackageMap), key, byteArrayHash, byteArrayEqual); + + if (array) { + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, byteArrayLength(t, array)))); + } else { + return 0; + } +} + #ifdef AVIAN_HEAPDUMP extern "C" AVIAN_EXPORT void JNICALL diff --git a/src/classpath-android.cpp b/src/classpath-android.cpp index 9221ae2614..0966755984 100644 --- a/src/classpath-android.cpp +++ b/src/classpath-android.cpp @@ -22,6 +22,7 @@ extern "C" int JNI_OnLoad(JavaVM*, void*); #include "avian/machine.h" #include "avian/classpath-common.h" #include "avian/process.h" +#include "avian/util.h" #ifdef PLATFORM_WINDOWS const char* getErrnoDescription(int err); // This function is defined in mingw-extensions.cpp @@ -488,9 +489,22 @@ class MyClasspath : public Classpath { } virtual void - boot(Thread*) + boot(Thread* t) { - // ignore + object c = resolveClass + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader"); + PROTECT(t, c); + + object constructor = resolveMethod + (t, c, "", "(Ljava/lang/ClassLoader;Z)V"); + PROTECT(t, constructor); + + t->m->processor->invoke + (t, constructor, root(t, Machine::BootLoader), 0, true); + + t->m->processor->invoke + (t, constructor, root(t, Machine::AppLoader), + root(t, Machine::BootLoader), false); } virtual const char* @@ -499,12 +513,6 @@ class MyClasspath : public Classpath { return AVIAN_CLASSPATH; } - virtual void - updatePackageMap(Thread*, object) - { - // ignore - } - virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index e49d4fa0c1..217333659b 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -133,12 +133,6 @@ class MyClasspath : public Classpath { return AVIAN_CLASSPATH; } - virtual void - updatePackageMap(Thread*, object) - { - // ignore - } - virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 812b69f0c5..723ce7e475 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -774,62 +774,6 @@ class MyClasspath : public Classpath { return classpath; } - virtual void - updatePackageMap(Thread* t, object class_) - { - PROTECT(t, class_); - - if (root(t, Machine::PackageMap) == 0) { - setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0)); - } - - object className = vm::className(t, class_); - if ('[' != byteArrayBody(t, className, 0)) { - THREAD_RUNTIME_ARRAY - (t, char, packageName, byteArrayLength(t, className)); - - char* s = reinterpret_cast(&byteArrayBody(t, className, 0)); - char* p = strrchr(s, '/'); - - if (p) { - int length = (p - s) + 1; - memcpy(RUNTIME_ARRAY_BODY(packageName), - &byteArrayBody(t, className, 0), - length); - RUNTIME_ARRAY_BODY(packageName)[length] = 0; - - object key = vm::makeByteArray - (t, "%s", RUNTIME_ARRAY_BODY(packageName)); - PROTECT(t, key); - - hashMapRemove - (t, root(t, Machine::PackageMap), key, byteArrayHash, - byteArrayEqual); - - object source = classSource(t, class_); - if (source) { - // note that we strip the "file:" prefix, since - // Package.defineSystemPackage expects an unadorned - // filename: - const unsigned PrefixLength = 5; - unsigned sourceNameLength = byteArrayLength(t, source) - - PrefixLength; - THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength); - memcpy(RUNTIME_ARRAY_BODY(sourceName), - &byteArrayBody(t, source, PrefixLength), - sourceNameLength); - - source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName)); - } else { - source = vm::makeByteArray(t, "avian-dummy-package-source"); - } - - hashMapInsert - (t, root(t, Machine::PackageMap), key, source, byteArrayHash); - } - } - } - virtual object makeDirectByteBuffer(Thread* t, void* p, jlong capacity) { diff --git a/src/machine.cpp b/src/machine.cpp index 7c62617d09..74719cdbc2 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3042,6 +3042,61 @@ findInTable(Thread* t, object table, object name, object spec, return 0; } +void +updatePackageMap(Thread* t, object class_) +{ + PROTECT(t, class_); + + if (root(t, Machine::PackageMap) == 0) { + setRoot(t, Machine::PackageMap, makeHashMap(t, 0, 0)); + } + + object className = vm::className(t, class_); + if ('[' != byteArrayBody(t, className, 0)) { + THREAD_RUNTIME_ARRAY + (t, char, packageName, byteArrayLength(t, className)); + + char* s = reinterpret_cast(&byteArrayBody(t, className, 0)); + char* p = strrchr(s, '/'); + + if (p) { + int length = (p - s) + 1; + memcpy(RUNTIME_ARRAY_BODY(packageName), + &byteArrayBody(t, className, 0), + length); + RUNTIME_ARRAY_BODY(packageName)[length] = 0; + + object key = vm::makeByteArray + (t, "%s", RUNTIME_ARRAY_BODY(packageName)); + PROTECT(t, key); + + hashMapRemove + (t, root(t, Machine::PackageMap), key, byteArrayHash, + byteArrayEqual); + + object source = classSource(t, class_); + if (source) { + // note that we strip the "file:" prefix, since OpenJDK's + // Package.defineSystemPackage expects an unadorned filename: + const unsigned PrefixLength = 5; + unsigned sourceNameLength = byteArrayLength(t, source) + - PrefixLength; + THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength); + memcpy(RUNTIME_ARRAY_BODY(sourceName), + &byteArrayBody(t, source, PrefixLength), + sourceNameLength); + + source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName)); + } else { + source = vm::makeByteArray(t, "avian-dummy-package-source"); + } + + hashMapInsert + (t, root(t, Machine::PackageMap), key, source, byteArrayHash); + } + } +} + } // namespace namespace vm { @@ -4295,7 +4350,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_, if (class_) { hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); - t->m->classpath->updatePackageMap(t, class_); + updatePackageMap(t, class_); } else if (throw_) { throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0)); } diff --git a/test/Reflection.java b/test/Reflection.java index 2661c07ff5..2a59548bec 100644 --- a/test/Reflection.java +++ b/test/Reflection.java @@ -249,6 +249,9 @@ public class Reflection { expect(getClass().getDeclaringClass() == null); } }.run(); + + expect(avian.testing.annotations.Test.class.getPackage().getName().equals + ("avian.testing.annotations")); } protected static class Baz {