Global lock levels.

Introduce the notion of the mutators/GC being a shared-exclusive (aka
reader-writer) lock. Introduce globally ordered locks, analysable by
annotalysis, statically at compile time. Add locking attributes to
methods.

More subtly, remove the heap_lock_ and split between various locks that
are held for smaller periods (where work doesn't get blocked). Remove
buggy Dalvik style thread transitions. Make GC use CMS in all cases when
concurrent is enabled. Fix bug where suspend counts rather than debug
suspend counts were sent to JDWP. Move the PathClassLoader to
WellKnownClasses. In debugger refactor calls to send request and
possibly suspend. Break apart different VmWait thread states. Move
identity hash code to a shared method.

Change-Id: Icdbfc3ce3fcccd14341860ac7305d8e97b51f5c6
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index 37454fd..1aa069e 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -60,8 +60,17 @@
 extern "C" void art_handle_fill_data_from_code(void*, void*);
 
 // JNI entrypoints.
-extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
 extern void* FindNativeMethod(Thread* thread);
+extern uint32_t JniMethodStart(Thread* self);
+extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self);
+extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self);
+extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
+                                     Thread* self);
+extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
+                                         Thread* self);
+extern Object* JniMethodEndWithReferenceSynchronized(jobject result,
+                                                     uint32_t saved_local_ref_cookie,
+                                                     jobject locked, Thread* self);
 
 // Lock entrypoints.
 extern "C" void art_lock_object_from_code(void*);
@@ -182,8 +191,13 @@
   points->pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
 
   // JNI
-  points->pDecodeJObjectInThread = DecodeJObjectInThread;
   points->pFindNativeMethod = FindNativeMethod;
+  points->pJniMethodStart = JniMethodStart;
+  points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
+  points->pJniMethodEnd = JniMethodEnd;
+  points->pJniMethodEndSynchronized = JniMethodEndSynchronized;
+  points->pJniMethodEndWithReference = JniMethodEndWithReference;
+  points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
 
   // Locks
   points->pLockObjectFromCode = art_lock_object_from_code;
diff --git a/src/oat/runtime/arm/stub_arm.cc b/src/oat/runtime/arm/stub_arm.cc
index 5a20748..d3c94a8 100644
--- a/src/oat/runtime/arm/stub_arm.cc
+++ b/src/oat/runtime/arm/stub_arm.cc
@@ -17,6 +17,7 @@
 #include "jni_internal.h"
 #include "oat/utils/arm/assembler_arm.h"
 #include "oat/runtime/oat_support_entrypoints.h"
+#include "oat/runtime/stub.h"
 #include "object.h"
 #include "stack_indirect_reference_table.h"
 
diff --git a/src/oat/runtime/callee_save_frame.h b/src/oat/runtime/callee_save_frame.h
index 1509553..14ba046 100644
--- a/src/oat/runtime/callee_save_frame.h
+++ b/src/oat/runtime/callee_save_frame.h
@@ -23,9 +23,11 @@
 
 class Method;
 
