From f2394249307a53e66313ba9a20952b83c85e047a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 10 Jun 2009 18:15:00 -0600 Subject: [PATCH] implement NewDirectByteBuffer etc. properly when building against Classpath; call JNI_OnLoad if found in newly-loaded libraries --- makefile | 4 +-- src/builtin.cpp | 14 +++++++++ src/common.h | 1 - src/gnu.cpp | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ src/jnienv.cpp | 29 +++++++++-------- src/machine.cpp | 59 ++++++++++++++++++++++++----------- src/machine.h | 39 +++++++++++++++++++++-- 7 files changed, 193 insertions(+), 36 deletions(-) diff --git a/makefile b/makefile index 7a971cbefb..7510dd9664 100644 --- a/makefile +++ b/makefile @@ -56,7 +56,7 @@ ifdef gnu $(gnu)/lib/classpath/libjavanio.a \ $(gnu)/lib/classpath/libjavautil.a gnu-object-dep = $(build)/gnu-object.dep - gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" + gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU gnu-lflags = -lgmp gnu-objects = $(shell find $(build)/gnu-objects -name "*.o") endif @@ -473,7 +473,7 @@ $(test-dep): $(test-sources) @mkdir -p $(test-build) $(javac) -d $(test-build) -bootclasspath $(classpath-build) \ $(shell $(MAKE) -s --no-print-directory $(test-classes)) - $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(dir $(@)) \ + $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ test/Subroutine.java @touch $(@) diff --git a/src/builtin.cpp b/src/builtin.cpp index 0ab9d7205b..7b6d7048b7 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -71,6 +71,15 @@ compatibleArrayTypes(Thread* t, object a, object b) or (classVmFlags(t, b) & PrimitiveFlag)))); } +void +runOnLoadIfFound(Thread* t, System::Library* library) +{ + void* p = library->resolve("JNI_OnLoad"); + if (p) { + reinterpret_cast(p)(t->m, 0); + } +} + } // namespace extern "C" JNIEXPORT int64_t JNICALL @@ -612,6 +621,10 @@ Avian_java_lang_Runtime_load and (s[length] == ',' or s[length] == 0)) { // library is built in to this executable + if (not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + runOnLoadIfFound(t, t->m->libraries); + } return; } else { while (*s and *s != ',') ++ s; @@ -635,6 +648,7 @@ Avian_java_lang_Runtime_load System::Library* lib; if (LIKELY(t->m->system->success(t->m->system->load(&lib, n, mapName)))) { last->setNext(lib); + runOnLoadIfFound(t, lib); } else { object message = makeString(t, "library not found: %s", n); t->exception = makeUnsatisfiedLinkError(t, message); diff --git a/src/common.h b/src/common.h index c3c03e89c4..7f4abb3243 100644 --- a/src/common.h +++ b/src/common.h @@ -115,7 +115,6 @@ pad(unsigned n) return pad(n, BytesPerWord); } - inline unsigned ceiling(unsigned n, unsigned d) { diff --git a/src/gnu.cpp b/src/gnu.cpp index c76b0e3706..652217b352 100644 --- a/src/gnu.cpp +++ b/src/gnu.cpp @@ -33,6 +33,89 @@ setProperty(Thread* t, object method, object properties, } // namespace +namespace vm { + +jobject JNICALL +NewDirectByteBuffer(Thread* t, void* address, jlong capacity) +{ + const char* pointerClassName; + const char* initSpec; + if (BytesPerWord == 8) { + pointerClassName = "gnu/classpath/Pointer64"; + initSpec = "(J)V"; + } else { + pointerClassName = "gnu/classpath/Pointer32"; + initSpec = "(I)V"; + } + + object pointerClass = resolveClass(t, pointerClassName); + if (UNLIKELY(pointerClass == 0)) return 0; + PROTECT(t, pointerClass); + + object pointerConstructor = resolveMethod + (t, pointerClass, "", initSpec); + if (UNLIKELY(pointerConstructor == 0)) return 0; + + object pointer = make(t, pointerClass); + PROTECT(t, pointer); + + t->m->processor->invoke(t, pointerConstructor, pointer, address); + if (UNLIKELY(t->exception)) return 0; + + object bufferClass = resolveClass + (t, "java/nio/DirectByteBufferImpl$ReadWrite"); + if (UNLIKELY(bufferClass == 0)) return 0; + PROTECT(t, bufferClass); + + object bufferConstructor = resolveMethod + (t, bufferClass, "", "(Lgnu/classpath/Pointer;int)V"); + if (UNLIKELY(bufferConstructor == 0)) return 0; + + object buffer = make(t, bufferClass); + PROTECT(t, buffer); + + t->m->processor->invoke + (t, bufferConstructor, buffer, &pointer, static_cast(capacity)); + if (UNLIKELY(t->exception)) return 0; + + return makeLocalReference(t, buffer); +} + +void* JNICALL +GetDirectBufferAddress(Thread* t, jobject buffer) +{ + object addressField = resolveField + (t, objectClass(t, *buffer), "address", "Lgnu/classpath/Pointer;"); + if (UNLIKELY(addressField == 0)) return 0; + + object address = cast(*buffer, fieldOffset(t, addressField)); + if (address == 0) return 0; + + const char* dataSpec; + if (BytesPerWord == 8) { + dataSpec = "J"; + } else { + dataSpec = "I"; + } + + object dataField = resolveField + (t, objectClass(t, address), "data", dataSpec); + if (UNLIKELY(dataField == 0)) return 0; + + return cast(address, fieldOffset(t, dataField)); +} + +jlong JNICALL +GetDirectBufferCapacity(Thread* t, jobject buffer) +{ + object capField = resolveField(t, objectClass(t, *buffer), "cap", "I"); + if (UNLIKELY(capField == 0)) return 0; + + return cast(*buffer, fieldOffset(t, capField)); +} + +} // namespace vm + extern "C" JNIEXPORT void JNICALL Avian_gnu_classpath_VMSystemProperties_preInit (Thread* t, object, uintptr_t* arguments) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 199145ba6c..559a0c256d 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -256,6 +256,7 @@ ExceptionCheck(Thread* t) return t->exception != 0; } +#ifndef AVIAN_GNU jobject JNICALL NewDirectByteBuffer(Thread*, void*, jlong) { @@ -269,10 +270,11 @@ GetDirectBufferAddress(Thread*, jobject) } jlong JNICALL -GetDirectBufferCapacity(JNIEnv*, jobject) +GetDirectBufferCapacity(Thread*, jobject) { return -1; } +#endif// not AVIAN_GNU jclass JNICALL GetObjectClass(Thread* t, jobject o) @@ -833,22 +835,12 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) va_end(a); } -object -findField(Thread* t, jclass c, const char* name, const char* spec) -{ - object n = makeByteArray(t, "%s", name); - PROTECT(t, n); - - object s = makeByteArray(t, "%s", spec); - return vm::findField(t, *c, n, s); -} - jfieldID JNICALL GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { ENTER(t, Thread::ActiveState); - object field = findField(t, c, name, spec); + object field = resolveField(t, *c, name, spec); if (UNLIKELY(t->exception)) return 0; return fieldOffset(t, field); @@ -859,7 +851,7 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { ENTER(t, Thread::ActiveState); - object field = findField(t, c, name, spec); + object field = resolveField(t, *c, name, spec); if (UNLIKELY(t->exception)) return 0; return fieldOffset(t, field); @@ -1899,6 +1891,17 @@ append(char** p, const char* value, unsigned length, char tail) namespace vm { +#ifdef AVIAN_GNU +jobject JNICALL +NewDirectByteBuffer(Thread*, void*, jlong); + +void* JNICALL +GetDirectBufferAddress(Thread*, jobject); + +jlong JNICALL +GetDirectBufferCapacity(Thread*, jobject); +#endif//AVIAN_GNU + void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) { diff --git a/src/machine.cpp b/src/machine.cpp index d8d3a4d459..8e48c22bff 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1800,6 +1800,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, weakReferences(0), tenuredWeakReferences(0), unsafe(false), + triedBuiltinOnLoad(false), heapPoolIndex(0) { heap->setClient(heapClient); @@ -2600,33 +2601,55 @@ resolveClass(Thread* t, object spec) } object -resolveMethod(Thread* t, const char* className, const char* methodName, +resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec) { - object class_ = resolveClass(t, makeByteArray(t, "%s", className)); - if (LIKELY(t->exception == 0)) { - PROTECT(t, class_); + PROTECT(t, class_); - object name = makeByteArray(t, methodName); - PROTECT(t, name); + object name = makeByteArray(t, methodName); + PROTECT(t, name); - object spec = makeByteArray(t, methodSpec); - object reference = makeReference(t, class_, name, spec); + object spec = makeByteArray(t, methodSpec); - object method = findMethodInClass(t, class_, referenceName(t, reference), - referenceSpec(t, reference)); + object method = findMethodInClass(t, class_, name, spec); - if (t->exception == 0 and method == 0) { - object message = makeString - (t, "%s %s not found in %s", methodName, methodSpec, className); + if (t->exception == 0 and method == 0) { + object message = makeString + (t, "%s %s not found in %s", methodName, methodSpec, className); - t->exception = makeNoSuchMethodError(t, message); - } else { - return method; - } + t->exception = makeNoSuchMethodError(t, message); + return 0; + } else { + return method; + } +} + +object +resolveField(Thread* t, object class_, const char* fieldName, + const char* fieldSpec) +{ + PROTECT(t, class_); + + object name = makeByteArray(t, fieldName); + PROTECT(t, name); + + object spec = makeByteArray(t, fieldSpec); + PROTECT(t, spec); + + object field = 0; + for (; class_ != 0 and field == 0; class_ = classSuper(t, class_)) { + field = findFieldInClass(t, class_, name, spec); } - return 0; + if (t->exception == 0 and field == 0) { + object message = makeString + (t, "%s %s not found in %s", fieldName, fieldSpec, className); + + t->exception = makeNoSuchFieldError(t, message); + return 0; + } else { + return field; + } } object diff --git a/src/machine.h b/src/machine.h index a03693aee8..021d8414a7 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1195,6 +1195,7 @@ class Machine { object weakReferences; object tenuredWeakReferences; bool unsafe; + bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; @@ -2049,12 +2050,46 @@ object parseClass(Thread* t, const uint8_t* data, unsigned length); object -resolveClass(Thread* t, object spec); +resolveClass(Thread* t, object name); + +inline object +resolveClass(Thread* t, const char* name) +{ + return resolveClass(t, makeByteArray(t, "%s", name)); +} object -resolveMethod(Thread* t, const char* className, const char* methodName, +resolveMethod(Thread* t, object class_, const char* methodName, const char* methodSpec); +inline object +resolveMethod(Thread* t, const char* className, const char* methodName, + const char* methodSpec) +{ + object class_ = resolveClass(t, className); + if (LIKELY(t->exception == 0)) { + return resolveMethod(t, class_, methodName, methodSpec); + } else { + return 0; + } +} + +object +resolveField(Thread* t, object class_, const char* fieldName, + const char* fieldSpec); + +inline object +resolveField(Thread* t, const char* className, const char* fieldName, + const char* fieldSpec) +{ + object class_ = resolveClass(t, className); + if (LIKELY(t->exception == 0)) { + return resolveField(t, class_, fieldName, fieldSpec); + } else { + return 0; + } +} + object resolveObjectArrayClass(Thread* t, object elementSpec);