Implement jfieldID and jmethodID properly.
Change-Id: I048107fbca4e21cf34e8fda6defdbc0b97421cf0
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index f28bff9..dbb2674 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -20,244 +20,123 @@
namespace art {
-jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args);
-void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass clazz,
- jmethodID methodID, va_list args);
-void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass clazz,
- jmethodID methodID, jvalue* args);
+// This is private API, but with two different implementations: ARM and x86.
+void CreateInvokeStub(Assembler* assembler, Method* method);
-enum JNI_OnLoadState {
- kPending = 0, /* initial state, must be zero */
- kFailed,
- kOkay,
-};
+// TODO: this should be in our anonymous namespace, but is currently needed
+// for testing in "jni_internal_test.cc".
+bool EnsureInvokeStub(Method* method) {
+ if (method->GetInvokeStub() != NULL) {
+ return true;
+ }
+ // TODO: use signature to find a matching stub
+ // TODO: failed, acquire a lock on the stub table
+ Assembler assembler;
+ CreateInvokeStub(&assembler, method);
+ // TODO: store native_entry in the stub table
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ size_t length = assembler.CodeSize();
+ void* addr = mmap(NULL, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (addr == MAP_FAILED) {
+ PLOG(FATAL) << "mmap failed";
+ }
+ MemoryRegion region(addr, length);
+ assembler.FinalizeInstructions(region);
+ method->SetInvokeStub(reinterpret_cast<Method::InvokeStub*>(region.pointer()));
+ return true;
+}
-struct SharedLibrary {
- SharedLibrary() : jni_on_load_lock(Mutex::Create("JNI_OnLoad lock")) {
+// TODO: this can't be in our anonymous namespace because of the map in JavaVM.
+class SharedLibrary {
+public:
+ SharedLibrary(const std::string& path, void* handle, Object* class_loader)
+ : path_(path),
+ handle_(handle),
+ jni_on_load_lock_(Mutex::Create("JNI_OnLoad lock")),
+ jni_on_load_tid_(Thread::Current()->GetId()),
+ jni_on_load_result_(kPending) {
}
~SharedLibrary() {
- delete jni_on_load_lock;
+ delete jni_on_load_lock_;
}
- // Path to library "/system/lib/libjni.so".
- std::string path;
-
- // The void* returned by dlopen(3).
- void* handle;
-
- // The ClassLoader this library is associated with.
- Object* class_loader;
-
- // Guards remaining items.
- Mutex* jni_on_load_lock;
- // Wait for JNI_OnLoad in other thread.
- pthread_cond_t jni_on_load_cond;
- // Recursive invocation guard.
- uint32_t jni_on_load_tid;
- // Result of earlier JNI_OnLoad call.
- JNI_OnLoadState jni_on_load_result;
-};
-
-/*
- * Check the result of an earlier call to JNI_OnLoad on this library. If
- * the call has not yet finished in another thread, wait for it.
- */
-bool CheckOnLoadResult(JavaVMExt* vm, SharedLibrary* library) {
- Thread* self = Thread::Current();
- if (library->jni_on_load_tid == self->GetId()) {
- // Check this so we don't end up waiting for ourselves. We need
- // to return "true" so the caller can continue.
- LOG(INFO) << *self << " recursive attempt to load library "
- << "\"" << library->path << "\"";
- return true;
+ Object* GetClassLoader() {
+ return class_loader_;
}
- UNIMPLEMENTED(ERROR) << "need to pthread_cond_wait!";
- // MutexLock mu(library->jni_on_load_lock);
- while (library->jni_on_load_result == kPending) {
- if (vm->verbose_jni) {
- LOG(INFO) << "[" << *self << " waiting for \"" << library->path << "\" "
- << "JNI_OnLoad...]";
- }
- Thread::State old_state = self->GetState();
- self->SetState(Thread::kWaiting); // TODO: VMWAIT
- // pthread_cond_wait(&library->jni_on_load_cond, &library->jni_on_load_lock);
- self->SetState(old_state);
- }
-
- bool okay = (library->jni_on_load_result == kOkay);
- if (vm->verbose_jni) {
- LOG(INFO) << "[Earlier JNI_OnLoad for \"" << library->path << "\" "
- << (okay ? "succeeded" : "failed") << "]";
- }
- return okay;
-}
-
-typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
-
-/*
- * Load native code from the specified absolute pathname. Per the spec,
- * if we've already loaded a library with the specified pathname, we
- * return without doing anything.
- *
- * TODO? for better results we should absolutify the pathname. For fully
- * correct results we should stat to get the inode and compare that. The
- * existing implementation is fine so long as everybody is using
- * System.loadLibrary.
- *
- * The library will be associated with the specified class loader. The JNI
- * spec says we can't load the same library into more than one class loader.
- *
- * Returns "true" on success. On failure, sets *detail to a
- * human-readable description of the error or NULL if no detail is
- * available; ownership of the string is transferred to the caller.
- */
-bool JavaVMExt::LoadNativeLibrary(const std::string& path, Object* class_loader, char** detail) {
- *detail = NULL;
-
- // See if we've already loaded this library. If we have, and the class loader
- // matches, return successfully without doing anything.
- SharedLibrary* library = libraries[path];
- if (library != NULL) {
- if (library->class_loader != class_loader) {
- LOG(WARNING) << "Shared library \"" << path << "\" already opened by "
- << "ClassLoader " << library->class_loader << "; "
- << "can't open in " << class_loader;
- *detail = strdup("already opened by different ClassLoader");
- return false;
- }
- if (verbose_jni) {
- LOG(INFO) << "[Shared library \"" << path << "\" already loaded in "
- << "ClassLoader " << class_loader << "]";
- }
- if (!CheckOnLoadResult(this, library)) {
- *detail = strdup("JNI_OnLoad failed before");
- return false;
- }
- return true;
- }
-
- // Open the shared library. Because we're using a full path, the system
- // doesn't have to search through LD_LIBRARY_PATH. (It may do so to
- // resolve this library's dependencies though.)
-
- // Failures here are expected when java.library.path has several entries
- // and we have to hunt for the lib.
-
- // The current version of the dynamic linker prints detailed information
- // about dlopen() failures. Some things to check if the message is
- // cryptic:
- // - make sure the library exists on the device
- // - verify that the right path is being opened (the debug log message
- // above can help with that)
- // - check to see if the library is valid (e.g. not zero bytes long)
- // - check config/prelink-linux-arm.map to ensure that the library
- // is listed and is not being overrun by the previous entry (if
- // loading suddenly stops working on a prelinked library, this is
- // a good one to check)
- // - write a trivial app that calls sleep() then dlopen(), attach
- // to it with "strace -p <pid>" while it sleeps, and watch for
- // attempts to open nonexistent dependent shared libs
-
- // TODO: automate some of these checks!
-
- // This can execute slowly for a large library on a busy system, so we
- // want to switch from RUNNING to VMWAIT while it executes. This allows
- // the GC to ignore us.
- Thread* self = Thread::Current();
- Thread::State old_state = self->GetState();
- self->SetState(Thread::kWaiting); // TODO: VMWAIT
- void* handle = dlopen(path.c_str(), RTLD_LAZY);
- self->SetState(old_state);
-
- if (verbose_jni) {
- LOG(INFO) << "[Call to dlopen(\"" << path << "\") returned " << handle << "]";
- }
-
- if (handle == NULL) {
- *detail = strdup(dlerror());
- return false;
- }
-
- // Create a new entry.
- library = new SharedLibrary;
- library->path = path;
- library->handle = handle;
- library->class_loader = class_loader;
- UNIMPLEMENTED(ERROR) << "missing pthread_cond_init";
- // pthread_cond_init(&library->onLoadCond, NULL);
- library->jni_on_load_tid = self->GetId();
-
- libraries[path] = library;
-
-// if (pNewEntry != pActualEntry) {
-// LOG(INFO) << "WOW: we lost a race to add a shared library (\"" << path << "\" ClassLoader=" << class_loader <<")";
-// freeSharedLibEntry(pNewEntry);
-// return CheckOnLoadResult(this, pActualEntry);
-// } else
- {
- if (verbose_jni) {
- LOG(INFO) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
+ /*
+ * Check the result of an earlier call to JNI_OnLoad on this library. If
+ * the call has not yet finished in another thread, wait for it.
+ */
+ bool CheckOnLoadResult(JavaVMExt* vm) {
+ Thread* self = Thread::Current();
+ if (jni_on_load_tid_ == self->GetId()) {
+ // Check this so we don't end up waiting for ourselves. We need
+ // to return "true" so the caller can continue.
+ LOG(INFO) << *self << " recursive attempt to load library "
+ << "\"" << path_ << "\"";
+ return true;
}
- bool result = true;
- void* sym = dlsym(handle, "JNI_OnLoad");
- if (sym == NULL) {
- if (verbose_jni) {
- LOG(INFO) << "[No JNI_OnLoad found in \"" << path << "\"]";
+ UNIMPLEMENTED(ERROR) << "need to pthread_cond_wait!";
+ // MutexLock mu(jni_on_load_lock_);
+ while (jni_on_load_result_ == kPending) {
+ if (vm->verbose_jni) {
+ LOG(INFO) << "[" << *self << " waiting for \"" << path_ << "\" "
+ << "JNI_OnLoad...]";
}
- } else {
- // Call JNI_OnLoad. We have to override the current class
- // loader, which will always be "null" since the stuff at the
- // top of the stack is around Runtime.loadLibrary(). (See
- // the comments in the JNI FindClass function.)
- UNIMPLEMENTED(WARNING) << "need to override current class loader";
- JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
- //Object* prevOverride = self->classLoaderOverride;
- //self->classLoaderOverride = classLoader;
-
- old_state = self->GetState();
- self->SetState(Thread::kNative);
- if (verbose_jni) {
- LOG(INFO) << "[Calling JNI_OnLoad in \"" << path << "\"]";
- }
- int version = (*jni_on_load)(reinterpret_cast<JavaVM*>(this), NULL);
+ Thread::State old_state = self->GetState();
+ self->SetState(Thread::kWaiting); // TODO: VMWAIT
+ // pthread_cond_wait(&jni_on_load_cond_, &jni_on_load_lock_);
self->SetState(old_state);
-
- UNIMPLEMENTED(WARNING) << "need to restore current class loader";
- //self->classLoaderOverride = prevOverride;
-
- if (version != JNI_VERSION_1_2 &&
- version != JNI_VERSION_1_4 &&
- version != JNI_VERSION_1_6) {
- LOG(WARNING) << "JNI_OnLoad in \"" << path << "\" returned "
- << "bad version: " << version;
- // It's unwise to call dlclose() here, but we can mark it
- // as bad and ensure that future load attempts will fail.
- // We don't know how far JNI_OnLoad got, so there could
- // be some partially-initialized stuff accessible through
- // newly-registered native method calls. We could try to
- // unregister them, but that doesn't seem worthwhile.
- result = false;
- } else {
- if (verbose_jni) {
- LOG(INFO) << "[Returned " << (result ? "successfully" : "failure")
- << " from JNI_OnLoad in \"" << path << "\"]";
- }
- }
}
- library->jni_on_load_result = result ? kOkay : kFailed;
- library->jni_on_load_tid = 0;
+ bool okay = (jni_on_load_result_ == kOkay);
+ if (vm->verbose_jni) {
+ LOG(INFO) << "[Earlier JNI_OnLoad for \"" << path_ << "\" "
+ << (okay ? "succeeded" : "failed") << "]";
+ }
+ return okay;
+ }
+
+ void SetResult(bool result) {
+ jni_on_load_result_ = result ? kOkay : kFailed;
+ jni_on_load_tid_ = 0;
// Broadcast a wakeup to anybody sleeping on the condition variable.
UNIMPLEMENTED(ERROR) << "missing pthread_cond_broadcast";
- // MutexLock mu(library->jni_on_load_lock);
- // pthread_cond_broadcast(&library->jni_on_load_cond);
- return result;
+ // MutexLock mu(library->jni_on_load_lock_);
+ // pthread_cond_broadcast(&library->jni_on_load_cond_);
}
-}
+
+ private:
+ enum JNI_OnLoadState {
+ kPending,
+ kFailed,
+ kOkay,
+ };
+
+ // Path to library "/system/lib/libjni.so".
+ std::string path_;
+
+ // The void* returned by dlopen(3).
+ void* handle_;
+
+ // The ClassLoader this library is associated with.
+ Object* class_loader_;
+
+ // Guards remaining items.
+ Mutex* jni_on_load_lock_;
+ // Wait for JNI_OnLoad in other thread.
+ pthread_cond_t jni_on_load_cond_;
+ // Recursive invocation guard.
+ uint32_t jni_on_load_tid_;
+ // Result of earlier JNI_OnLoad call.
+ JNI_OnLoadState jni_on_load_result_;
+};
+
+namespace {
// Entry/exit processing for all JNI calls.
//
@@ -355,6 +234,17 @@
return reinterpret_cast<T>(ref);
}
+jweak AddWeakGlobalReference(ScopedJniThreadState& ts, Object* obj) {
+ if (obj == NULL) {
+ return NULL;
+ }
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& weak_globals = vm->weak_globals;
+ MutexLock mu(vm->weak_globals_lock);
+ IndirectRef ref = weak_globals.Add(IRT_FIRST_SEGMENT, obj);
+ return reinterpret_cast<jweak>(ref);
+}
+
template<typename T>
T Decode(ScopedJniThreadState& ts, jobject obj) {
if (obj == NULL) {
@@ -408,27 +298,12 @@
return reinterpret_cast<T>(result);
}
-void CreateInvokeStub(Assembler* assembler, Method* method);
+Field* DecodeField(ScopedJniThreadState& ts, jfieldID fid) {
+ return Decode<Field*>(ts, reinterpret_cast<jweak>(fid));
+}
-bool EnsureInvokeStub(Method* method) {
- if (method->GetInvokeStub() != NULL) {
- return true;
- }
- // TODO: use signature to find a matching stub
- // TODO: failed, acquire a lock on the stub table
- Assembler assembler;
- CreateInvokeStub(&assembler, method);
- // TODO: store native_entry in the stub table
- int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- size_t length = assembler.CodeSize();
- void* addr = mmap(NULL, length, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (addr == MAP_FAILED) {
- PLOG(FATAL) << "mmap failed";
- }
- MemoryRegion region(addr, length);
- assembler.FinalizeInstructions(region);
- method->SetInvokeStub(reinterpret_cast<Method::InvokeStub*>(region.pointer()));
- return true;
+Method* DecodeMethod(ScopedJniThreadState& ts, jmethodID mid) {
+ return Decode<Method*>(ts, reinterpret_cast<jweak>(mid));
}
byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) {
@@ -506,9 +381,8 @@
}
JValue InvokeWithArgArray(ScopedJniThreadState& ts, jobject obj,
- jmethodID method_id, byte* args) {
- // TODO: DecodeReference
- Method* method = reinterpret_cast<Method*>(method_id);
+ jmethodID mid, byte* args) {
+ Method* method = DecodeMethod(ts, mid);
Object* rcvr = Decode<Object*>(ts, obj);
Thread* self = ts.Self();
@@ -536,28 +410,17 @@
}
JValue InvokeWithJValues(ScopedJniThreadState& ts, jobject obj,
- jmethodID method_id, jvalue* args) {
- Method* method = reinterpret_cast<Method*>(method_id);
+ jmethodID mid, jvalue* args) {
+ Method* method = DecodeMethod(ts, mid);
scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
- return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
+ return InvokeWithArgArray(ts, obj, mid, arg_array.get());
}
JValue InvokeWithVarArgs(ScopedJniThreadState& ts, jobject obj,
- jmethodID method_id, va_list args) {
- Method* method = reinterpret_cast<Method*>(method_id);
+ jmethodID mid, va_list args) {
+ Method* method = DecodeMethod(ts, mid);
scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
- return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
-}
-
-jint GetVersion(JNIEnv* env) {
- ScopedJniThreadState ts(env);
- return JNI_VERSION_1_6;
-}
-
-jclass DefineClass(JNIEnv* env, const char*, jobject, const jbyte*, jsize) {
- ScopedJniThreadState ts(env);
- LOG(WARNING) << "JNI DefineClass is not supported";
- return NULL;
+ return InvokeWithArgArray(ts, obj, mid, arg_array.get());
}
// Section 12.3.2 of the JNI spec describes JNI class descriptors. They're
@@ -584,1268 +447,68 @@
return result;
}
-jclass FindClass(JNIEnv* env, const char* name) {
- ScopedJniThreadState ts(env);
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- std::string descriptor(NormalizeJniClassDescriptor(name));
- // TODO: need to get the appropriate ClassLoader.
- Class* c = class_linker->FindClass(descriptor, NULL);
- return AddLocalReference<jclass>(ts, c);
-}
-
-jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jfieldID FromReflectedField(JNIEnv* env, jobject field) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jobject ToReflectedMethod(JNIEnv* env, jclass cls,
- jmethodID methodID, jboolean isStatic) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jclass GetSuperclass(JNIEnv* env, jclass sub) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jboolean IsAssignableFrom(JNIEnv* env, jclass sub, jclass sup) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jobject ToReflectedField(JNIEnv* env, jclass cls,
- jfieldID fieldID, jboolean isStatic) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jint Throw(JNIEnv* env, jthrowable obj) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint ThrowNew(JNIEnv* env, jclass clazz, const char* msg) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jthrowable ExceptionOccurred(JNIEnv* env) {
- ScopedJniThreadState ts(env);
- Object* exception = ts.Self()->GetException();
- if (exception == NULL) {
- return NULL;
- } else {
- // TODO: if adding a local reference failing causes the VM to abort
- // then the following check will never occur.
- jthrowable localException = AddLocalReference<jthrowable>(ts, exception);
- if (localException == NULL) {
- // We were unable to add a new local reference, and threw a new
- // exception. We can't return "exception", because it's not a
- // local reference. So we have to return NULL, indicating that
- // there was no exception, even though it's pretty much raining
- // exceptions in here.
- LOG(WARNING) << "JNI WARNING: addLocal/exception combo";
- }
- return localException;
- }
-}
-
-void ExceptionDescribe(JNIEnv* env) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ExceptionClear(JNIEnv* env) {
- ScopedJniThreadState ts(env);
- ts.Self()->ClearException();
-}
-
-void FatalError(JNIEnv* env, const char* msg) {
- ScopedJniThreadState ts(env);
- LOG(FATAL) << "JNI FatalError called: " << msg;
-}
-
-jint PushLocalFrame(JNIEnv* env, jint cap) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING) << "ignoring PushLocalFrame(" << cap << ")";
- return JNI_OK;
-}
-
-jobject PopLocalFrame(JNIEnv* env, jobject res) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING) << "ignoring PopLocalFrame " << res;
- return res;
-}
-
-jobject NewGlobalRef(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return NULL;
- }
-
- JavaVMExt* vm = Runtime::Current()->GetJavaVM();
- IndirectReferenceTable& globals = vm->globals;
- MutexLock mu(vm->globals_lock);
- IndirectRef ref = globals.Add(IRT_FIRST_SEGMENT, Decode<Object*>(ts, obj));
- return reinterpret_cast<jobject>(ref);
-}
-
-void DeleteGlobalRef(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return;
- }
-
- JavaVMExt* vm = Runtime::Current()->GetJavaVM();
- IndirectReferenceTable& globals = vm->globals;
- MutexLock mu(vm->globals_lock);
-
- if (!globals.Remove(IRT_FIRST_SEGMENT, obj)) {
- LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
- << "failed to find entry";
- }
-}
-
-jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return NULL;
- }
-
- JavaVMExt* vm = Runtime::Current()->GetJavaVM();
- IndirectReferenceTable& weak_globals = vm->weak_globals;
- MutexLock mu(vm->weak_globals_lock);
- IndirectRef ref = weak_globals.Add(IRT_FIRST_SEGMENT, Decode<Object*>(ts, obj));
- return reinterpret_cast<jobject>(ref);
-}
-
-void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return;
- }
-
- JavaVMExt* vm = Runtime::Current()->GetJavaVM();
- IndirectReferenceTable& weak_globals = vm->weak_globals;
- MutexLock mu(vm->weak_globals_lock);
-
- if (!weak_globals.Remove(IRT_FIRST_SEGMENT, obj)) {
- LOG(WARNING) << "JNI WARNING: DeleteWeakGlobalRef(" << obj << ") "
- << "failed to find entry";
- }
-}
-
-jobject NewLocalRef(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return NULL;
- }
-
- IndirectReferenceTable& locals = ts.Env()->locals;
-
- uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
- IndirectRef ref = locals.Add(cookie, Decode<Object*>(ts, obj));
- return reinterpret_cast<jobject>(ref);
-}
-
-void DeleteLocalRef(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- if (obj == NULL) {
- return;
- }
-
- IndirectReferenceTable& locals = ts.Env()->locals;
-
- uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
- if (!locals.Remove(cookie, obj)) {
- // Attempting to delete a local reference that is not in the
- // topmost local reference frame is a no-op. DeleteLocalRef returns
- // void and doesn't throw any exceptions, but we should probably
- // complain about it so the user will notice that things aren't
- // going quite the way they expect.
- LOG(WARNING) << "JNI WARNING: DeleteLocalRef(" << obj << ") "
- << "failed to find entry";
- }
-}
-
-jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) {
- ScopedJniThreadState ts(env);
- return (Decode<Object*>(ts, obj1) == Decode<Object*>(ts, obj2))
- ? JNI_TRUE : JNI_FALSE;
-}
-
-jint EnsureLocalCapacity(JNIEnv* env, jint) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jobject AllocObject(JNIEnv* env, jclass clazz) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jobject NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list args;
- va_start(args, methodID);
- jobject result = NewObjectV(env, clazz, methodID, args);
- va_end(args);
- return result;
-}
-
-jobject NewObjectV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- Class* klass = Decode<Class*>(ts, clazz);
- Object* result = klass->NewInstance();
- jobject local_result = AddLocalReference<jobject>(ts, result);
- CallNonvirtualVoidMethodV(env, local_result, clazz, methodID, args);
- return local_result;
-}
-
-jobject NewObjectA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- Class* klass = Decode<Class*>(ts, clazz);
- Object* result = klass->NewInstance();
- jobject local_result = AddLocalReference<jobjectArray>(ts, result);
- CallNonvirtualVoidMethodA(env, local_result, clazz, methodID, args);
- return local_result;
-}
-
-jclass GetObjectClass(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass clazz) {
- ScopedJniThreadState ts(env);
- CHECK_NE(static_cast<jclass>(NULL), clazz);
- if (jobj == NULL) {
- // NB. JNI is different from regular Java instanceof in this respect
- return JNI_TRUE;
- } else {
- Object* obj = Decode<Object*>(ts, jobj);
- Class* klass = Decode<Class*>(ts, clazz);
- return Object::InstanceOf(obj, klass) ? JNI_TRUE : JNI_FALSE;
- }
-}
-
-jmethodID GetMethodID(JNIEnv* env,
- jclass clazz, const char* name, const char* sig) {
- ScopedJniThreadState ts(env);
- Class* klass = Decode<Class*>(ts, clazz);
- if (!klass->IsInitialized()) {
+jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
+ Class* c = Decode<Class*>(ts, jni_class);
+ if (!c->IsInitialized()) {
// TODO: initialize the class
}
- Method* method = klass->FindVirtualMethod(name, sig);
- if (method == NULL) {
- // No virtual method matching the signature. Search declared
- // private methods and constructors.
- method = klass->FindDeclaredDirectMethod(name, sig);
- }
- if (method == NULL) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "no method \"%s.%s%s\"",
- class_name.c_str(), name, sig);
- return NULL;
- } else if (method->IsStatic()) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "method \"%s.%s%s\" is static",
- class_name.c_str(), name, sig);
- return NULL;
+
+ Method* method = NULL;
+ if (is_static) {
+ method = c->FindDirectMethod(name, sig);
} else {
- // TODO: create a JNI weak global reference for method
- bool success = EnsureInvokeStub(method);
- if (!success) {
- // TODO: throw OutOfMemoryException
- return NULL;
+ method = c->FindVirtualMethod(name, sig);
+ if (method == NULL) {
+ // No virtual method matching the signature. Search declared
+ // private methods and constructors.
+ method = c->FindDeclaredDirectMethod(name, sig);
}
- return reinterpret_cast<jmethodID>(method);
}
-}
-jobject CallObjectMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ if (method == NULL || method->IsStatic() != is_static) {
+ Thread* self = Thread::Current();
+ std::string class_name(c->GetDescriptor().ToString());
+ // TODO: try searching for the opposite kind of method from is_static
+ // for better diagnostics?
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "no %s method \"%s.%s%s\"", is_static ? "static" : "non-static",
+ class_name.c_str(), name, sig);
+ return NULL;
+ }
-jobject CallObjectMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ bool success = EnsureInvokeStub(method);
+ if (!success) {
+ // TODO: throw OutOfMemoryException
+ return NULL;
+ }
-jobject CallObjectMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return reinterpret_cast<jmethodID>(AddWeakGlobalReference(ts, method));
}
-jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jboolean CallBooleanMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jboolean CallBooleanMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jbyte CallByteMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jbyte CallByteMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jchar CallCharMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jchar CallCharMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jshort CallShortMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jshort CallShortMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint CallIntMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint CallIntMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jlong CallLongMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jlong CallLongMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jfloat CallFloatMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jfloat CallFloatMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jdouble CallDoubleMethodV(JNIEnv* env,
- jobject obj, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jdouble CallDoubleMethodA(JNIEnv* env,
- jobject obj, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void CallVoidMethodV(JNIEnv* env, jobject obj,
- jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void CallVoidMethodA(JNIEnv* env, jobject obj,
- jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jobject CallNonvirtualObjectMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- jobject local_result = AddLocalReference<jobject>(ts, result.l);
- va_end(ap);
- return local_result;
-}
-
-jobject CallNonvirtualObjectMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, args);
- return AddLocalReference<jobject>(ts, result.l);
-}
-
-jobject CallNonvirtualObjectMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- JValue result = InvokeWithJValues(ts, obj, methodID, args);
- return AddLocalReference<jobject>(ts, result.l);
-}
-
-jboolean CallNonvirtualBooleanMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.z;
-}
-
-jboolean CallNonvirtualBooleanMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).z;
-}
-
-jboolean CallNonvirtualBooleanMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).z;
-}
-
-jbyte CallNonvirtualByteMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.b;
-}
-
-jbyte CallNonvirtualByteMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).b;
-}
-
-jbyte CallNonvirtualByteMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).b;
-}
-
-jchar CallNonvirtualCharMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.c;
-}
-
-jchar CallNonvirtualCharMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).c;
-}
-
-jchar CallNonvirtualCharMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).c;
-}
-
-jshort CallNonvirtualShortMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.s;
-}
-
-jshort CallNonvirtualShortMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).s;
-}
-
-jshort CallNonvirtualShortMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).s;
-}
-
-jint CallNonvirtualIntMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.i;
-}
-
-jint CallNonvirtualIntMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).i;
-}
-
-jint CallNonvirtualIntMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).i;
-}
-
-jlong CallNonvirtualLongMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.j;
-}
-
-jlong CallNonvirtualLongMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).j;
-}
-
-jlong CallNonvirtualLongMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).j;
-}
-
-jfloat CallNonvirtualFloatMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.f;
-}
-
-jfloat CallNonvirtualFloatMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).f;
-}
-
-jfloat CallNonvirtualFloatMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).f;
-}
-
-jdouble CallNonvirtualDoubleMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
- return result.d;
-}
-
-jdouble CallNonvirtualDoubleMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, obj, methodID, args).d;
-}
-
-jdouble CallNonvirtualDoubleMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, obj, methodID, args).d;
-}
-
-void CallNonvirtualVoidMethod(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- InvokeWithVarArgs(ts, obj, methodID, ap);
- va_end(ap);
-}
-
-void CallNonvirtualVoidMethodV(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- InvokeWithVarArgs(ts, obj, methodID, args);
-}
-
-void CallNonvirtualVoidMethodA(JNIEnv* env,
- jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- InvokeWithJValues(ts, obj, methodID, args);
-}
-
-jfieldID GetFieldID(JNIEnv* env,
- jclass clazz, const char* name, const char* sig) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jobject GetObjectField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jbyte GetByteField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jchar GetCharField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jshort GetShortField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint GetIntField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jlong GetLongField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jfloat GetFloatField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jdouble GetDoubleField(JNIEnv* env, jobject obj, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-void SetObjectField(JNIEnv* env, jobject obj, jfieldID fieldID, jobject val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetBooleanField(JNIEnv* env, jobject obj, jfieldID fieldID, jboolean val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetByteField(JNIEnv* env, jobject obj, jfieldID fieldID, jbyte val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetCharField(JNIEnv* env, jobject obj, jfieldID fieldID, jchar val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetShortField(JNIEnv* env, jobject obj, jfieldID fieldID, jshort val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetIntField(JNIEnv* env, jobject obj, jfieldID fieldID, jint val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetLongField(JNIEnv* env, jobject obj, jfieldID fieldID, jlong val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetFloatField(JNIEnv* env, jobject obj, jfieldID fieldID, jfloat val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetDoubleField(JNIEnv* env, jobject obj, jfieldID fieldID, jdouble val) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jmethodID GetStaticMethodID(JNIEnv* env,
- jclass clazz, const char* name, const char* sig) {
- ScopedJniThreadState ts(env);
- Class* klass = Decode<Class*>(ts, clazz);
- if (!klass->IsInitialized()) {
+jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
+ Class* c = Decode<Class*>(ts, jni_class);
+ if (!c->IsInitialized()) {
// TODO: initialize the class
}
- Method* method = klass->FindDirectMethod(name, sig);
- if (method == NULL) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- // TODO: may want to FindVirtualMethod to give more informative error
- // message here
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "no method \"%s.%s%s\"",
- class_name.c_str(), name, sig);
- return NULL;
- } else if (!method->IsStatic()) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "method \"%s.%s%s\" is not static",
- class_name.c_str(), name, sig);
- return NULL;
+
+ Field* field = NULL;
+ if (is_static) {
+ field = c->FindStaticField(name, sig);
} else {
- // TODO: create a JNI weak global reference for method
- bool success = EnsureInvokeStub(method);
- if (!success) {
- // TODO: throw OutOfMemoryException
- return NULL;
- }
- return reinterpret_cast<jmethodID>(method);
+ field = c->FindInstanceField(name, sig);
}
-}
-jobject CallStaticObjectMethod(JNIEnv* env,
- jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- jobject local_result = AddLocalReference<jobject>(ts, result.l);
- va_end(ap);
- return local_result;
-}
-
-jobject CallStaticObjectMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, args);
- return AddLocalReference<jobject>(ts, result.l);
-}
-
-jobject CallStaticObjectMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- JValue result = InvokeWithJValues(ts, NULL, methodID, args);
- return AddLocalReference<jobject>(ts, result.l);
-}
-
-jboolean CallStaticBooleanMethod(JNIEnv* env,
- jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.z;
-}
-
-jboolean CallStaticBooleanMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).z;
-}
-
-jboolean CallStaticBooleanMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).z;
-}
-
-jbyte CallStaticByteMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.b;
-}
-
-jbyte CallStaticByteMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).b;
-}
-
-jbyte CallStaticByteMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).b;
-}
-
-jchar CallStaticCharMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.c;
-}
-
-jchar CallStaticCharMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).c;
-}
-
-jchar CallStaticCharMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).c;
-}
-
-jshort CallStaticShortMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.s;
-}
-
-jshort CallStaticShortMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).s;
-}
-
-jshort CallStaticShortMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).s;
-}
-
-jint CallStaticIntMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.i;
-}
-
-jint CallStaticIntMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).i;
-}
-
-jint CallStaticIntMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).i;
-}
-
-jlong CallStaticLongMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.j;
-}
-
-jlong CallStaticLongMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).j;
-}
-
-jlong CallStaticLongMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).j;
-}
-
-jfloat CallStaticFloatMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.f;
-}
-
-jfloat CallStaticFloatMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).f;
-}
-
-jfloat CallStaticFloatMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).f;
-}
-
-jdouble CallStaticDoubleMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
- return result.d;
-}
-
-jdouble CallStaticDoubleMethodV(JNIEnv* env,
- jclass clazz, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts, NULL, methodID, args).d;
-}
-
-jdouble CallStaticDoubleMethodA(JNIEnv* env,
- jclass clazz, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts, NULL, methodID, args).d;
-}
-
-void CallStaticVoidMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
- ScopedJniThreadState ts(env);
- va_list ap;
- va_start(ap, methodID);
- InvokeWithVarArgs(ts, NULL, methodID, ap);
- va_end(ap);
-}
-
-void CallStaticVoidMethodV(JNIEnv* env,
- jclass cls, jmethodID methodID, va_list args) {
- ScopedJniThreadState ts(env);
- InvokeWithVarArgs(ts, NULL, methodID, args);
-}
-
-void CallStaticVoidMethodA(JNIEnv* env,
- jclass cls, jmethodID methodID, jvalue* args) {
- ScopedJniThreadState ts(env);
- InvokeWithJValues(ts, NULL, methodID, args);
-}
-
-jfieldID GetStaticFieldID(JNIEnv* env,
- jclass clazz, const char* name, const char* sig) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jobject GetStaticObjectField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jboolean GetStaticBooleanField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
-}
-
-jbyte GetStaticByteField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jchar GetStaticCharField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jshort GetStaticShortField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint GetStaticIntField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jlong GetStaticLongField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jfloat GetStaticFloatField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jdouble GetStaticDoubleField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-void SetStaticObjectField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jobject value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticBooleanField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jboolean value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticByteField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jbyte value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticCharField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jchar value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticShortField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jshort value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticIntField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jint value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticLongField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jlong value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticFloatField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jfloat value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetStaticDoubleField(JNIEnv* env,
- jclass clazz, jfieldID fieldID, jdouble value) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jstring NewString(JNIEnv* env, const jchar* unicode, jsize len) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jsize GetStringLength(JNIEnv* env, jstring str) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-const jchar* GetStringChars(JNIEnv* env, jstring str, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-void ReleaseStringChars(JNIEnv* env, jstring str, const jchar* chars) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jstring NewStringUTF(JNIEnv* env, const char* utf) {
- ScopedJniThreadState ts(env);
- if (utf == NULL) {
+ if (field == NULL) {
+ Thread* self = Thread::Current();
+ std::string class_name(c->GetDescriptor().ToString());
+ self->ThrowNewException("Ljava/lang/NoSuchFieldError;",
+ "no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
+ name, class_name.c_str());
return NULL;
}
- String* result = String::AllocFromModifiedUtf8(utf);
- return AddLocalReference<jstring>(ts, result);
-}
-jsize GetStringUTFLength(JNIEnv* env, jstring str) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-const char* GetStringUTFChars(JNIEnv* env, jstring str, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-void ReleaseStringUTFChars(JNIEnv* env, jstring str, const char* chars) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jsize GetArrayLength(JNIEnv* env, jarray array) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-void SetObjectArrayElement(JNIEnv* env,
- jobjectArray java_array, jsize index, jobject java_value) {
- ScopedJniThreadState ts(env);
- ObjectArray<Object>* array = Decode<ObjectArray<Object>*>(ts, java_array);
- Object* value = Decode<Object*>(ts, java_value);
- array->Set(index, value);
+ jweak fid = AddWeakGlobalReference(ts, field);
+ return reinterpret_cast<jfieldID>(fid);
}
template<typename JniT, typename ArtT>
@@ -1855,633 +518,1835 @@
return AddLocalReference<JniT>(ts, result);
}
-jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jbooleanArray, BooleanArray>(ts, length);
-}
+} // namespace
-jbyteArray NewByteArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jbyteArray, ByteArray>(ts, length);
-}
+class JNI {
+ public:
-jcharArray NewCharArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jcharArray, CharArray>(ts, length);
-}
+ static jint GetVersion(JNIEnv* env) {
+ ScopedJniThreadState ts(env);
+ return JNI_VERSION_1_6;
+ }
-jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jdoubleArray, DoubleArray>(ts, length);
-}
-
-jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jfloatArray, FloatArray>(ts, length);
-}
-
-jintArray NewIntArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jintArray, IntArray>(ts, length);
-}
-
-jlongArray NewLongArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jlongArray, LongArray>(ts, length);
-}
-
-jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass, jobject initial_element) {
- ScopedJniThreadState ts(env);
- CHECK_GE(length, 0); // TODO: ReportJniError
-
- // Compute the array class corresponding to the given element class.
- Class* element_class = Decode<Class*>(ts, element_jclass);
- std::string descriptor;
- descriptor += "[";
- descriptor += element_class->GetDescriptor().ToString();
-
- // Find the class.
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- // TODO: need to get the appropriate ClassLoader.
- Class* array_class = class_linker->FindClass(descriptor, NULL);
- if (array_class == NULL) {
+ static jclass DefineClass(JNIEnv* env, const char*, jobject, const jbyte*, jsize) {
+ ScopedJniThreadState ts(env);
+ LOG(WARNING) << "JNI DefineClass is not supported";
return NULL;
}
- ObjectArray<Object>* result = ObjectArray<Object>::Alloc(array_class, length);
- CHECK(initial_element == NULL); // TODO: support initial_element
- return AddLocalReference<jobjectArray>(ts, result);
-}
-
-jshortArray NewShortArray(JNIEnv* env, jsize length) {
- ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jshortArray, ShortArray>(ts, length);
-}
-
-jboolean* GetBooleanArrayElements(JNIEnv* env,
- jbooleanArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jshort* GetShortArrayElements(JNIEnv* env,
- jshortArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jfloat* GetFloatArrayElements(JNIEnv* env,
- jfloatArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jdouble* GetDoubleArrayElements(JNIEnv* env,
- jdoubleArray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-void ReleaseBooleanArrayElements(JNIEnv* env,
- jbooleanArray array, jboolean* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseByteArrayElements(JNIEnv* env,
- jbyteArray array, jbyte* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseCharArrayElements(JNIEnv* env,
- jcharArray array, jchar* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseShortArrayElements(JNIEnv* env,
- jshortArray array, jshort* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseIntArrayElements(JNIEnv* env,
- jintArray array, jint* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseLongArrayElements(JNIEnv* env,
- jlongArray array, jlong* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseFloatArrayElements(JNIEnv* env,
- jfloatArray array, jfloat* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void ReleaseDoubleArrayElements(JNIEnv* env,
- jdoubleArray array, jdouble* elems, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetBooleanArrayRegion(JNIEnv* env,
- jbooleanArray array, jsize start, jsize l, jboolean* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetByteArrayRegion(JNIEnv* env,
- jbyteArray array, jsize start, jsize len, jbyte* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetCharArrayRegion(JNIEnv* env,
- jcharArray array, jsize start, jsize len, jchar* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetShortArrayRegion(JNIEnv* env,
- jshortArray array, jsize start, jsize len, jshort* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetIntArrayRegion(JNIEnv* env,
- jintArray array, jsize start, jsize len, jint* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetLongArrayRegion(JNIEnv* env,
- jlongArray array, jsize start, jsize len, jlong* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetFloatArrayRegion(JNIEnv* env,
- jfloatArray array, jsize start, jsize len, jfloat* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void GetDoubleArrayRegion(JNIEnv* env,
- jdoubleArray array, jsize start, jsize len, jdouble* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetBooleanArrayRegion(JNIEnv* env,
- jbooleanArray array, jsize start, jsize l, const jboolean* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetByteArrayRegion(JNIEnv* env,
- jbyteArray array, jsize start, jsize len, const jbyte* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetCharArrayRegion(JNIEnv* env,
- jcharArray array, jsize start, jsize len, const jchar* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetShortArrayRegion(JNIEnv* env,
- jshortArray array, jsize start, jsize len, const jshort* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetIntArrayRegion(JNIEnv* env,
- jintArray array, jsize start, jsize len, const jint* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetLongArrayRegion(JNIEnv* env,
- jlongArray array, jsize start, jsize len, const jlong* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetFloatArrayRegion(JNIEnv* env,
- jfloatArray array, jsize start, jsize len, const jfloat* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-void SetDoubleArrayRegion(JNIEnv* env,
- jdoubleArray array, jsize start, jsize len, const jdouble* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
-
-jint RegisterNatives(JNIEnv* env,
- jclass clazz, const JNINativeMethod* methods, jint nMethods) {
- ScopedJniThreadState ts(env);
- Class* klass = Decode<Class*>(ts, clazz);
- for(int i = 0; i < nMethods; i++) {
- const char* name = methods[i].name;
- const char* sig = methods[i].signature;
-
- if (*sig == '!') {
- // TODO: fast jni. it's too noisy to log all these.
- ++sig;
- }
-
- Method* method = klass->FindDirectMethod(name, sig);
- if (method == NULL) {
- method = klass->FindVirtualMethod(name, sig);
- }
- if (method == NULL) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "no method \"%s.%s%s\"",
- class_name.c_str(), name, sig);
- return JNI_ERR;
- } else if (!method->IsNative()) {
- Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
- // TODO: pretty print method names through a single routine
- self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
- "method \"%s.%s%s\" is not native",
- class_name.c_str(), name, sig);
- return JNI_ERR;
- }
- method->RegisterNative(methods[i].fnPtr);
+ static jclass FindClass(JNIEnv* env, const char* name) {
+ ScopedJniThreadState ts(env);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ std::string descriptor(NormalizeJniClassDescriptor(name));
+ // TODO: need to get the appropriate ClassLoader.
+ Class* c = class_linker->FindClass(descriptor, NULL);
+ return AddLocalReference<jclass>(ts, c);
}
- return JNI_OK;
-}
-jint UnregisterNatives(JNIEnv* env, jclass clazz) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
-
-jint MonitorEnter(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING);
- return 0;
-}
-
-jint MonitorExit(JNIEnv* env, jobject obj) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING);
- return 0;
-}
-
-jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
- ScopedJniThreadState ts(env);
- Runtime* runtime = Runtime::Current();
- if (runtime != NULL) {
- *vm = reinterpret_cast<JavaVM*>(runtime->GetJavaVM());
- } else {
- *vm = NULL;
+ static jmethodID FromReflectedMethod(JNIEnv* env, jobject java_method) {
+ ScopedJniThreadState ts(env);
+ Method* method = Decode<Method*>(ts, java_method);
+ return reinterpret_cast<jmethodID>(AddWeakGlobalReference(ts, method));
}
- return (*vm != NULL) ? JNI_OK : JNI_ERR;
-}
-void GetStringRegion(JNIEnv* env,
- jstring str, jsize start, jsize len, jchar* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
+ static jfieldID FromReflectedField(JNIEnv* env, jobject java_field) {
+ ScopedJniThreadState ts(env);
+ Field* field = Decode<Field*>(ts, java_field);
+ return reinterpret_cast<jfieldID>(AddWeakGlobalReference(ts, field));
+ }
-void GetStringUTFRegion(JNIEnv* env,
- jstring str, jsize start, jsize len, char* buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
+ static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) {
+ ScopedJniThreadState ts(env);
+ Method* method = DecodeMethod(ts, mid);
+ return AddLocalReference<jobject>(ts, method);
+ }
-void* GetPrimitiveArrayCritical(JNIEnv* env,
- jarray array, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
+ ScopedJniThreadState ts(env);
+ Field* field = DecodeField(ts, fid);
+ return AddLocalReference<jobject>(ts, field);
+ }
-void ReleasePrimitiveArrayCritical(JNIEnv* env,
- jarray array, void* carray, jint mode) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
+ static jclass GetSuperclass(JNIEnv* env, jclass sub) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
-const jchar* GetStringCritical(JNIEnv* env, jstring s, jboolean* isCopy) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ static jboolean IsAssignableFrom(JNIEnv* env, jclass sub, jclass sup) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
-void ReleaseStringCritical(JNIEnv* env, jstring s, const jchar* cstr) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
-}
+ static jint Throw(JNIEnv* env, jthrowable obj) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
-jboolean ExceptionCheck(JNIEnv* env) {
- ScopedJniThreadState ts(env);
- return ts.Self()->IsExceptionPending() ? JNI_TRUE : JNI_FALSE;
-}
+ static jint ThrowNew(JNIEnv* env, jclass clazz, const char* msg) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
-jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ static jthrowable ExceptionOccurred(JNIEnv* env) {
+ ScopedJniThreadState ts(env);
+ Object* exception = ts.Self()->GetException();
+ if (exception == NULL) {
+ return NULL;
+ } else {
+ // TODO: if adding a local reference failing causes the VM to abort
+ // then the following check will never occur.
+ jthrowable localException = AddLocalReference<jthrowable>(ts, exception);
+ if (localException == NULL) {
+ // We were unable to add a new local reference, and threw a new
+ // exception. We can't return "exception", because it's not a
+ // local reference. So we have to return NULL, indicating that
+ // there was no exception, even though it's pretty much raining
+ // exceptions in here.
+ LOG(WARNING) << "JNI WARNING: addLocal/exception combo";
+ }
+ return localException;
+ }
+ }
+
+ static void ExceptionDescribe(JNIEnv* env) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ExceptionClear(JNIEnv* env) {
+ ScopedJniThreadState ts(env);
+ ts.Self()->ClearException();
+ }
+
+ static void FatalError(JNIEnv* env, const char* msg) {
+ ScopedJniThreadState ts(env);
+ LOG(FATAL) << "JNI FatalError called: " << msg;
+ }
+
+ static jint PushLocalFrame(JNIEnv* env, jint cap) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(WARNING) << "ignoring PushLocalFrame(" << cap << ")";
+ return JNI_OK;
+ }
+
+ static jobject PopLocalFrame(JNIEnv* env, jobject res) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(WARNING) << "ignoring PopLocalFrame " << res;
+ return res;
+ }
+
+ static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& globals = vm->globals;
+ MutexLock mu(vm->globals_lock);
+ IndirectRef ref = globals.Add(IRT_FIRST_SEGMENT, Decode<Object*>(ts, obj));
+ return reinterpret_cast<jobject>(ref);
+ }
+
+ static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ if (obj == NULL) {
+ return;
+ }
+
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& globals = vm->globals;
+ MutexLock mu(vm->globals_lock);
+
+ if (!globals.Remove(IRT_FIRST_SEGMENT, obj)) {
+ LOG(WARNING) << "JNI WARNING: DeleteGlobalRef(" << obj << ") "
+ << "failed to find entry";
+ }
+ }
+
+ static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ return AddWeakGlobalReference(ts, Decode<Object*>(ts, obj));
+ }
+
+ static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
+ ScopedJniThreadState ts(env);
+ if (obj == NULL) {
+ return;
+ }
+
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& weak_globals = vm->weak_globals;
+ MutexLock mu(vm->weak_globals_lock);
+
+ if (!weak_globals.Remove(IRT_FIRST_SEGMENT, obj)) {
+ LOG(WARNING) << "JNI WARNING: DeleteWeakGlobalRef(" << obj << ") "
+ << "failed to find entry";
+ }
+ }
+
+ static jobject NewLocalRef(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ IndirectReferenceTable& locals = ts.Env()->locals;
+
+ uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
+ IndirectRef ref = locals.Add(cookie, Decode<Object*>(ts, obj));
+ return reinterpret_cast<jobject>(ref);
+ }
+
+ static void DeleteLocalRef(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ if (obj == NULL) {
+ return;
+ }
+
+ IndirectReferenceTable& locals = ts.Env()->locals;
+
+ uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
+ if (!locals.Remove(cookie, obj)) {
+ // Attempting to delete a local reference that is not in the
+ // topmost local reference frame is a no-op. DeleteLocalRef returns
+ // void and doesn't throw any exceptions, but we should probably
+ // complain about it so the user will notice that things aren't
+ // going quite the way they expect.
+ LOG(WARNING) << "JNI WARNING: DeleteLocalRef(" << obj << ") "
+ << "failed to find entry";
+ }
+ }
+
+ static jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) {
+ ScopedJniThreadState ts(env);
+ return (Decode<Object*>(ts, obj1) == Decode<Object*>(ts, obj2))
+ ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jint EnsureLocalCapacity(JNIEnv* env, jint) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jobject AllocObject(JNIEnv* env, jclass clazz) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list args;
+ va_start(args, methodID);
+ jobject result = NewObjectV(env, clazz, methodID, args);
+ va_end(args);
+ return result;
+ }
+
+ static jobject NewObjectV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ Class* klass = Decode<Class*>(ts, clazz);
+ Object* result = klass->NewInstance();
+ jobject local_result = AddLocalReference<jobject>(ts, result);
+ CallNonvirtualVoidMethodV(env, local_result, clazz, methodID, args);
+ return local_result;
+ }
+
+ static jobject NewObjectA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ Class* klass = Decode<Class*>(ts, clazz);
+ Object* result = klass->NewInstance();
+ jobject local_result = AddLocalReference<jobjectArray>(ts, result);
+ CallNonvirtualVoidMethodA(env, local_result, clazz, methodID, args);
+ return local_result;
+ }
+
+ static jclass GetObjectClass(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass clazz) {
+ ScopedJniThreadState ts(env);
+ CHECK_NE(static_cast<jclass>(NULL), clazz);
+ if (jobj == NULL) {
+ // NB. JNI is different from regular Java instanceof in this respect
+ return JNI_TRUE;
+ } else {
+ Object* obj = Decode<Object*>(ts, jobj);
+ Class* klass = Decode<Class*>(ts, clazz);
+ return Object::InstanceOf(obj, klass) ? JNI_TRUE : JNI_FALSE;
+ }
+ }
+
+ static jmethodID GetMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
+ ScopedJniThreadState ts(env);
+ return FindMethodID(ts, c, name, sig, false);
+ }
+
+ static jmethodID GetStaticMethodID(JNIEnv* env, jclass c, const char* name, const char* sig) {
+ ScopedJniThreadState ts(env);
+ return FindMethodID(ts, c, name, sig, true);
+ }
+
+ static jobject CallObjectMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jobject CallObjectMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jobject CallObjectMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
+
+ static jboolean CallBooleanMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
+
+ static jboolean CallBooleanMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
+
+ static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jbyte CallByteMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jbyte CallByteMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jchar CallCharMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jchar CallCharMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jshort CallShortMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jshort CallShortMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint CallIntMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint CallIntMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jlong CallLongMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jlong CallLongMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jfloat CallFloatMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jfloat CallFloatMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jdouble CallDoubleMethodV(JNIEnv* env,
+ jobject obj, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jdouble CallDoubleMethodA(JNIEnv* env,
+ jobject obj, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void CallVoidMethodV(JNIEnv* env, jobject obj,
+ jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void CallVoidMethodA(JNIEnv* env, jobject obj,
+ jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jobject CallNonvirtualObjectMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ va_end(ap);
+ return local_result;
+ }
+
+ static jobject CallNonvirtualObjectMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
+ }
+
+ static jobject CallNonvirtualObjectMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ JValue result = InvokeWithJValues(ts, obj, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
+ }
+
+ static jboolean CallNonvirtualBooleanMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.z;
+ }
+
+ static jboolean CallNonvirtualBooleanMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).z;
+ }
+
+ static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).z;
+ }
+
+ static jbyte CallNonvirtualByteMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.b;
+ }
+
+ static jbyte CallNonvirtualByteMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).b;
+ }
+
+ static jbyte CallNonvirtualByteMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).b;
+ }
+
+ static jchar CallNonvirtualCharMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.c;
+ }
+
+ static jchar CallNonvirtualCharMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).c;
+ }
+
+ static jchar CallNonvirtualCharMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).c;
+ }
+
+ static jshort CallNonvirtualShortMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.s;
+ }
+
+ static jshort CallNonvirtualShortMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).s;
+ }
+
+ static jshort CallNonvirtualShortMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).s;
+ }
+
+ static jint CallNonvirtualIntMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.i;
+ }
+
+ static jint CallNonvirtualIntMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).i;
+ }
+
+ static jint CallNonvirtualIntMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).i;
+ }
+
+ static jlong CallNonvirtualLongMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.j;
+ }
+
+ static jlong CallNonvirtualLongMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).j;
+ }
+
+ static jlong CallNonvirtualLongMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).j;
+ }
+
+ static jfloat CallNonvirtualFloatMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.f;
+ }
+
+ static jfloat CallNonvirtualFloatMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).f;
+ }
+
+ static jfloat CallNonvirtualFloatMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).f;
+ }
+
+ static jdouble CallNonvirtualDoubleMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.d;
+ }
+
+ static jdouble CallNonvirtualDoubleMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, obj, methodID, args).d;
+ }
+
+ static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, obj, methodID, args).d;
+ }
+
+ static void CallNonvirtualVoidMethod(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ }
+
+ static void CallNonvirtualVoidMethodV(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ InvokeWithVarArgs(ts, obj, methodID, args);
+ }
+
+ static void CallNonvirtualVoidMethodA(JNIEnv* env,
+ jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ InvokeWithJValues(ts, obj, methodID, args);
+ }
+
+ static jfieldID GetFieldID(JNIEnv* env,
+ jclass c, const char* name, const char* sig) {
+ ScopedJniThreadState ts(env);
+ return FindFieldID(ts, c, name, sig, false);
+ }
-void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
+ static jfieldID GetStaticFieldID(JNIEnv* env,
+ jclass c, const char* name, const char* sig) {
+ ScopedJniThreadState ts(env);
+ return FindFieldID(ts, c, name, sig, true);
+ }
-jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
-}
+ static jobject GetObjectField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
-jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNIInvalidRefType;
-}
+ static jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
+
+ static jbyte GetByteField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jchar GetCharField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jshort GetShortField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint GetIntField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jlong GetLongField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jfloat GetFloatField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jdouble GetDoubleField(JNIEnv* env, jobject obj, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static void SetObjectField(JNIEnv* env, jobject obj, jfieldID fieldID, jobject val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetBooleanField(JNIEnv* env, jobject obj, jfieldID fieldID, jboolean val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetByteField(JNIEnv* env, jobject obj, jfieldID fieldID, jbyte val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetCharField(JNIEnv* env, jobject obj, jfieldID fieldID, jchar val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetShortField(JNIEnv* env, jobject obj, jfieldID fieldID, jshort val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetIntField(JNIEnv* env, jobject obj, jfieldID fieldID, jint val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetLongField(JNIEnv* env, jobject obj, jfieldID fieldID, jlong val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetFloatField(JNIEnv* env, jobject obj, jfieldID fieldID, jfloat val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetDoubleField(JNIEnv* env, jobject obj, jfieldID fieldID, jdouble val) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jobject CallStaticObjectMethod(JNIEnv* env,
+ jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ va_end(ap);
+ return local_result;
+ }
+
+ static jobject CallStaticObjectMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
+ }
+
+ static jobject CallStaticObjectMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ JValue result = InvokeWithJValues(ts, NULL, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
+ }
+
+ static jboolean CallStaticBooleanMethod(JNIEnv* env,
+ jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.z;
+ }
+
+ static jboolean CallStaticBooleanMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).z;
+ }
+
+ static jboolean CallStaticBooleanMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).z;
+ }
+
+ static jbyte CallStaticByteMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.b;
+ }
+
+ static jbyte CallStaticByteMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).b;
+ }
+
+ static jbyte CallStaticByteMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).b;
+ }
+
+ static jchar CallStaticCharMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.c;
+ }
+
+ static jchar CallStaticCharMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).c;
+ }
+
+ static jchar CallStaticCharMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).c;
+ }
+
+ static jshort CallStaticShortMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.s;
+ }
+
+ static jshort CallStaticShortMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).s;
+ }
+
+ static jshort CallStaticShortMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).s;
+ }
+
+ static jint CallStaticIntMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.i;
+ }
+
+ static jint CallStaticIntMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).i;
+ }
+
+ static jint CallStaticIntMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).i;
+ }
+
+ static jlong CallStaticLongMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.j;
+ }
+
+ static jlong CallStaticLongMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).j;
+ }
+
+ static jlong CallStaticLongMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).j;
+ }
+
+ static jfloat CallStaticFloatMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.f;
+ }
+
+ static jfloat CallStaticFloatMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).f;
+ }
+
+ static jfloat CallStaticFloatMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).f;
+ }
+
+ static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.d;
+ }
+
+ static jdouble CallStaticDoubleMethodV(JNIEnv* env,
+ jclass clazz, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithVarArgs(ts, NULL, methodID, args).d;
+ }
+
+ static jdouble CallStaticDoubleMethodA(JNIEnv* env,
+ jclass clazz, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ return InvokeWithJValues(ts, NULL, methodID, args).d;
+ }
+
+ static void CallStaticVoidMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
+ ScopedJniThreadState ts(env);
+ va_list ap;
+ va_start(ap, methodID);
+ InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ }
+
+ static void CallStaticVoidMethodV(JNIEnv* env,
+ jclass cls, jmethodID methodID, va_list args) {
+ ScopedJniThreadState ts(env);
+ InvokeWithVarArgs(ts, NULL, methodID, args);
+ }
+
+ static void CallStaticVoidMethodA(JNIEnv* env,
+ jclass cls, jmethodID methodID, jvalue* args) {
+ ScopedJniThreadState ts(env);
+ InvokeWithJValues(ts, NULL, methodID, args);
+ }
+
+ static jobject GetStaticObjectField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jboolean GetStaticBooleanField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNI_FALSE;
+ }
+
+ static jbyte GetStaticByteField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jchar GetStaticCharField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jshort GetStaticShortField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint GetStaticIntField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jlong GetStaticLongField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jfloat GetStaticFloatField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jdouble GetStaticDoubleField(JNIEnv* env, jclass clazz, jfieldID fieldID) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static void SetStaticObjectField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jobject value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticBooleanField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jboolean value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticByteField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jbyte value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticCharField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jchar value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticShortField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jshort value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticIntField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jint value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticLongField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jlong value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticFloatField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jfloat value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetStaticDoubleField(JNIEnv* env,
+ jclass clazz, jfieldID fieldID, jdouble value) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jstring NewString(JNIEnv* env, const jchar* unicode, jsize len) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jsize GetStringLength(JNIEnv* env, jstring str) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static const jchar* GetStringChars(JNIEnv* env, jstring str, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleaseStringChars(JNIEnv* env, jstring str, const jchar* chars) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jstring NewStringUTF(JNIEnv* env, const char* utf) {
+ ScopedJniThreadState ts(env);
+ if (utf == NULL) {
+ return NULL;
+ }
+ String* result = String::AllocFromModifiedUtf8(utf);
+ return AddLocalReference<jstring>(ts, result);
+ }
+
+ static jsize GetStringUTFLength(JNIEnv* env, jstring str) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static const char* GetStringUTFChars(JNIEnv* env, jstring str, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleaseStringUTFChars(JNIEnv* env, jstring str, const char* chars) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jsize GetArrayLength(JNIEnv* env, jarray array) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void SetObjectArrayElement(JNIEnv* env,
+ jobjectArray java_array, jsize index, jobject java_value) {
+ ScopedJniThreadState ts(env);
+ ObjectArray<Object>* array = Decode<ObjectArray<Object>*>(ts, java_array);
+ Object* value = Decode<Object*>(ts, java_value);
+ array->Set(index, value);
+ }
+
+ static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jbooleanArray, BooleanArray>(ts, length);
+ }
+
+ static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jbyteArray, ByteArray>(ts, length);
+ }
+
+ static jcharArray NewCharArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jcharArray, CharArray>(ts, length);
+ }
+
+ static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jdoubleArray, DoubleArray>(ts, length);
+ }
+
+ static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jfloatArray, FloatArray>(ts, length);
+ }
+
+ static jintArray NewIntArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jintArray, IntArray>(ts, length);
+ }
+
+ static jlongArray NewLongArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jlongArray, LongArray>(ts, length);
+ }
+
+ static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass, jobject initial_element) {
+ ScopedJniThreadState ts(env);
+ CHECK_GE(length, 0); // TODO: ReportJniError
+
+ // Compute the array class corresponding to the given element class.
+ Class* element_class = Decode<Class*>(ts, element_jclass);
+ std::string descriptor;
+ descriptor += "[";
+ descriptor += element_class->GetDescriptor().ToString();
+
+ // Find the class.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ // TODO: need to get the appropriate ClassLoader.
+ Class* array_class = class_linker->FindClass(descriptor, NULL);
+ if (array_class == NULL) {
+ return NULL;
+ }
+
+ ObjectArray<Object>* result = ObjectArray<Object>::Alloc(array_class, length);
+ CHECK(initial_element == NULL); // TODO: support initial_element
+ return AddLocalReference<jobjectArray>(ts, result);
+ }
+
+ static jshortArray NewShortArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jshortArray, ShortArray>(ts, length);
+ }
+
+ static jboolean* GetBooleanArrayElements(JNIEnv* env,
+ jbooleanArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jshort* GetShortArrayElements(JNIEnv* env,
+ jshortArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jfloat* GetFloatArrayElements(JNIEnv* env,
+ jfloatArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jdouble* GetDoubleArrayElements(JNIEnv* env,
+ jdoubleArray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleaseBooleanArrayElements(JNIEnv* env,
+ jbooleanArray array, jboolean* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseByteArrayElements(JNIEnv* env,
+ jbyteArray array, jbyte* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseCharArrayElements(JNIEnv* env,
+ jcharArray array, jchar* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseShortArrayElements(JNIEnv* env,
+ jshortArray array, jshort* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseIntArrayElements(JNIEnv* env,
+ jintArray array, jint* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseLongArrayElements(JNIEnv* env,
+ jlongArray array, jlong* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseFloatArrayElements(JNIEnv* env,
+ jfloatArray array, jfloat* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void ReleaseDoubleArrayElements(JNIEnv* env,
+ jdoubleArray array, jdouble* elems, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetBooleanArrayRegion(JNIEnv* env,
+ jbooleanArray array, jsize start, jsize l, jboolean* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetByteArrayRegion(JNIEnv* env,
+ jbyteArray array, jsize start, jsize len, jbyte* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetCharArrayRegion(JNIEnv* env,
+ jcharArray array, jsize start, jsize len, jchar* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetShortArrayRegion(JNIEnv* env,
+ jshortArray array, jsize start, jsize len, jshort* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetIntArrayRegion(JNIEnv* env,
+ jintArray array, jsize start, jsize len, jint* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetLongArrayRegion(JNIEnv* env,
+ jlongArray array, jsize start, jsize len, jlong* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetFloatArrayRegion(JNIEnv* env,
+ jfloatArray array, jsize start, jsize len, jfloat* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetDoubleArrayRegion(JNIEnv* env,
+ jdoubleArray array, jsize start, jsize len, jdouble* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetBooleanArrayRegion(JNIEnv* env,
+ jbooleanArray array, jsize start, jsize l, const jboolean* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetByteArrayRegion(JNIEnv* env,
+ jbyteArray array, jsize start, jsize len, const jbyte* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetCharArrayRegion(JNIEnv* env,
+ jcharArray array, jsize start, jsize len, const jchar* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetShortArrayRegion(JNIEnv* env,
+ jshortArray array, jsize start, jsize len, const jshort* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetIntArrayRegion(JNIEnv* env,
+ jintArray array, jsize start, jsize len, const jint* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetLongArrayRegion(JNIEnv* env,
+ jlongArray array, jsize start, jsize len, const jlong* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetFloatArrayRegion(JNIEnv* env,
+ jfloatArray array, jsize start, jsize len, const jfloat* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void SetDoubleArrayRegion(JNIEnv* env,
+ jdoubleArray array, jsize start, jsize len, const jdouble* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jint RegisterNatives(JNIEnv* env,
+ jclass clazz, const JNINativeMethod* methods, jint nMethods) {
+ ScopedJniThreadState ts(env);
+ Class* klass = Decode<Class*>(ts, clazz);
+ for(int i = 0; i < nMethods; i++) {
+ const char* name = methods[i].name;
+ const char* sig = methods[i].signature;
+
+ if (*sig == '!') {
+ // TODO: fast jni. it's too noisy to log all these.
+ ++sig;
+ }
+
+ Method* method = klass->FindDirectMethod(name, sig);
+ if (method == NULL) {
+ method = klass->FindVirtualMethod(name, sig);
+ }
+ if (method == NULL) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "no method \"%s.%s%s\"",
+ class_name.c_str(), name, sig);
+ return JNI_ERR;
+ } else if (!method->IsNative()) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "method \"%s.%s%s\" is not native",
+ class_name.c_str(), name, sig);
+ return JNI_ERR;
+ }
+ method->RegisterNative(methods[i].fnPtr);
+ }
+ return JNI_OK;
+ }
+
+ static jint UnregisterNatives(JNIEnv* env, jclass clazz) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jint MonitorEnter(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(WARNING);
+ return 0;
+ }
+
+ static jint MonitorExit(JNIEnv* env, jobject obj) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(WARNING);
+ return 0;
+ }
+
+ static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
+ ScopedJniThreadState ts(env);
+ Runtime* runtime = Runtime::Current();
+ if (runtime != NULL) {
+ *vm = reinterpret_cast<JavaVM*>(runtime->GetJavaVM());
+ } else {
+ *vm = NULL;
+ }
+ return (*vm != NULL) ? JNI_OK : JNI_ERR;
+ }
+
+ static void GetStringRegion(JNIEnv* env,
+ jstring str, jsize start, jsize len, jchar* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void GetStringUTFRegion(JNIEnv* env,
+ jstring str, jsize start, jsize len, char* buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static void* GetPrimitiveArrayCritical(JNIEnv* env,
+ jarray array, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleasePrimitiveArrayCritical(JNIEnv* env,
+ jarray array, void* carray, jint mode) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static const jchar* GetStringCritical(JNIEnv* env, jstring s, jboolean* isCopy) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void ReleaseStringCritical(JNIEnv* env, jstring s, const jchar* cstr) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ }
+
+ static jboolean ExceptionCheck(JNIEnv* env) {
+ ScopedJniThreadState ts(env);
+ return ts.Self()->IsExceptionPending() ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
+ static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return 0;
+ }
+
+ static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
+ ScopedJniThreadState ts(env);
+ UNIMPLEMENTED(FATAL);
+ return JNIInvalidRefType;
+ }
+};
static const struct JNINativeInterface gNativeInterface = {
NULL, // reserved0.
NULL, // reserved1.
NULL, // reserved2.
NULL, // reserved3.
- GetVersion,
- DefineClass,
- FindClass,
- FromReflectedMethod,
- FromReflectedField,
- ToReflectedMethod,
- GetSuperclass,
- IsAssignableFrom,
- ToReflectedField,
- Throw,
- ThrowNew,
- ExceptionOccurred,
- ExceptionDescribe,
- ExceptionClear,
- FatalError,
- PushLocalFrame,
- PopLocalFrame,
- NewGlobalRef,
- DeleteGlobalRef,
- DeleteLocalRef,
- IsSameObject,
- NewLocalRef,
- EnsureLocalCapacity,
- AllocObject,
- NewObject,
- NewObjectV,
- NewObjectA,
- GetObjectClass,
- IsInstanceOf,
- GetMethodID,
- CallObjectMethod,
- CallObjectMethodV,
- CallObjectMethodA,
- CallBooleanMethod,
- CallBooleanMethodV,
- CallBooleanMethodA,
- CallByteMethod,
- CallByteMethodV,
- CallByteMethodA,
- CallCharMethod,
- CallCharMethodV,
- CallCharMethodA,
- CallShortMethod,
- CallShortMethodV,
- CallShortMethodA,
- CallIntMethod,
- CallIntMethodV,
- CallIntMethodA,
- CallLongMethod,
- CallLongMethodV,
- CallLongMethodA,
- CallFloatMethod,
- CallFloatMethodV,
- CallFloatMethodA,
- CallDoubleMethod,
- CallDoubleMethodV,
- CallDoubleMethodA,
- CallVoidMethod,
- CallVoidMethodV,
- CallVoidMethodA,
- CallNonvirtualObjectMethod,
- CallNonvirtualObjectMethodV,
- CallNonvirtualObjectMethodA,
- CallNonvirtualBooleanMethod,
- CallNonvirtualBooleanMethodV,
- CallNonvirtualBooleanMethodA,
- CallNonvirtualByteMethod,
- CallNonvirtualByteMethodV,
- CallNonvirtualByteMethodA,
- CallNonvirtualCharMethod,
- CallNonvirtualCharMethodV,
- CallNonvirtualCharMethodA,
- CallNonvirtualShortMethod,
- CallNonvirtualShortMethodV,
- CallNonvirtualShortMethodA,
- CallNonvirtualIntMethod,
- CallNonvirtualIntMethodV,
- CallNonvirtualIntMethodA,
- CallNonvirtualLongMethod,
- CallNonvirtualLongMethodV,
- CallNonvirtualLongMethodA,
- CallNonvirtualFloatMethod,
- CallNonvirtualFloatMethodV,
- CallNonvirtualFloatMethodA,
- CallNonvirtualDoubleMethod,
- CallNonvirtualDoubleMethodV,
- CallNonvirtualDoubleMethodA,
- CallNonvirtualVoidMethod,
- CallNonvirtualVoidMethodV,
- CallNonvirtualVoidMethodA,
- GetFieldID,
- GetObjectField,
- GetBooleanField,
- GetByteField,
- GetCharField,
- GetShortField,
- GetIntField,
- GetLongField,
- GetFloatField,
- GetDoubleField,
- SetObjectField,
- SetBooleanField,
- SetByteField,
- SetCharField,
- SetShortField,
- SetIntField,
- SetLongField,
- SetFloatField,
- SetDoubleField,
- GetStaticMethodID,
- CallStaticObjectMethod,
- CallStaticObjectMethodV,
- CallStaticObjectMethodA,
- CallStaticBooleanMethod,
- CallStaticBooleanMethodV,
- CallStaticBooleanMethodA,
- CallStaticByteMethod,
- CallStaticByteMethodV,
- CallStaticByteMethodA,
- CallStaticCharMethod,
- CallStaticCharMethodV,
- CallStaticCharMethodA,
- CallStaticShortMethod,
- CallStaticShortMethodV,
- CallStaticShortMethodA,
- CallStaticIntMethod,
- CallStaticIntMethodV,
- CallStaticIntMethodA,
- CallStaticLongMethod,
- CallStaticLongMethodV,
- CallStaticLongMethodA,
- CallStaticFloatMethod,
- CallStaticFloatMethodV,
- CallStaticFloatMethodA,
- CallStaticDoubleMethod,
- CallStaticDoubleMethodV,
- CallStaticDoubleMethodA,
- CallStaticVoidMethod,
- CallStaticVoidMethodV,
- CallStaticVoidMethodA,
- GetStaticFieldID,
- GetStaticObjectField,
- GetStaticBooleanField,
- GetStaticByteField,
- GetStaticCharField,
- GetStaticShortField,
- GetStaticIntField,
- GetStaticLongField,
- GetStaticFloatField,
- GetStaticDoubleField,
- SetStaticObjectField,
- SetStaticBooleanField,
- SetStaticByteField,
- SetStaticCharField,
- SetStaticShortField,
- SetStaticIntField,
- SetStaticLongField,
- SetStaticFloatField,
- SetStaticDoubleField,
- NewString,
- GetStringLength,
- GetStringChars,
- ReleaseStringChars,
- NewStringUTF,
- GetStringUTFLength,
- GetStringUTFChars,
- ReleaseStringUTFChars,
- GetArrayLength,
- NewObjectArray,
- GetObjectArrayElement,
- SetObjectArrayElement,
- NewBooleanArray,
- NewByteArray,
- NewCharArray,
- NewShortArray,
- NewIntArray,
- NewLongArray,
- NewFloatArray,
- NewDoubleArray,
- GetBooleanArrayElements,
- GetByteArrayElements,
- GetCharArrayElements,
- GetShortArrayElements,
- GetIntArrayElements,
- GetLongArrayElements,
- GetFloatArrayElements,
- GetDoubleArrayElements,
- ReleaseBooleanArrayElements,
- ReleaseByteArrayElements,
- ReleaseCharArrayElements,
- ReleaseShortArrayElements,
- ReleaseIntArrayElements,
- ReleaseLongArrayElements,
- ReleaseFloatArrayElements,
- ReleaseDoubleArrayElements,
- GetBooleanArrayRegion,
- GetByteArrayRegion,
- GetCharArrayRegion,
- GetShortArrayRegion,
- GetIntArrayRegion,
- GetLongArrayRegion,
- GetFloatArrayRegion,
- GetDoubleArrayRegion,
- SetBooleanArrayRegion,
- SetByteArrayRegion,
- SetCharArrayRegion,
- SetShortArrayRegion,
- SetIntArrayRegion,
- SetLongArrayRegion,
- SetFloatArrayRegion,
- SetDoubleArrayRegion,
- RegisterNatives,
- UnregisterNatives,
- MonitorEnter,
- MonitorExit,
- GetJavaVM,
- GetStringRegion,
- GetStringUTFRegion,
- GetPrimitiveArrayCritical,
- ReleasePrimitiveArrayCritical,
- GetStringCritical,
- ReleaseStringCritical,
- NewWeakGlobalRef,
- DeleteWeakGlobalRef,
- ExceptionCheck,
- NewDirectByteBuffer,
- GetDirectBufferAddress,
- GetDirectBufferCapacity,
- GetObjectRefType,
+ JNI::GetVersion,
+ JNI::DefineClass,
+ JNI::FindClass,
+ JNI::FromReflectedMethod,
+ JNI::FromReflectedField,
+ JNI::ToReflectedMethod,
+ JNI::GetSuperclass,
+ JNI::IsAssignableFrom,
+ JNI::ToReflectedField,
+ JNI::Throw,
+ JNI::ThrowNew,
+ JNI::ExceptionOccurred,
+ JNI::ExceptionDescribe,
+ JNI::ExceptionClear,
+ JNI::FatalError,
+ JNI::PushLocalFrame,
+ JNI::PopLocalFrame,
+ JNI::NewGlobalRef,
+ JNI::DeleteGlobalRef,
+ JNI::DeleteLocalRef,
+ JNI::IsSameObject,
+ JNI::NewLocalRef,
+ JNI::EnsureLocalCapacity,
+ JNI::AllocObject,
+ JNI::NewObject,
+ JNI::NewObjectV,
+ JNI::NewObjectA,
+ JNI::GetObjectClass,
+ JNI::IsInstanceOf,
+ JNI::GetMethodID,
+ JNI::CallObjectMethod,
+ JNI::CallObjectMethodV,
+ JNI::CallObjectMethodA,
+ JNI::CallBooleanMethod,
+ JNI::CallBooleanMethodV,
+ JNI::CallBooleanMethodA,
+ JNI::CallByteMethod,
+ JNI::CallByteMethodV,
+ JNI::CallByteMethodA,
+ JNI::CallCharMethod,
+ JNI::CallCharMethodV,
+ JNI::CallCharMethodA,
+ JNI::CallShortMethod,
+ JNI::CallShortMethodV,
+ JNI::CallShortMethodA,
+ JNI::CallIntMethod,
+ JNI::CallIntMethodV,
+ JNI::CallIntMethodA,
+ JNI::CallLongMethod,
+ JNI::CallLongMethodV,
+ JNI::CallLongMethodA,
+ JNI::CallFloatMethod,
+ JNI::CallFloatMethodV,
+ JNI::CallFloatMethodA,
+ JNI::CallDoubleMethod,
+ JNI::CallDoubleMethodV,
+ JNI::CallDoubleMethodA,
+ JNI::CallVoidMethod,
+ JNI::CallVoidMethodV,
+ JNI::CallVoidMethodA,
+ JNI::CallNonvirtualObjectMethod,
+ JNI::CallNonvirtualObjectMethodV,
+ JNI::CallNonvirtualObjectMethodA,
+ JNI::CallNonvirtualBooleanMethod,
+ JNI::CallNonvirtualBooleanMethodV,
+ JNI::CallNonvirtualBooleanMethodA,
+ JNI::CallNonvirtualByteMethod,
+ JNI::CallNonvirtualByteMethodV,
+ JNI::CallNonvirtualByteMethodA,
+ JNI::CallNonvirtualCharMethod,
+ JNI::CallNonvirtualCharMethodV,
+ JNI::CallNonvirtualCharMethodA,
+ JNI::CallNonvirtualShortMethod,
+ JNI::CallNonvirtualShortMethodV,
+ JNI::CallNonvirtualShortMethodA,
+ JNI::CallNonvirtualIntMethod,
+ JNI::CallNonvirtualIntMethodV,
+ JNI::CallNonvirtualIntMethodA,
+ JNI::CallNonvirtualLongMethod,
+ JNI::CallNonvirtualLongMethodV,
+ JNI::CallNonvirtualLongMethodA,
+ JNI::CallNonvirtualFloatMethod,
+ JNI::CallNonvirtualFloatMethodV,
+ JNI::CallNonvirtualFloatMethodA,
+ JNI::CallNonvirtualDoubleMethod,
+ JNI::CallNonvirtualDoubleMethodV,
+ JNI::CallNonvirtualDoubleMethodA,
+ JNI::CallNonvirtualVoidMethod,
+ JNI::CallNonvirtualVoidMethodV,
+ JNI::CallNonvirtualVoidMethodA,
+ JNI::GetFieldID,
+ JNI::GetObjectField,
+ JNI::GetBooleanField,
+ JNI::GetByteField,
+ JNI::GetCharField,
+ JNI::GetShortField,
+ JNI::GetIntField,
+ JNI::GetLongField,
+ JNI::GetFloatField,
+ JNI::GetDoubleField,
+ JNI::SetObjectField,
+ JNI::SetBooleanField,
+ JNI::SetByteField,
+ JNI::SetCharField,
+ JNI::SetShortField,
+ JNI::SetIntField,
+ JNI::SetLongField,
+ JNI::SetFloatField,
+ JNI::SetDoubleField,
+ JNI::GetStaticMethodID,
+ JNI::CallStaticObjectMethod,
+ JNI::CallStaticObjectMethodV,
+ JNI::CallStaticObjectMethodA,
+ JNI::CallStaticBooleanMethod,
+ JNI::CallStaticBooleanMethodV,
+ JNI::CallStaticBooleanMethodA,
+ JNI::CallStaticByteMethod,
+ JNI::CallStaticByteMethodV,
+ JNI::CallStaticByteMethodA,
+ JNI::CallStaticCharMethod,
+ JNI::CallStaticCharMethodV,
+ JNI::CallStaticCharMethodA,
+ JNI::CallStaticShortMethod,
+ JNI::CallStaticShortMethodV,
+ JNI::CallStaticShortMethodA,
+ JNI::CallStaticIntMethod,
+ JNI::CallStaticIntMethodV,
+ JNI::CallStaticIntMethodA,
+ JNI::CallStaticLongMethod,
+ JNI::CallStaticLongMethodV,
+ JNI::CallStaticLongMethodA,
+ JNI::CallStaticFloatMethod,
+ JNI::CallStaticFloatMethodV,
+ JNI::CallStaticFloatMethodA,
+ JNI::CallStaticDoubleMethod,
+ JNI::CallStaticDoubleMethodV,
+ JNI::CallStaticDoubleMethodA,
+ JNI::CallStaticVoidMethod,
+ JNI::CallStaticVoidMethodV,
+ JNI::CallStaticVoidMethodA,
+ JNI::GetStaticFieldID,
+ JNI::GetStaticObjectField,
+ JNI::GetStaticBooleanField,
+ JNI::GetStaticByteField,
+ JNI::GetStaticCharField,
+ JNI::GetStaticShortField,
+ JNI::GetStaticIntField,
+ JNI::GetStaticLongField,
+ JNI::GetStaticFloatField,
+ JNI::GetStaticDoubleField,
+ JNI::SetStaticObjectField,
+ JNI::SetStaticBooleanField,
+ JNI::SetStaticByteField,
+ JNI::SetStaticCharField,
+ JNI::SetStaticShortField,
+ JNI::SetStaticIntField,
+ JNI::SetStaticLongField,
+ JNI::SetStaticFloatField,
+ JNI::SetStaticDoubleField,
+ JNI::NewString,
+ JNI::GetStringLength,
+ JNI::GetStringChars,
+ JNI::ReleaseStringChars,
+ JNI::NewStringUTF,
+ JNI::GetStringUTFLength,
+ JNI::GetStringUTFChars,
+ JNI::ReleaseStringUTFChars,
+ JNI::GetArrayLength,
+ JNI::NewObjectArray,
+ JNI::GetObjectArrayElement,
+ JNI::SetObjectArrayElement,
+ JNI::NewBooleanArray,
+ JNI::NewByteArray,
+ JNI::NewCharArray,
+ JNI::NewShortArray,
+ JNI::NewIntArray,
+ JNI::NewLongArray,
+ JNI::NewFloatArray,
+ JNI::NewDoubleArray,
+ JNI::GetBooleanArrayElements,
+ JNI::GetByteArrayElements,
+ JNI::GetCharArrayElements,
+ JNI::GetShortArrayElements,
+ JNI::GetIntArrayElements,
+ JNI::GetLongArrayElements,
+ JNI::GetFloatArrayElements,
+ JNI::GetDoubleArrayElements,
+ JNI::ReleaseBooleanArrayElements,
+ JNI::ReleaseByteArrayElements,
+ JNI::ReleaseCharArrayElements,
+ JNI::ReleaseShortArrayElements,
+ JNI::ReleaseIntArrayElements,
+ JNI::ReleaseLongArrayElements,
+ JNI::ReleaseFloatArrayElements,
+ JNI::ReleaseDoubleArrayElements,
+ JNI::GetBooleanArrayRegion,
+ JNI::GetByteArrayRegion,
+ JNI::GetCharArrayRegion,
+ JNI::GetShortArrayRegion,
+ JNI::GetIntArrayRegion,
+ JNI::GetLongArrayRegion,
+ JNI::GetFloatArrayRegion,
+ JNI::GetDoubleArrayRegion,
+ JNI::SetBooleanArrayRegion,
+ JNI::SetByteArrayRegion,
+ JNI::SetCharArrayRegion,
+ JNI::SetShortArrayRegion,
+ JNI::SetIntArrayRegion,
+ JNI::SetLongArrayRegion,
+ JNI::SetFloatArrayRegion,
+ JNI::SetDoubleArrayRegion,
+ JNI::RegisterNatives,
+ JNI::UnregisterNatives,
+ JNI::MonitorEnter,
+ JNI::MonitorExit,
+ JNI::GetJavaVM,
+ JNI::GetStringRegion,
+ JNI::GetStringUTFRegion,
+ JNI::GetPrimitiveArrayCritical,
+ JNI::ReleasePrimitiveArrayCritical,
+ JNI::GetStringCritical,
+ JNI::ReleaseStringCritical,
+ JNI::NewWeakGlobalRef,
+ JNI::DeleteWeakGlobalRef,
+ JNI::ExceptionCheck,
+ JNI::NewDirectByteBuffer,
+ JNI::GetDirectBufferAddress,
+ JNI::GetDirectBufferCapacity,
+ JNI::GetObjectRefType,
};
static const size_t kMonitorsInitial = 32; // Arbitrary.
@@ -2539,92 +2404,95 @@
return JNI_ERR;
}
-jint DestroyJavaVM(JavaVM* vm) {
- if (vm == NULL) {
- return JNI_ERR;
- } else {
- JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
- delete raw_vm->runtime;
- return JNI_OK;
+class JII {
+ public:
+ static jint DestroyJavaVM(JavaVM* vm) {
+ if (vm == NULL) {
+ return JNI_ERR;
+ } else {
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ delete raw_vm->runtime;
+ return JNI_OK;
+ }
}
-}
-jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
- if (vm == NULL || p_env == NULL) {
- return JNI_ERR;
- }
- JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
- Runtime* runtime = raw_vm->runtime;
- const char* name = NULL;
- if (thr_args != NULL) {
- // TODO: check version
- name = static_cast<JavaVMAttachArgs*>(thr_args)->name;
- // TODO: thread group
- }
- bool success = runtime->AttachCurrentThread(name, p_env);
- if (!success) {
- return JNI_ERR;
- } else {
- return JNI_OK;
- }
-}
-
-jint DetachCurrentThread(JavaVM* vm) {
- if (vm == NULL) {
- return JNI_ERR;
- } else {
+ static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
+ if (vm == NULL || p_env == NULL) {
+ return JNI_ERR;
+ }
JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
Runtime* runtime = raw_vm->runtime;
- runtime->DetachCurrentThread();
+ const char* name = NULL;
+ if (thr_args != NULL) {
+ // TODO: check version
+ name = static_cast<JavaVMAttachArgs*>(thr_args)->name;
+ // TODO: thread group
+ }
+ bool success = runtime->AttachCurrentThread(name, p_env);
+ if (!success) {
+ return JNI_ERR;
+ } else {
+ return JNI_OK;
+ }
+ }
+
+ static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
+ if (vm == NULL || p_env == NULL) {
+ return JNI_ERR;
+ }
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
+ const char* name = NULL;
+ if (thr_args != NULL) {
+ // TODO: check version
+ name = static_cast<JavaVMAttachArgs*>(thr_args)->name;
+ // TODO: thread group
+ }
+ bool success = runtime->AttachCurrentThreadAsDaemon(name, p_env);
+ if (!success) {
+ return JNI_ERR;
+ } else {
+ return JNI_OK;
+ }
+ }
+
+ static jint DetachCurrentThread(JavaVM* vm) {
+ if (vm == NULL) {
+ return JNI_ERR;
+ } else {
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
+ runtime->DetachCurrentThread();
+ return JNI_OK;
+ }
+ }
+
+ static jint GetEnv(JavaVM* vm, void** env, jint version) {
+ if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
+ return JNI_EVERSION;
+ }
+ if (vm == NULL || env == NULL) {
+ return JNI_ERR;
+ }
+ Thread* thread = Thread::Current();
+ if (thread == NULL) {
+ *env = NULL;
+ return JNI_EDETACHED;
+ }
+ *env = thread->GetJniEnv();
return JNI_OK;
}
-}
-
-jint GetEnv(JavaVM* vm, void** env, jint version) {
- if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
- return JNI_EVERSION;
- }
- if (vm == NULL || env == NULL) {
- return JNI_ERR;
- }
- Thread* thread = Thread::Current();
- if (thread == NULL) {
- *env = NULL;
- return JNI_EDETACHED;
- }
- *env = thread->GetJniEnv();
- return JNI_OK;
-}
-
-jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
- if (vm == NULL || p_env == NULL) {
- return JNI_ERR;
- }
- JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
- Runtime* runtime = raw_vm->runtime;
- const char* name = NULL;
- if (thr_args != NULL) {
- // TODO: check version
- name = static_cast<JavaVMAttachArgs*>(thr_args)->name;
- // TODO: thread group
- }
- bool success = runtime->AttachCurrentThreadAsDaemon(name, p_env);
- if (!success) {
- return JNI_ERR;
- } else {
- return JNI_OK;
- }
-}
+};
struct JNIInvokeInterface gInvokeInterface = {
NULL, // reserved0
NULL, // reserved1
NULL, // reserved2
- DestroyJavaVM,
- AttachCurrentThread,
- DetachCurrentThread,
- GetEnv,
- AttachCurrentThreadAsDaemon
+ JII::DestroyJavaVM,
+ JII::AttachCurrentThread,
+ JII::DetachCurrentThread,
+ JII::GetEnv,
+ JII::AttachCurrentThreadAsDaemon
};
static const size_t kPinTableInitialSize = 16;
@@ -2653,4 +2521,158 @@
delete weak_globals_lock;
}
+/*
+ * Load native code from the specified absolute pathname. Per the spec,
+ * if we've already loaded a library with the specified pathname, we
+ * return without doing anything.
+ *
+ * TODO? for better results we should absolutify the pathname. For fully
+ * correct results we should stat to get the inode and compare that. The
+ * existing implementation is fine so long as everybody is using
+ * System.loadLibrary.
+ *
+ * The library will be associated with the specified class loader. The JNI
+ * spec says we can't load the same library into more than one class loader.
+ *
+ * Returns "true" on success. On failure, sets *detail to a
+ * human-readable description of the error or NULL if no detail is
+ * available; ownership of the string is transferred to the caller.
+ */
+bool JavaVMExt::LoadNativeLibrary(const std::string& path, Object* class_loader, char** detail) {
+ *detail = NULL;
+
+ // See if we've already loaded this library. If we have, and the class loader
+ // matches, return successfully without doing anything.
+ SharedLibrary* library = libraries[path];
+ if (library != NULL) {
+ if (library->GetClassLoader() != class_loader) {
+ LOG(WARNING) << "Shared library \"" << path << "\" already opened by "
+ << "ClassLoader " << library->GetClassLoader() << "; "
+ << "can't open in " << class_loader;
+ *detail = strdup("already opened by different ClassLoader");
+ return false;
+ }
+ if (verbose_jni) {
+ LOG(INFO) << "[Shared library \"" << path << "\" already loaded in "
+ << "ClassLoader " << class_loader << "]";
+ }
+ if (!library->CheckOnLoadResult(this)) {
+ *detail = strdup("JNI_OnLoad failed before");
+ return false;
+ }
+ return true;
+ }
+
+ // Open the shared library. Because we're using a full path, the system
+ // doesn't have to search through LD_LIBRARY_PATH. (It may do so to
+ // resolve this library's dependencies though.)
+
+ // Failures here are expected when java.library.path has several entries
+ // and we have to hunt for the lib.
+
+ // The current version of the dynamic linker prints detailed information
+ // about dlopen() failures. Some things to check if the message is
+ // cryptic:
+ // - make sure the library exists on the device
+ // - verify that the right path is being opened (the debug log message
+ // above can help with that)
+ // - check to see if the library is valid (e.g. not zero bytes long)
+ // - check config/prelink-linux-arm.map to ensure that the library
+ // is listed and is not being overrun by the previous entry (if
+ // loading suddenly stops working on a prelinked library, this is
+ // a good one to check)
+ // - write a trivial app that calls sleep() then dlopen(), attach
+ // to it with "strace -p <pid>" while it sleeps, and watch for
+ // attempts to open nonexistent dependent shared libs
+
+ // TODO: automate some of these checks!
+
+ // This can execute slowly for a large library on a busy system, so we
+ // want to switch from RUNNING to VMWAIT while it executes. This allows
+ // the GC to ignore us.
+ Thread* self = Thread::Current();
+ Thread::State old_state = self->GetState();
+ self->SetState(Thread::kWaiting); // TODO: VMWAIT
+ void* handle = dlopen(path.c_str(), RTLD_LAZY);
+ self->SetState(old_state);
+
+ if (verbose_jni) {
+ LOG(INFO) << "[Call to dlopen(\"" << path << "\") returned " << handle << "]";
+ }
+
+ if (handle == NULL) {
+ *detail = strdup(dlerror());
+ return false;
+ }
+
+ // Create a new entry.
+ library = new SharedLibrary(path, handle, class_loader);
+ UNIMPLEMENTED(ERROR) << "missing pthread_cond_init";
+ // pthread_cond_init(&library->onLoadCond, NULL);
+
+ libraries[path] = library;
+
+ // if (pNewEntry != pActualEntry) {
+ // LOG(INFO) << "WOW: we lost a race to add a shared library (\"" << path << "\" ClassLoader=" << class_loader <<")";
+ // freeSharedLibEntry(pNewEntry);
+ // return CheckOnLoadResult(this, pActualEntry);
+ // } else
+ {
+ if (verbose_jni) {
+ LOG(INFO) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
+ }
+
+ bool result = true;
+ void* sym = dlsym(handle, "JNI_OnLoad");
+ if (sym == NULL) {
+ if (verbose_jni) {
+ LOG(INFO) << "[No JNI_OnLoad found in \"" << path << "\"]";
+ }
+ } else {
+ // Call JNI_OnLoad. We have to override the current class
+ // loader, which will always be "null" since the stuff at the
+ // top of the stack is around Runtime.loadLibrary(). (See
+ // the comments in the JNI FindClass function.)
+ UNIMPLEMENTED(WARNING) << "need to override current class loader";
+ typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
+ JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
+ //Object* prevOverride = self->classLoaderOverride;
+ //self->classLoaderOverride = classLoader;
+
+ old_state = self->GetState();
+ self->SetState(Thread::kNative);
+ if (verbose_jni) {
+ LOG(INFO) << "[Calling JNI_OnLoad in \"" << path << "\"]";
+ }
+ int version = (*jni_on_load)(reinterpret_cast<JavaVM*>(this), NULL);
+ self->SetState(old_state);
+
+ UNIMPLEMENTED(WARNING) << "need to restore current class loader";
+ //self->classLoaderOverride = prevOverride;
+
+ if (version != JNI_VERSION_1_2 &&
+ version != JNI_VERSION_1_4 &&
+ version != JNI_VERSION_1_6) {
+ LOG(WARNING) << "JNI_OnLoad in \"" << path << "\" returned "
+ << "bad version: " << version;
+ // It's unwise to call dlclose() here, but we can mark it
+ // as bad and ensure that future load attempts will fail.
+ // We don't know how far JNI_OnLoad got, so there could
+ // be some partially-initialized stuff accessible through
+ // newly-registered native method calls. We could try to
+ // unregister them, but that doesn't seem worthwhile.
+ result = false;
+ } else {
+ if (verbose_jni) {
+ LOG(INFO) << "[Returned " << (result ? "successfully" : "failure")
+ << " from JNI_OnLoad in \"" << path << "\"]";
+ }
+ }
+ }
+
+ library->SetResult(result);
+ return result;
+ }
+}
+
} // namespace art
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index f51b6c9..6c5d6f2 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -57,23 +57,91 @@
EXPECT_CLASS_NOT_FOUND("K");
}
+#define EXPECT_EXCEPTION(exception_class) \
+ do { \
+ EXPECT_TRUE(env_->ExceptionCheck()); \
+ jthrowable exception = env_->ExceptionOccurred(); \
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception); \
+ EXPECT_TRUE(env_->IsInstanceOf(exception, exception_class)); \
+ env_->ExceptionClear(); \
+ } while (false)
+
+TEST_F(JniInternalTest, GetFieldID) {
+ jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
+ ASSERT_TRUE(jlnsfe != NULL);
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_TRUE(c != NULL);
+
+ // Wrong type.
+ jfieldID fid = env_->GetFieldID(c, "count", "J");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+
+ // Wrong name.
+ fid = env_->GetFieldID(c, "Count", "I");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+
+ // Good declared field lookup.
+ fid = env_->GetFieldID(c, "count", "I");
+ EXPECT_NE(static_cast<jfieldID>(NULL), fid);
+ EXPECT_TRUE(fid != NULL);
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Good superclass field lookup.
+ c = env_->FindClass("java/lang/StringBuilder");
+ fid = env_->GetFieldID(c, "count", "I");
+ EXPECT_NE(static_cast<jfieldID>(NULL), fid);
+ EXPECT_TRUE(fid != NULL);
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Not instance.
+ fid = env_->GetFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+}
+
+TEST_F(JniInternalTest, GetStaticFieldID) {
+ jclass jlnsfe = env_->FindClass("java/lang/NoSuchFieldError");
+ ASSERT_TRUE(jlnsfe != NULL);
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_TRUE(c != NULL);
+
+ // Wrong type.
+ jfieldID fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "J");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+
+ // Wrong name.
+ fid = env_->GetStaticFieldID(c, "cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+
+ // Good declared field lookup.
+ fid = env_->GetStaticFieldID(c, "CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ EXPECT_NE(static_cast<jfieldID>(NULL), fid);
+ EXPECT_TRUE(fid != NULL);
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Not static.
+ fid = env_->GetStaticFieldID(c, "count", "I");
+ EXPECT_EQ(static_cast<jfieldID>(NULL), fid);
+ EXPECT_EXCEPTION(jlnsfe);
+}
+
TEST_F(JniInternalTest, GetMethodID) {
jclass jlobject = env_->FindClass("java/lang/Object");
jclass jlstring = env_->FindClass("java/lang/String");
jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
// Sanity check that no exceptions are pending
- EXPECT_FALSE(env_->ExceptionCheck());
+ ASSERT_FALSE(env_->ExceptionCheck());
// Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
// a pending exception
jmethodID method = env_->GetMethodID(jlobject, "foo", "()V");
EXPECT_EQ(static_cast<jmethodID>(NULL), method);
- EXPECT_TRUE(env_->ExceptionCheck());
- jthrowable exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
// Check that java.lang.Object.equals() does exist
method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
@@ -84,11 +152,7 @@
// method is static
method = env_->GetMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
EXPECT_EQ(static_cast<jmethodID>(NULL), method);
- EXPECT_TRUE(env_->ExceptionCheck());
- exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
}
TEST_F(JniInternalTest, GetStaticMethodID) {
@@ -96,27 +160,19 @@
jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
// Sanity check that no exceptions are pending
- EXPECT_FALSE(env_->ExceptionCheck());
+ ASSERT_FALSE(env_->ExceptionCheck());
// Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
// a pending exception
jmethodID method = env_->GetStaticMethodID(jlobject, "foo", "()V");
EXPECT_EQ(static_cast<jmethodID>(NULL), method);
- EXPECT_TRUE(env_->ExceptionCheck());
- jthrowable exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
// Check that GetStaticMethodID for java.lang.Object.equals(Object) fails as
// the method is not static
method = env_->GetStaticMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
EXPECT_EQ(static_cast<jmethodID>(NULL), method);
- EXPECT_TRUE(env_->ExceptionCheck());
- exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
// Check that java.lang.String.valueOf(int) does exist
jclass jlstring = env_->FindClass("java/lang/String");
@@ -126,12 +182,42 @@
EXPECT_FALSE(env_->ExceptionCheck());
}
+TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
+ jclass jlrField = env_->FindClass("java/lang/reflect/Field");
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_TRUE(c != NULL);
+ jfieldID fid = env_->GetFieldID(c, "count", "I");
+ ASSERT_TRUE(fid != NULL);
+ // Turn the fid into a java.lang.reflect.Field...
+ jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
+ ASSERT_TRUE(c != NULL);
+ ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
+ // ...and back again.
+ jfieldID fid2 = env_->FromReflectedField(field);
+ ASSERT_TRUE(fid2 != NULL);
+}
+
+TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) {
+ jclass jlrMethod = env_->FindClass("java/lang/reflect/Method");
+ jclass c = env_->FindClass("java/lang/String");
+ ASSERT_TRUE(c != NULL);
+ jmethodID mid = env_->GetMethodID(c, "length", "()I");
+ ASSERT_TRUE(mid != NULL);
+ // Turn the mid into a java.lang.reflect.Method...
+ jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
+ ASSERT_TRUE(c != NULL);
+ ASSERT_TRUE(env_->IsInstanceOf(method, jlrMethod));
+ // ...and back again.
+ jmethodID mid2 = env_->FromReflectedMethod(method);
+ ASSERT_TRUE(mid2 != NULL);
+}
+
TEST_F(JniInternalTest, RegisterNatives) {
jclass jlobject = env_->FindClass("java/lang/Object");
jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
// Sanity check that no exceptions are pending
- EXPECT_FALSE(env_->ExceptionCheck());
+ ASSERT_FALSE(env_->ExceptionCheck());
// Check that registering to a non-existent java.lang.Object.foo() causes a
// NoSuchMethodError
@@ -139,22 +225,14 @@
JNINativeMethod methods[] = {{"foo", "()V", NULL}};
env_->RegisterNatives(jlobject, methods, 1);
}
- EXPECT_TRUE(env_->ExceptionCheck());
- jthrowable exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
// Check that registering non-native methods causes a NoSuchMethodError
{
JNINativeMethod methods[] = {{"equals", "(Ljava/lang/Object;)Z", NULL}};
env_->RegisterNatives(jlobject, methods, 1);
}
- EXPECT_TRUE(env_->ExceptionCheck());
- exception = env_->ExceptionOccurred();
- EXPECT_NE(static_cast<jthrowable>(NULL), exception);
- EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(jlnsme);
// Check that registering native methods is successful
{
@@ -215,6 +293,7 @@
}
TEST_F(JniInternalTest, SetObjectArrayElement) {
+ jclass aioobe = env_->FindClass("java/lang/ArrayIndexOutOfBoundsException");
jclass c = env_->FindClass("[Ljava/lang/Object;");
ASSERT_TRUE(c != NULL);
@@ -224,16 +303,12 @@
// TODO: check reading value back
// ArrayIndexOutOfBounds for negative index.
- // TODO: check exception type
env_->SetObjectArrayElement(array, -1, c);
- EXPECT_TRUE(env_->ExceptionCheck());
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(aioobe);
// ArrayIndexOutOfBounds for too-large index.
- // TODO: check exception type
env_->SetObjectArrayElement(array, 1, c);
- EXPECT_TRUE(env_->ExceptionCheck());
- env_->ExceptionClear();
+ EXPECT_EXCEPTION(aioobe);
// TODO: check ArrayStoreException thrown for bad types.
}
diff --git a/src/object.cc b/src/object.cc
index 8af1778..b9324a6 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -442,6 +442,62 @@
return NULL;
}
+Field* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& descriptor) {
+ // Is the field in this class?
+ // Interfaces are not relevant because they can't contain instance fields.
+ for (size_t i = 0; i < NumInstanceFields(); ++i) {
+ Field* f = GetInstanceField(i);
+ if (f->GetName()->Equals(name) && f->GetDescriptor() == descriptor) {
+ return f;
+ }
+ }
+ return NULL;
+}
+
+Field* Class::FindInstanceField(const StringPiece& name, const StringPiece& descriptor) {
+ // Is the field in this class, or any of its superclasses?
+ // Interfaces are not relevant because they can't contain instance fields.
+ for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ Field* f = c->FindDeclaredInstanceField(name, descriptor);
+ if (f != NULL) {
+ return f;
+ }
+ }
+ return NULL;
+}
+
+Field* Class::FindDeclaredStaticField(const StringPiece& name, const StringPiece& descriptor) {
+ for (size_t i = 0; i < NumStaticFields(); ++i) {
+ Field* f = GetStaticField(i);
+ if (f->GetName()->Equals(name) && f->GetDescriptor() == descriptor) {
+ return f;
+ }
+ }
+ return NULL;
+}
+
+Field* Class::FindStaticField(const StringPiece& name, const StringPiece& descriptor) {
+ // Is the field in this class (or its interfaces), or any of its
+ // superclasses (or their interfaces)?
+ for (Class* c = this; c != NULL; c = c->GetSuperClass()) {
+ // Is the field in this class?
+ Field* f = c->FindDeclaredStaticField(name, descriptor);
+ if (f != NULL) {
+ return f;
+ }
+
+ // Is this field in any of this class' interfaces?
+ for (size_t i = 0; i < c->NumInterfaces(); ++i) {
+ Class* interface = c->GetInterface(i);
+ f = interface->FindDeclaredStaticField(name, descriptor);
+ if (f != NULL) {
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
template<typename T>
PrimitiveArray<T>* PrimitiveArray<T>::Alloc(size_t length) {
Array* raw_array = Array::Alloc(array_class_, length, sizeof(T));
diff --git a/src/object.h b/src/object.h
index c78103b..2b5a054 100644
--- a/src/object.h
+++ b/src/object.h
@@ -979,6 +979,20 @@
return num_reference_instance_fields_;
}
+ // Finds the given instance field in this class or a superclass.
+ Field* FindInstanceField(const StringPiece& name,
+ const StringPiece& descriptor);
+
+ Field* FindDeclaredInstanceField(const StringPiece& name,
+ const StringPiece& descriptor);
+
+ // Finds the given static field in this class or a superclass.
+ Field* FindStaticField(const StringPiece& name,
+ const StringPiece& descriptor);
+
+ Field* FindDeclaredStaticField(const StringPiece& name,
+ const StringPiece& descriptor);
+
Field* GetInstanceField(uint32_t i) const { // TODO: uint16_t
DCHECK_NE(NumInstanceFields(), 0U);
return ifields_->Get(i);
diff --git a/src/object_test.cc b/src/object_test.cc
index 3f5333b..549544c 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -333,4 +333,62 @@
EXPECT_TRUE(O->IsAssignableFrom(IA));
}
+TEST_F(ObjectTest, FindInstanceField) {
+ String* s = String::AllocFromModifiedUtf8("ABC");
+ ASSERT_TRUE(s != NULL);
+ Class* c = s->GetClass();
+ ASSERT_TRUE(c != NULL);
+
+ // Wrong type.
+ EXPECT_TRUE(c->FindDeclaredInstanceField("count", "J") == NULL);
+ EXPECT_TRUE(c->FindInstanceField("count", "J") == NULL);
+
+ // Wrong name.
+ EXPECT_TRUE(c->FindDeclaredInstanceField("Count", "I") == NULL);
+ EXPECT_TRUE(c->FindInstanceField("Count", "I") == NULL);
+
+ // Right name and type.
+ Field* f1 = c->FindDeclaredInstanceField("count", "I");
+ Field* f2 = c->FindInstanceField("count", "I");
+ EXPECT_TRUE(f1 != NULL);
+ EXPECT_TRUE(f2 != NULL);
+ EXPECT_EQ(f1, f2);
+
+ // TODO: check that s.count == 3.
+
+ // Ensure that we handle superclass fields correctly...
+ c = class_linker_->FindSystemClass("Ljava/lang/StringBuilder;");
+ ASSERT_TRUE(c != NULL);
+ // No StringBuilder.count...
+ EXPECT_TRUE(c->FindDeclaredInstanceField("count", "I") == NULL);
+ // ...but there is an AbstractStringBuilder.count.
+ EXPECT_TRUE(c->FindInstanceField("count", "I") != NULL);
+}
+
+TEST_F(ObjectTest, FindStaticField) {
+ String* s = String::AllocFromModifiedUtf8("ABC");
+ ASSERT_TRUE(s != NULL);
+ Class* c = s->GetClass();
+ ASSERT_TRUE(c != NULL);
+
+ // Wrong type.
+ EXPECT_TRUE(c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL);
+ EXPECT_TRUE(c->FindStaticField("CASE_INSENSITIVE_ORDER", "I") == NULL);
+
+ // Wrong name.
+ EXPECT_TRUE(c->FindDeclaredStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL);
+ EXPECT_TRUE(c->FindStaticField("cASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;") == NULL);
+
+ // Right name and type.
+ Field* f1 = c->FindDeclaredStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ Field* f2 = c->FindStaticField("CASE_INSENSITIVE_ORDER", "Ljava/util/Comparator;");
+ EXPECT_TRUE(f1 != NULL);
+ EXPECT_TRUE(f2 != NULL);
+ EXPECT_EQ(f1, f2);
+
+ // TODO: test static fields via superclasses.
+ // TODO: test static fields via interfaces.
+ // TODO: test that interfaces trump superclasses.
+}
+
} // namespace art