-// Place a special frame at the TOS that will save the callee saves for the given type
-static void  FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type) {
-  // Be aware the store below may well stomp on an incoming argument
+// Place a special frame at the TOS that will save the callee saves for the given type.
+static void  FinishCalleeSaveFrameSetup(Thread* self, Method** sp, Runtime::CalleeSaveType type)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
+  // Be aware the store below may well stomp on an incoming argument.
+  GlobalSynchronization::mutator_lock_->AssertSharedHeld();
   *sp = Runtime::Current()->GetCalleeSaveMethod(type);
   self->SetTopOfStack(sp, 0);
   self->VerifyStack();
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index a235e4f..39d9eab 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -72,8 +72,14 @@
   void (*pHandleFillArrayDataFromCode)(void*, void*);
 
   // JNI
-  Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
   void* (*pFindNativeMethod)(Thread* thread);
+  uint32_t (*pJniMethodStart)(Thread*);
+  uint32_t (*pJniMethodStartSynchronized)(jobject to_lock, Thread* self);
+  void (*pJniMethodEnd)(uint32_t cookie, Thread* self);
+  void (*pJniMethodEndSynchronized)(uint32_t cookie, jobject locked, Thread* self);
+  Object* (*pJniMethodEndWithReference)(jobject result, uint32_t cookie, Thread* self);
+  Object* (*pJniMethodEndWithReferenceSynchronized)(jobject result, uint32_t cookie,
+                                                    jobject locked, Thread* self);
 
   // Locks
   void (*pLockObjectFromCode)(void*);
diff --git a/src/oat/runtime/stub.h b/src/oat/runtime/stub.h
new file mode 100644
index 0000000..5d8b37d
--- /dev/null
+++ b/src/oat/runtime/stub.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
+#define ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
+
+#include "runtime.h"
+
+namespace art {
+
+namespace arm {
+  ByteArray* CreateAbstractMethodErrorStub()
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+  ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type)
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+  ByteArray* CreateJniDlsymLookupStub()
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+}
+
+namespace x86 {
+  ByteArray* CreateAbstractMethodErrorStub()
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+  ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type)
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+  ByteArray* CreateJniDlsymLookupStub()
+      SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_);
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_OAT_RUNTIME_OAT_RUNTIME_STUB_H_
diff --git a/src/oat/runtime/support_alloc.cc b/src/oat/runtime/support_alloc.cc
index d9394d2..4a03f98 100644
--- a/src/oat/runtime/support_alloc.cc
+++ b/src/oat/runtime/support_alloc.cc
@@ -20,39 +20,45 @@
 namespace art {
 
 extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
-                                          Thread* self, Method** sp) {
+                                          Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return AllocObjectFromCode(type_idx, method, self, false);
 }
 
 extern "C" Object* artAllocObjectFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
-                                                         Thread* self, Method** sp) {
+                                                         Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return AllocObjectFromCode(type_idx, method, self, true);
 }
 
 extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                        Thread* self, Method** sp) {
+                                        Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return AllocArrayFromCode(type_idx, method, component_count, self, false);
 }
 
 extern "C" Array* artAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
                                                        int32_t component_count,
-                                                       Thread* self, Method** sp) {
+                                                       Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return AllocArrayFromCode(type_idx, method, component_count, self, true);
 }
 
 extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
-                                               int32_t component_count, Thread* self, Method** sp) {
+                                               int32_t component_count, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false);
 }
 
 extern "C" Array* artCheckAndAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
                                                                int32_t component_count,
-                                                               Thread* self, Method** sp) {
+                                                               Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true);
 }
