Initialize the rest of libcore's native code.
This native code requires NewGlobalRef, so this patch also implements
NewLocalRef/DeleteLocalRef, NewGlobalRef/DeleteGlobalRef, and
NewWeakGlobalRef/DeleteWeakGlobalRef.
(The assembler change is because "math.h" also defines OVERFLOW. A slight
change in #include ordering caused the names to conflict.)
Change-Id: Ifbf3b532ec3b0896bd7507d2881c6b77b64f01e7
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
index 693f1b4..78a20c0 100644
--- a/src/assembler_x86.cc
+++ b/src/assembler_x86.cc
@@ -1560,7 +1560,7 @@
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 @@
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 @@
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 @@
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 @@
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 391d078..36019ae 100644
--- a/src/constants_x86.h
+++ b/src/constants_x86.h
@@ -73,29 +73,28 @@
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,
+ 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,
- ZERO = EQUAL,
- NOT_ZERO = NOT_EQUAL,
- NEGATIVE = SIGN,
- POSITIVE = NOT_SIGN
+ kZero = kEqual,
+ kNotZero = kNotEqual,
+ kNegative = kSign,
+ kPositive = kNotSign
};
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 599b0fe..c538670 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 @@
};
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 @@
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 @@
}
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 @@
// 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 @@
{
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 @@
{
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 @@
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";
+ }
+}
+
+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 @@
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 @@
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 @@
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 74366d3..1a4235d 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 @@
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 4fa60c5..9957565 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -242,6 +242,117 @@
// 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 335396d..864b257 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 @@
// 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 71fbd48c..054a4cd 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -41,11 +41,11 @@
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_;