diff options
-rw-r--r-- | build/Android.libart.mk | 2 | ||||
-rw-r--r-- | build/Android.test.mk | 4 | ||||
-rw-r--r-- | src/assembler_x86.cc | 10 | ||||
-rw-r--r-- | src/constants_x86.h | 43 | ||||
-rw-r--r-- | src/jni_internal.cc | 109 | ||||
-rw-r--r-- | src/jni_internal.h | 8 | ||||
-rw-r--r-- | src/jni_internal_test.cc | 111 | ||||
-rw-r--r-- | src/runtime.cc | 6 | ||||
-rw-r--r-- | src/thread.h | 4 |
9 files changed, 230 insertions, 67 deletions
diff --git a/build/Android.libart.mk b/build/Android.libart.mk index b71cc534a7..61a25b440e 100644 --- a/build/Android.libart.mk +++ b/build/Android.libart.mk @@ -38,7 +38,7 @@ define build-libart LOCAL_CFLAGS += -UNDEBUG endif LOCAL_C_INCLUDES += src $(ART_C_INCLUDES) - LOCAL_SHARED_LIBRARIES := liblog + LOCAL_SHARED_LIBRARIES := liblog libnativehelper ifeq ($(1),target) LOCAL_SHARED_LIBRARIES += libcutils libstlport libz libdl else diff --git a/build/Android.test.mk b/build/Android.test.mk index 3f5673c891..22209ec72e 100644 --- a/build/Android.test.mk +++ b/build/Android.test.mk @@ -32,10 +32,10 @@ define build-art-test LOCAL_C_INCLUDES += $(ART_C_INCLUDES) LOCAL_SHARED_LIBRARIES := libarttest libartd ifeq ($(1),target) - LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libstlport libz + LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libstlport libz LOCAL_STATIC_LIBRARIES := libgtest libgtest_main else - LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libz-host + LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libz-host LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_host libgtest_main_host endif ifeq ($(1),target) diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc index 693f1b4e41..78a20c0ee3 100644 --- a/src/assembler_x86.cc +++ b/src/assembler_x86.cc @@ -1560,7 +1560,7 @@ void Assembler::CreateStackHandle(ManagedRegister out_reg, xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); } testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); - j(ZERO, &null_arg); + j(kZero, &null_arg); leal(out_reg.AsCpuRegister(), Address(ESP, handle_offset)); Bind(&null_arg); } else { @@ -1576,7 +1576,7 @@ void Assembler::CreateStackHandle(FrameOffset out_off, Label null_arg; movl(scratch.AsCpuRegister(), Address(ESP, handle_offset)); testl(scratch.AsCpuRegister(), scratch.AsCpuRegister()); - j(ZERO, &null_arg); + j(kZero, &null_arg); leal(scratch.AsCpuRegister(), Address(ESP, handle_offset)); Bind(&null_arg); } else { @@ -1595,7 +1595,7 @@ void Assembler::LoadReferenceFromStackHandle(ManagedRegister out_reg, xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); } testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); - j(ZERO, &null_arg); + j(kZero, &null_arg); movl(out_reg.AsCpuRegister(), Address(in_reg.AsCpuRegister(), 0)); Bind(&null_arg); } @@ -1627,7 +1627,7 @@ void Assembler::SuspendPoll(ManagedRegister scratch, ManagedRegister return_reg, new SuspendCountSlowPath(return_reg, return_save_location, return_size); buffer_.EnqueueSlowPath(slow); fs()->cmpl(Address::Absolute(Thread::SuspendCountOffset()), Immediate(0)); - j(NOT_EQUAL, slow->Entry()); + j(kNotEqual, slow->Entry()); Bind(slow->Continuation()); } @@ -1651,7 +1651,7 @@ void Assembler::ExceptionPoll(ManagedRegister scratch) { ExceptionSlowPath* slow = new ExceptionSlowPath(); buffer_.EnqueueSlowPath(slow); fs()->cmpl(Address::Absolute(Thread::ExceptionOffset()), Immediate(0)); - j(NOT_EQUAL, slow->Entry()); + j(kNotEqual, slow->Entry()); Bind(slow->Continuation()); } diff --git a/src/constants_x86.h b/src/constants_x86.h index 391d0780ca..36019ae91d 100644 --- a/src/constants_x86.h +++ b/src/constants_x86.h @@ -73,29 +73,28 @@ enum ScaleFactor { TIMES_8 = 3 }; - enum Condition { - OVERFLOW = 0, - NO_OVERFLOW = 1, - BELOW = 2, - ABOVE_EQUAL = 3, - EQUAL = 4, - NOT_EQUAL = 5, - BELOW_EQUAL = 6, - ABOVE = 7, - SIGN = 8, - NOT_SIGN = 9, - PARITY_EVEN = 10, - PARITY_ODD = 11, - LESS = 12, - GREATER_EQUAL = 13, - LESS_EQUAL = 14, - GREATER = 15, - - ZERO = EQUAL, - NOT_ZERO = NOT_EQUAL, - NEGATIVE = SIGN, - POSITIVE = NOT_SIGN + kOverflow = 0, + kNoOverflow = 1, + kBelow = 2, + kAboveEqual = 3, + kEqual = 4, + kNotEqual = 5, + kBelowEqual = 6, + kAbove = 7, + kSign = 8, + kNotSign = 9, + kParityEven = 10, + kParityOdd = 11, + kLess = 12, + kGreaterEqual = 13, + kLessEqual = 14, + kGreater = 15, + + kZero = kEqual, + kNotZero = kNotEqual, + kNegative = kSign, + kPositive = kNotSign }; diff --git a/src/jni_internal.cc b/src/jni_internal.cc index 599b0fe68f..c53867083c 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "assembler.h" #include "class_linker.h" #include "jni.h" #include "logging.h" @@ -26,7 +27,11 @@ enum JNI_OnLoadState { }; struct SharedLibrary { - SharedLibrary() : jni_on_load_lock("JNI_OnLoad") { + SharedLibrary() : jni_on_load_lock(Mutex::Create("JNI_OnLoad lock")) { + } + + ~SharedLibrary() { + delete jni_on_load_lock; } // Path to library "/system/lib/libjni.so". @@ -39,7 +44,7 @@ struct SharedLibrary { Object* class_loader; // Guards remaining items. - Mutex jni_on_load_lock; + Mutex* jni_on_load_lock; // Wait for JNI_OnLoad in other thread. pthread_cond_t jni_on_load_cond; // Recursive invocation guard. @@ -63,7 +68,7 @@ bool CheckOnLoadResult(JavaVMExt* vm, SharedLibrary* library) { } UNIMPLEMENTED(ERROR) << "need to pthread_cond_wait!"; - // MutexLock mu(&library->jni_on_load_lock); + // 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 << "\" " @@ -242,7 +247,7 @@ bool JavaVMExt::LoadNativeLibrary(const std::string& path, Object* class_loader, // Broadcast a wakeup to anybody sleeping on the condition variable. UNIMPLEMENTED(ERROR) << "missing pthread_cond_broadcast"; - // MutexLock mu(&library->jni_on_load_lock); + // MutexLock mu(library->jni_on_load_lock); // pthread_cond_broadcast(&library->jni_on_load_cond); return result; } @@ -364,7 +369,7 @@ T Decode(ScopedJniThreadState& ts, jobject obj) { { JavaVMExt* vm = Runtime::Current()->GetJavaVM(); IndirectReferenceTable& globals = vm->globals; - MutexLock mu(&vm->globals_lock); + MutexLock mu(vm->globals_lock); result = globals.Get(ref); break; } @@ -372,7 +377,7 @@ T Decode(ScopedJniThreadState& ts, jobject obj) { { JavaVMExt* vm = Runtime::Current()->GetJavaVM(); IndirectReferenceTable& weak_globals = vm->weak_globals; - MutexLock mu(&vm->weak_globals_lock); + MutexLock mu(vm->weak_globals_lock); result = weak_globals.Get(ref); if (result == kClearedJniWeakGlobal) { // This is a special case where it's okay to return NULL. @@ -663,20 +668,79 @@ jobject PopLocalFrame(JNIEnv* env, jobject res) { return res; } -jobject NewGlobalRef(JNIEnv* env, jobject lobj) { +jobject NewGlobalRef(JNIEnv* env, jobject obj) { ScopedJniThreadState ts(env); - UNIMPLEMENTED(FATAL); - return NULL; + 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 gref) { +void DeleteGlobalRef(JNIEnv* env, jobject obj) { ScopedJniThreadState ts(env); - UNIMPLEMENTED(FATAL); + 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"; + } } -void DeleteLocalRef(JNIEnv* env, jobject obj) { +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; } @@ -701,12 +765,6 @@ jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) { return JNI_FALSE; } -jobject NewLocalRef(JNIEnv* env, jobject ref) { - ScopedJniThreadState ts(env); - UNIMPLEMENTED(FATAL); - return NULL; -} - jint EnsureLocalCapacity(JNIEnv* env, jint) { ScopedJniThreadState ts(env); UNIMPLEMENTED(FATAL); @@ -2095,17 +2153,6 @@ void ReleaseStringCritical(JNIEnv* env, jstring s, const jchar* cstr) { UNIMPLEMENTED(FATAL); } -jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) { - ScopedJniThreadState ts(env); - UNIMPLEMENTED(FATAL); - return NULL; -} - -void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) { - ScopedJniThreadState ts(env); - UNIMPLEMENTED(FATAL); -} - jboolean ExceptionCheck(JNIEnv* env) { ScopedJniThreadState ts(env); return ts.Self()->IsExceptionPending() ? JNI_TRUE : JNI_FALSE; @@ -2530,9 +2577,9 @@ JavaVMExt::JavaVMExt(Runtime* runtime, bool check_jni, bool verbose_jni) check_jni(check_jni), verbose_jni(verbose_jni), pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize), - globals_lock("JNI global reference table"), + globals_lock(Mutex::Create("JNI global reference table lock")), globals(kGlobalsInitial, kGlobalsMax, kGlobal), - weak_globals_lock("JNI weak global reference table"), + weak_globals_lock(Mutex::Create("JNI weak global reference table lock")), weak_globals(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal) { } diff --git a/src/jni_internal.h b/src/jni_internal.h index 74366d3eea..1a4235d118 100644 --- a/src/jni_internal.h +++ b/src/jni_internal.h @@ -5,19 +5,19 @@ #include "jni.h" -#include "assembler.h" #include "indirect_reference_table.h" #include "macros.h" #include "reference_table.h" -#include "thread.h" #include <map> #include <string> namespace art { +class Mutex; class Runtime; class SharedLibrary; +class Thread; struct JavaVMExt { JavaVMExt(Runtime* runtime, bool check_jni, bool verbose_jni); @@ -53,11 +53,11 @@ struct JavaVMExt { ReferenceTable pin_table; // JNI global references. - Mutex globals_lock; + Mutex* globals_lock; IndirectReferenceTable globals; // JNI weak global references. - Mutex weak_globals_lock; + Mutex* weak_globals_lock; IndirectReferenceTable weak_globals; std::map<std::string, SharedLibrary*> libraries; diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc index 4fa60c53da..9957565da3 100644 --- a/src/jni_internal_test.cc +++ b/src/jni_internal_test.cc @@ -242,6 +242,117 @@ TEST_F(JniInternalTest, SetObjectArrayElement) { // TODO: check ArrayStoreException thrown for bad types. } +TEST_F(JniInternalTest, NewLocalRef_NULL) { + EXPECT_TRUE(env_->NewLocalRef(NULL) == NULL); +} + +TEST_F(JniInternalTest, NewLocalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + jobject o = env_->NewLocalRef(s); + EXPECT_TRUE(o != NULL); + EXPECT_TRUE(o != s); + + // TODO: check that o is a local reference. +} + +TEST_F(JniInternalTest, DeleteLocalRef_NULL) { + env_->DeleteLocalRef(NULL); +} + +TEST_F(JniInternalTest, DeleteLocalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + env_->DeleteLocalRef(s); + + // Currently, deleting an already-deleted reference is just a warning. + env_->DeleteLocalRef(s); + + s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + jobject o = env_->NewLocalRef(s); + ASSERT_TRUE(o != NULL); + + env_->DeleteLocalRef(s); + env_->DeleteLocalRef(o); +} + +TEST_F(JniInternalTest, NewGlobalRef_NULL) { + EXPECT_TRUE(env_->NewGlobalRef(NULL) == NULL); +} + +TEST_F(JniInternalTest, NewGlobalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + jobject o = env_->NewGlobalRef(s); + EXPECT_TRUE(o != NULL); + EXPECT_TRUE(o != s); + + // TODO: check that o is a global reference. +} + +TEST_F(JniInternalTest, DeleteGlobalRef_NULL) { + env_->DeleteGlobalRef(NULL); +} + +TEST_F(JniInternalTest, DeleteGlobalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + + jobject o = env_->NewGlobalRef(s); + ASSERT_TRUE(o != NULL); + env_->DeleteGlobalRef(o); + + // Currently, deleting an already-deleted reference is just a warning. + env_->DeleteGlobalRef(o); + + jobject o1 = env_->NewGlobalRef(s); + ASSERT_TRUE(o1 != NULL); + jobject o2 = env_->NewGlobalRef(s); + ASSERT_TRUE(o2 != NULL); + + env_->DeleteGlobalRef(o1); + env_->DeleteGlobalRef(o2); +} + +TEST_F(JniInternalTest, NewWeakGlobalRef_NULL) { + EXPECT_TRUE(env_->NewWeakGlobalRef(NULL) == NULL); +} + +TEST_F(JniInternalTest, NewWeakGlobalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + jobject o = env_->NewWeakGlobalRef(s); + EXPECT_TRUE(o != NULL); + EXPECT_TRUE(o != s); + + // TODO: check that o is a weak global reference. +} + +TEST_F(JniInternalTest, DeleteWeakGlobalRef_NULL) { + env_->DeleteWeakGlobalRef(NULL); +} + +TEST_F(JniInternalTest, DeleteWeakGlobalRef) { + jstring s = env_->NewStringUTF(""); + ASSERT_TRUE(s != NULL); + + jobject o = env_->NewWeakGlobalRef(s); + ASSERT_TRUE(o != NULL); + env_->DeleteWeakGlobalRef(o); + + // Currently, deleting an already-deleted reference is just a warning. + env_->DeleteWeakGlobalRef(o); + + jobject o1 = env_->NewWeakGlobalRef(s); + ASSERT_TRUE(o1 != NULL); + jobject o2 = env_->NewWeakGlobalRef(s); + ASSERT_TRUE(o2 != NULL); + + env_->DeleteWeakGlobalRef(o1); + env_->DeleteWeakGlobalRef(o2); +} + bool EnsureInvokeStub(Method* method); byte* AllocateCode(void* code, size_t length) { diff --git a/src/runtime.cc b/src/runtime.cc index 335396d2ae..864b257c3c 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7,6 +7,7 @@ #include <limits> #include <vector> +#include "JniConstants.h" #include "class_linker.h" #include "heap.h" #include "jni_internal.h" @@ -312,7 +313,12 @@ Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) { // Most JNI libraries can just use System.loadLibrary, but you can't // if you're the library that implements System.loadLibrary! + Thread* self = Thread::Current(); + Thread::State old_state = self->GetState(); + self->SetState(Thread::kNative); + JniConstants::init(self->GetJniEnv()); LoadJniLibrary(instance_->GetJavaVM(), "javacore"); + self->SetState(old_state); return instance_; } diff --git a/src/thread.h b/src/thread.h index 71fbd48cb9..054a4cdff3 100644 --- a/src/thread.h +++ b/src/thread.h @@ -41,11 +41,11 @@ class Mutex { static Mutex* Create(const char* name); public: // TODO: protected - explicit Mutex(const char* name) : name_(name), owner_(NULL) {} - void SetOwner(Thread* thread) { owner_ = thread; } private: + explicit Mutex(const char* name) : name_(name), owner_(NULL) {} + const char* name_; Thread* owner_; |