diff --git a/src/oat/runtime/support_cast.cc b/src/oat/runtime/support_cast.cc
index 139239f..ea083f1 100644
--- a/src/oat/runtime/support_cast.cc
+++ b/src/oat/runtime/support_cast.cc
@@ -20,14 +20,16 @@
 namespace art {
 
 // Assignable test for code, won't throw.  Null and equality tests already performed
-extern "C" uint32_t artIsAssignableFromCode(const Class* klass, const Class* ref_class) {
+extern "C" uint32_t artIsAssignableFromCode(const Class* klass, const Class* ref_class)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DCHECK(klass != NULL);
   DCHECK(ref_class != NULL);
   return klass->IsAssignableFrom(ref_class) ? 1 : 0;
 }
 
 // Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
-extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self, Method** sp) {
+extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DCHECK(a->IsClass()) << PrettyClass(a);
   DCHECK(b->IsClass()) << PrettyClass(b);
   if (LIKELY(b->IsAssignableFrom(a))) {
@@ -45,7 +47,8 @@
 // Tests whether 'element' can be assigned into an array of type 'array_class'.
 // Returns 0 on success and -1 if an exception is pending.
 extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* array_class,
-                                             Thread* self, Method** sp) {
+                                             Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   DCHECK(array_class != NULL);
   // element can't be NULL as we catch this is screened in runtime_support
   Class* element_class = element->GetClass();
diff --git a/src/oat/runtime/support_debug.cc b/src/oat/runtime/support_debug.cc
index ef6e0b1..9968043 100644
--- a/src/oat/runtime/support_debug.cc
+++ b/src/oat/runtime/support_debug.cc
@@ -25,13 +25,15 @@
  * method entry and offset 0 within the method, we'll use an offset of -1
  * to denote method entry.
  */
-extern "C" void artUpdateDebuggerFromCode(int32_t dex_pc, Thread* self, Method** sp) {
+extern "C" void artUpdateDebuggerFromCode(int32_t dex_pc, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp,  Runtime::kRefsAndArgs);
   Dbg::UpdateDebugger(dex_pc, self);
 }
 
 // Temporary debugging hook for compiler.
-extern void DebugMe(Method* method, uint32_t info) {
+extern void DebugMe(Method* method, uint32_t info)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   LOG(INFO) << "DebugMe";
   if (method != NULL) {
     LOG(INFO) << PrettyMethod(method);
diff --git a/src/oat/runtime/support_dexcache.cc b/src/oat/runtime/support_dexcache.cc
index 49e038d..8e7c2ad 100644
--- a/src/oat/runtime/support_dexcache.cc
+++ b/src/oat/runtime/support_dexcache.cc
@@ -20,7 +20,8 @@
 namespace art {
 
 extern "C" Class* artInitializeStaticStorageFromCode(uint32_t type_idx, const Method* referrer,
-                                                     Thread* self, Method** sp) {
+                                                     Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   // Called to ensure static storage base is initialized for direct static field reads and writes.
   // A class may be accessing another class' fields when it doesn't have access, as access has been
   // given by inheritance.
@@ -29,7 +30,8 @@
 }
 
 extern "C" Class* artInitializeTypeFromCode(uint32_t type_idx, const Method* referrer, Thread* self,
-                                            Method** sp) {
+                                            Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   // Called when method->dex_cache_resolved_types_[] misses.
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return ResolveVerifyAndClinit(type_idx, referrer, self, false, false);
@@ -37,7 +39,8 @@
 
 extern "C" Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
                                                            const Method* referrer, Thread* self,
-                                                           Method** sp) {
+                                                           Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   // Called when caller isn't guaranteed to have access to a type and the dex cache may be
   // unpopulated.
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -45,7 +48,8 @@
 }
 
 extern "C" String* artResolveStringFromCode(Method* referrer, int32_t string_idx,
-                                            Thread* self, Method** sp) {
+                                            Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   return ResolveStringFromCode(referrer, string_idx);
 }
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 77fe618..99e3a94 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -22,7 +22,8 @@
 namespace art {
 
 extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
-                                           Thread* self, Method** sp) {
+                                           Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
@@ -36,7 +37,8 @@
 }
 
 extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
-                                           Thread* self, Method** sp) {
+                                           Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
@@ -50,7 +52,8 @@
 }
 
 extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
-                                           Thread* self, Method** sp) {
+                                           Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
@@ -64,7 +67,8 @@
 }
 
 extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, Object* obj,
-                                             const Method* referrer, Thread* self, Method** sp) {
+                                             const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int32_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->Get32(obj);
@@ -82,7 +86,8 @@
 }
 
 extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, Object* obj,
-                                             const Method* referrer, Thread* self, Method** sp) {
+                                             const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, false, sizeof(int64_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->Get64(obj);
@@ -100,7 +105,8 @@
 }
 
 extern "C" Object* artGetObjInstanceFromCode(uint32_t field_idx, Object* obj,
-                                              const Method* referrer, Thread* self, Method** sp) {
+                                              const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, false, false, sizeof(Object*));
   if (LIKELY(field != NULL && obj != NULL)) {
     return field->GetObj(obj);
@@ -118,7 +124,8 @@
 }
 
 extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
-                                      const Method* referrer, Thread* self, Method** sp) {
+                                      const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
@@ -134,7 +141,8 @@
 }
 
 extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
-                                      uint64_t new_value, Thread* self, Method** sp) {
+                                      uint64_t new_value, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
@@ -150,7 +158,8 @@
 }
 
 extern "C" int artSetObjStaticFromCode(uint32_t field_idx, Object* new_value,
-                                       const Method* referrer, Thread* self, Method** sp) {
+                                       const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
@@ -168,7 +177,8 @@
 }
 
 extern "C" int artSet32InstanceFromCode(uint32_t field_idx, Object* obj, uint32_t new_value,
-                                        const Method* referrer, Thread* self, Method** sp) {
+                                        const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int32_t));
   if (LIKELY(field != NULL && obj != NULL)) {
     field->Set32(obj, new_value);
@@ -188,7 +198,8 @@
 }
 
 extern "C" int artSet64InstanceFromCode(uint32_t field_idx, Object* obj, uint64_t new_value,
-                                        Thread* self, Method** sp) {
+                                        Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Method* callee_save = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsOnly);
   Method* referrer = sp[callee_save->GetFrameSizeInBytes() / sizeof(Method*)];
   Field* field = FindFieldFast(field_idx, referrer, true, true, sizeof(int64_t));
