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/build/Android.libart.mk b/build/Android.libart.mk
index b71cc53..61a25b4 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -38,7 +38,7 @@
     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 3f5673c..22209ec 100644
--- a/build/Android.test.mk
+++ b/build/Android.test.mk
@@ -32,10 +32,10 @@
   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 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_;