@@ -211,7 +222,8 @@
 }
 
 extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, Object* obj, Object* new_value,
-                                         const Method* referrer, Thread* self, Method** sp) {
+                                         const Method* referrer, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Field* field = FindFieldFast(field_idx, referrer, false, true, sizeof(Object*));
   if (LIKELY(field != NULL && obj != NULL)) {
     field->SetObj(obj, new_value);
diff --git a/src/oat/runtime/support_fillarray.cc b/src/oat/runtime/support_fillarray.cc
index 7227f6b..8561bd8 100644
--- a/src/oat/runtime/support_fillarray.cc
+++ b/src/oat/runtime/support_fillarray.cc
@@ -37,7 +37,8 @@
  */
 extern "C" int artHandleFillArrayDataFromCode(Array* array,
                                               const Instruction::ArrayDataPayload* payload,
-                                              Thread* self, Method** sp) {
+                                              Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   DCHECK_EQ(payload->ident, static_cast<uint16_t>(Instruction::kArrayDataSignature));
   if (UNLIKELY(array == NULL)) {
diff --git a/src/oat/runtime/support_invoke.cc b/src/oat/runtime/support_invoke.cc
index 4669688..9c7b3a2 100644
--- a/src/oat/runtime/support_invoke.cc
+++ b/src/oat/runtime/support_invoke.cc
@@ -20,7 +20,8 @@
 namespace art {
 
 static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
-                                Thread* self, Method** sp, bool access_check, InvokeType type) {
+                                Thread* self, Method** sp, bool access_check, InvokeType type)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
   if (UNLIKELY(method == NULL)) {
     FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
@@ -54,14 +55,16 @@
 // See comments in runtime_support_asm.S
 extern "C" uint64_t artInvokeInterfaceTrampoline(uint32_t method_idx, Object* this_object,
                                                  Method* caller_method, Thread* self,
-                                                 Method** sp) {
+                                                 Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, kInterface);
 }
 
 extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
                                                                 Object* this_object,
                                                                 Method* caller_method, Thread* self,
-                                                                Method** sp) {
+                                                                Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface);
 }
 
@@ -69,28 +72,32 @@
 extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
                                                              Object* this_object,
                                                              Method* caller_method, Thread* self,
-                                                             Method** sp) {
+                                                             Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect);
 }
 
 extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
                                                             Object* this_object,
                                                             Method* caller_method, Thread* self,
-                                                            Method** sp) {
+                                                            Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic);
 }
 
 extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
                                                             Object* this_object,
                                                             Method* caller_method, Thread* self,
-                                                            Method** sp) {
+                                                            Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper);
 }
 
 extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
                                                               Object* this_object,
                                                               Method* caller_method, Thread* self,
-                                                              Method** sp) {
+                                                              Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual);
 }
 
diff --git a/src/oat/runtime/support_jni.cc b/src/oat/runtime/support_jni.cc
index cfa1a11..bbff673 100644
--- a/src/oat/runtime/support_jni.cc
+++ b/src/oat/runtime/support_jni.cc
@@ -16,20 +16,23 @@
 
 #include "object.h"
 #include "object_utils.h"
+#include "scoped_thread_state_change.h"
 #include "thread.h"
 
 namespace art {
 
 // Used by the JNI dlsym stub to find the native method to invoke if none is registered.
-extern void* FindNativeMethod(Thread* self) {
+extern void* FindNativeMethod(Thread* self) LOCKS_EXCLUDED(GlobalSynchronization::mutator_lock_) {
+  GlobalSynchronization::mutator_lock_->AssertNotHeld();  // We come here as Native.
   DCHECK(Thread::Current() == self);
+  ScopedObjectAccess soa(self);
 
-  Method* method = const_cast<Method*>(self->GetCurrentMethod());
+  Method* method = self->GetCurrentMethod();
   DCHECK(method != NULL);
 
   // Lookup symbol address for method, on failure we'll return NULL with an
   // exception set, otherwise we return the address of the method we found.
-  void* native_code = self->GetJniEnv()->vm->FindCodeForNativeMethod(method);
+  void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
   if (native_code == NULL) {
     DCHECK(self->IsExceptionPending());
     return NULL;
@@ -40,23 +43,61 @@
   }
 }
 
-// Return value helper for jobject return types, used for JNI return values.
-extern Object* DecodeJObjectInThread(Thread* self, jobject java_object) {
-  if (self->IsExceptionPending()) {
-    return NULL;
-  }
-  Object* o = self->DecodeJObject(java_object);
-  if (o == NULL || !self->GetJniEnv()->check_jni) {
-    return o;
-  }
+// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
+extern uint32_t JniMethodStart(Thread* self) UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) {
+  JNIEnvExt* env = self->GetJniEnv();
+  uint32_t saved_local_ref_cookie = env->local_ref_cookie;
+  env->local_ref_cookie = env->locals.GetSegmentState();
+  self->TransitionFromRunnableToSuspended(kNative);
+  return saved_local_ref_cookie;
+}
 
+extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
+    UNLOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
+  self->DecodeJObject(to_lock)->MonitorEnter(self);
+  return JniMethodStart(self);
+}
+
+static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
+  JNIEnvExt* env = self->GetJniEnv();
+  env->locals.SetSegmentState(env->local_ref_cookie);
+  env->local_ref_cookie = saved_local_ref_cookie;
+  self->PopSirt();
+}
+
+static void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_)
+    UNLOCK_FUNCTION(monitor_lock_) {
+  // Save any pending exception over monitor exit call.
+  Throwable* saved_exception = NULL;
+  if (UNLIKELY(self->IsExceptionPending())) {
+    saved_exception = self->GetException();
+    self->ClearException();
+  }
+  // Decode locked object and unlock, before popping local references.
+  self->DecodeJObject(locked)->MonitorExit(self);
+  if (UNLIKELY(self->IsExceptionPending())) {
+    LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
+        << saved_exception->Dump()
+        << "\nEncountered second exception during implicit MonitorExit:\n"
+        << self->GetException()->Dump();
+  }
+  // Restore pending exception.
+  if (saved_exception != NULL) {
+    self->SetException(saved_exception);
+  }
+}
+
+static void CheckReferenceResult(Object* o, Thread* self)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
+  if (o == NULL) {
+    return;
+  }
   if (o == kInvalidIndirectRefObject) {
     JniAbortF(NULL, "invalid reference returned from %s",
               PrettyMethod(self->GetCurrentMethod()).c_str());
   }
-
-  // Make sure that the result is an instance of the type this
-  // method was expected to return.
+  // Make sure that the result is an instance of the type this method was expected to return.
   Method* m = self->GetCurrentMethod();
   MethodHelper mh(m);
   Class* return_type = mh.GetReturnType();
@@ -65,7 +106,53 @@
     JniAbortF(NULL, "attempt to return an instance of %s from %s",
               PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
   }
+}
 
+extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
+    SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
+  self->TransitionFromSuspendedToRunnable();
+  PopLocalReferences(saved_local_ref_cookie, self);
+}
+
+
+extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, Thread* self)
+    SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
+  self->TransitionFromSuspendedToRunnable();
+  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
+  PopLocalReferences(saved_local_ref_cookie, self);
+}
+
+extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
+                                         Thread* self)
+    SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
+  self->TransitionFromSuspendedToRunnable();
+  Object* o = self->DecodeJObject(result);  // Must decode before pop.
+  PopLocalReferences(saved_local_ref_cookie, self);
+  // Process result.
+  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
+    if (self->IsExceptionPending()) {
+      return NULL;
+    }
+    CheckReferenceResult(o, self);
+  }
+  return o;
+}
+
+extern Object* JniMethodEndWithReferenceSynchronized(jobject result,
+                                                     uint32_t saved_local_ref_cookie,
+                                                     jobject locked, Thread* self)
+    SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
+  self->TransitionFromSuspendedToRunnable();
+  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
+  Object* o = self->DecodeJObject(result);
+  PopLocalReferences(saved_local_ref_cookie, self);
+  // Process result.
+  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
+    if (self->IsExceptionPending()) {
+      return NULL;
+    }
+    CheckReferenceResult(o, self);
+  }
   return o;
 }
 
@@ -77,7 +164,8 @@
   *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
 }
 
-extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) {
+extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_){
   DCHECK(Thread::Current() == self);
   // TODO: this code is specific to ARM
   // On entry the stack pointed by sp is:
diff --git a/src/oat/runtime/support_locks.cc b/src/oat/runtime/support_locks.cc
index 30fc567..9d44e55 100644
--- a/src/oat/runtime/support_locks.cc
+++ b/src/oat/runtime/support_locks.cc
@@ -19,14 +19,16 @@
 
 namespace art {
 
-extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp) {
+extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp)
+    UNLOCK_FUNCTION(monitor_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   DCHECK(obj != NULL);  // Assumed to have been checked before entry
   // MonitorExit may throw exception
   return obj->MonitorExit(self) ? 0 /* Success */ : -1 /* Failure */;
 }
 
-extern "C" void artLockObjectFromCode(Object* obj, Thread* thread, Method** sp) {
+extern "C" void artLockObjectFromCode(Object* obj, Thread* thread, Method** sp)
+    EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
   DCHECK(obj != NULL);        // Assumed to have been checked before entry
   obj->MonitorEnter(thread);  // May block
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index 83d2265..972779d 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -18,7 +18,7 @@
 #include "object_utils.h"
 #include "reflection.h"
 #include "runtime_support.h"
-#include "scoped_jni_thread_state.h"
+#include "scoped_thread_state_change.h"
 #include "thread.h"
 #include "well_known_classes.h"
 
@@ -43,7 +43,8 @@
 // reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
 // the invocation handler which is a field within the proxy object receiver.
 extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
-                                      Thread* self, byte* stack_args) {
+                                      Thread* self, byte* stack_args)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   // Register the top of the managed stack
   Method** proxy_sp = reinterpret_cast<Method**>(stack_args - SP_OFFSET_IN_BYTES);
   DCHECK_EQ(*proxy_sp, proxy_method);
@@ -51,11 +52,11 @@
   DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
   // Start new JNI local reference state
   JNIEnvExt* env = self->GetJniEnv();
-  ScopedJniThreadState ts(env);
+  ScopedObjectAccessUnchecked soa(env);
   ScopedJniEnvLocalRefState env_state(env);
   // Create local ref. copies of proxy method and the receiver
-  jobject rcvr_jobj = ts.AddLocalReference<jobject>(receiver);
-  jobject proxy_method_jobj = ts.AddLocalReference<jobject>(proxy_method);
+  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
+  jobject proxy_method_jobj = soa.AddLocalReference<jobject>(proxy_method);
 
   // Placing into local references incoming arguments from the caller's register arguments,
   // replacing original Object* with jobject
@@ -74,7 +75,7 @@
   while (cur_arg < args_in_regs && param_index < num_params) {
     if (proxy_mh.IsParamAReference(param_index)) {
       Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = ts.AddLocalReference<jobject>(obj);
+      jobject jobj = soa.AddLocalReference<jobject>(obj);
       *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
     cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
@@ -85,7 +86,7 @@
   while (param_index < num_params) {
     if (proxy_mh.IsParamAReference(param_index)) {
       Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
-      jobject jobj = ts.AddLocalReference<jobject>(obj);
+      jobject jobj = soa.AddLocalReference<jobject>(obj);
       *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
     }
     cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
@@ -104,13 +105,13 @@
       CHECK(self->IsExceptionPending());
       return;
     }
-    args_jobj[2].l = ts.AddLocalReference<jobjectArray>(args);
+    args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
   }
   // Convert proxy method into expected interface method
   Method* interface_method = proxy_method->FindOverriddenMethod();
   DCHECK(interface_method != NULL);
   DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
-  args_jobj[1].l = ts.AddLocalReference<jobject>(interface_method);
+  args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
   // Box arguments
   cur_arg = 0;  // reset stack location to read to start
   // reset index, will index into param type array which doesn't include the receiver
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index 3f6bc8f..013f885 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -23,7 +23,7 @@
 #if defined(ART_USE_LLVM_COMPILER)
 #include "nth_caller_visitor.h"
 #endif
-#include "scoped_jni_thread_state.h"
+#include "scoped_thread_state_change.h"
 
 // Architecture specific assembler helper to deliver exception.
 extern "C" void art_deliver_exception_from_code(void*);
@@ -33,7 +33,8 @@
 #if !defined(ART_USE_LLVM_COMPILER)
 // Lazily resolve a method. Called by stub code.
 const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp, Thread* thread,
-                                                     Runtime::TrampolineType type) {
+                                                     Runtime::TrampolineType type)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
 #if defined(__arm__)
   // On entry the stack pointed by sp is:
   // | argN       |  |
@@ -82,7 +83,7 @@
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
   // Start new JNI local reference state
   JNIEnvExt* env = thread->GetJniEnv();
-  ScopedJniThreadState ts(env);
+  ScopedObjectAccessUnchecked soa(env);
   ScopedJniEnvLocalRefState env_state(env);
 
   // Compute details about the called method (avoid GCs)
@@ -147,7 +148,7 @@
       // If we thought we had fewer than 3 arguments in registers, account for the receiver
       args_in_regs++;
     }
-    ts.AddLocalReference<jobject>(obj);
+    soa.AddLocalReference<jobject>(obj);
   }
   size_t shorty_index = 1;  // skip return value
   // Iterate while arguments and arguments in registers (less 1 from cur_arg which is offset to skip
@@ -157,7 +158,7 @@
     shorty_index++;
     if (c == 'L') {
       Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
-      ts.AddLocalReference<jobject>(obj);
+      soa.AddLocalReference<jobject>(obj);
     }
     cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
   }
@@ -168,7 +169,7 @@
     shorty_index++;
     if (c == 'L') {
       Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
-      ts.AddLocalReference<jobject>(obj);
+      soa.AddLocalReference<jobject>(obj);
     }
     cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
   }
@@ -308,7 +309,8 @@
 
 #if !defined(ART_USE_LLVM_COMPILER)
 // Called by the AbstractMethodError. Called by stub code.
-extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
+extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
   thread->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
                              "abstract method \"%s\"", PrettyMethod(method).c_str());
diff --git a/src/oat/runtime/support_thread.cc b/src/oat/runtime/support_thread.cc
index 6cd595b..32284bb 100644
--- a/src/oat/runtime/support_thread.cc
+++ b/src/oat/runtime/support_thread.cc
@@ -20,15 +20,18 @@
 
 namespace art {
 
-void CheckSuspendFromCode(Thread* thread) {
-  // Called when thread->suspend_count_ != 0
-  Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
+void CheckSuspendFromCode(Thread* thread)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
+  // Called when thread->suspend_count_ != 0 on JNI return. JNI method acts as callee-save frame.
+  thread->VerifyStack();
+  thread->FullSuspendCheck();
 }
 
-extern "C" void artTestSuspendFromCode(Thread* thread, Method** sp) {
+extern "C" void artTestSuspendFromCode(Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   // Called when suspend count check value is 0 and thread->suspend_count_ != 0
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly);
-  Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
+  thread->FullSuspendCheck();
 }
 
 }  // namespace art
diff --git a/src/oat/runtime/support_throw.cc b/src/oat/runtime/support_throw.cc
index 31cf7d9..4fa2387 100644
--- a/src/oat/runtime/support_throw.cc
+++ b/src/oat/runtime/support_throw.cc
@@ -23,13 +23,15 @@
 namespace art {
 
 // Deliver an exception that's pending on thread helping set up a callee save frame on the way.
-extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
+extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
   thread->DeliverException();
 }
 
 // Called by generated call to throw an exception.
-extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
+extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   /*
    * exception may be NULL, in which case this routine should
    * throw NPE.  NOTE: this is a convenience for generated code,
@@ -47,7 +49,8 @@
 }
 
 // Called by generated call to throw a NPE exception.
-extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) {
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
   uint32_t dex_pc;
   Method* throw_method = self->GetCurrentMethod(&dex_pc);
@@ -56,21 +59,24 @@
 }
 
 // Called by generated call to throw an arithmetic divide by zero exception.
-extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
+extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
   thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
   thread->DeliverException();
 }
 
 // Called by generated call to throw an array index out of bounds exception.
-extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
+extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
   thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
                              "length=%d; index=%d", limit, index);
   thread->DeliverException();
 }
 
-extern "C" void artThrowStackOverflowFromCode(Thread* thread, Method** sp) {
+extern "C" void artThrowStackOverflowFromCode(Thread* thread, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll);
   // Remove extra entry pushed onto second stack during method tracing.
   if (Runtime::Current()->IsMethodTracingActive()) {
@@ -83,7 +89,8 @@
   thread->DeliverException();
 }
 
-extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp) {
+extern "C" void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self, Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
   Method* method = self->GetCurrentMethod();
   self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
@@ -91,7 +98,9 @@
   self->DeliverException();
 }
 
-extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self, Method** sp) {
+extern "C" void artThrowVerificationErrorFromCode(int32_t kind, int32_t ref, Thread* self,
+                                                  Method** sp)
+    SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
   Method* method = self->GetCurrentMethod();
   ThrowVerificationError(self, method, kind, ref);
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index a28a898..e52569d 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -59,8 +59,17 @@
 extern "C" void art_handle_fill_data_from_code(void*, void*);
 
 // JNI entrypoints.
-extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
 extern void* FindNativeMethod(Thread* thread);
+extern uint32_t JniMethodStart(Thread* self);
+extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self);
+extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self);
+extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
+                                     Thread* self);
+extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
+                                         Thread* self);
+extern Object* JniMethodEndWithReferenceSynchronized(jobject result,
+                                                     uint32_t saved_local_ref_cookie,
+                                                     jobject locked, Thread* self);
 
 // Lock entrypoints.
 extern "C" void art_lock_object_from_code(void*);
@@ -153,8 +162,13 @@
   points->pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
 
   // JNI
-  points->pDecodeJObjectInThread = DecodeJObjectInThread;
   points->pFindNativeMethod = FindNativeMethod;
+  points->pJniMethodStart = JniMethodStart;
+  points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
+  points->pJniMethodEnd = JniMethodEnd;
+  points->pJniMethodEndSynchronized = JniMethodEndSynchronized;
+  points->pJniMethodEndWithReference = JniMethodEndWithReference;
+  points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
 
   // Locks
   points->pLockObjectFromCode = art_lock_object_from_code;
diff --git a/src/oat/runtime/x86/stub_x86.cc b/src/oat/runtime/x86/stub_x86.cc
index a9db314..74e0f39 100644
--- a/src/oat/runtime/x86/stub_x86.cc
+++ b/src/oat/runtime/x86/stub_x86.cc
@@ -16,6 +16,7 @@
 
 #include "jni_internal.h"
 #include "oat/runtime/oat_support_entrypoints.h"
+#include "oat/runtime/stub.h"
 #include "oat/utils/x86/assembler_x86.h"
 #include "object.h"
 #include "stack_indirect_reference_table.h"