Initial changes towards Generic JNI option

Some initial changes that lead to an UNIMPLEMENTED. Works
by not compiling for JNI right now and tracking native methods
which have neither quick nor portable code. Uses new trampoline.

Change-Id: I5448654044eb2717752fd7359f4ef8bd5c17be6e
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 5166d29..fc85ae3 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -127,6 +127,9 @@
 extern "C" void art_quick_throw_null_pointer_exception();
 extern "C" void art_quick_throw_stack_overflow(void*);
 
+// Generic JNI downcall
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+
 extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
@@ -182,6 +185,7 @@
   qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
   qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
   qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+  qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline;
 
   // Locks
   qpoints->pLockObject = art_quick_lock_object;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index ed8bc13..71dcd7f 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -939,6 +939,8 @@
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolution_trampoline
 
+UNIMPLEMENTED art_quick_generic_jni_trampoline
+
     .extern artQuickToInterpreterBridge
 ENTRY art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index e1b441a..41d79c2 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -128,6 +128,9 @@
 extern "C" void art_quick_throw_null_pointer_exception();
 extern "C" void art_quick_throw_stack_overflow(void*);
 
+// Generic JNI downcall
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+
 extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
@@ -183,6 +186,7 @@
   qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
   qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
   qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+  qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline;
 
   // Locks
   qpoints->pLockObject = art_quick_lock_object;
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index d23be47..c3ae563 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1007,6 +1007,8 @@
     DELIVER_PENDING_EXCEPTION
 END art_quick_resolution_trampoline
 
+UNIMPLEMENTED art_quick_generic_jni_trampoline
+
     .extern artQuickToInterpreterBridge
 ENTRY art_quick_to_interpreter_bridge
     GENERATE_GLOBAL_POINTER
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index 888310a..763cbde 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -109,6 +109,9 @@
 extern "C" void art_quick_throw_null_pointer_exception();
 extern "C" void art_quick_throw_stack_overflow(void*);
 
+// Generic JNI downcall
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+
 extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
@@ -164,6 +167,7 @@
   qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
   qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
   qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+  qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline;
 
   // Locks
   qpoints->pLockObject = art_quick_lock_object;
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 8683a56..b24bfd5 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1170,6 +1170,11 @@
     DELIVER_PENDING_EXCEPTION
 END_FUNCTION art_quick_resolution_trampoline
 
+DEFINE_FUNCTION art_quick_generic_jni_trampoline
+    int3
+    int3
+END_FUNCTION art_quick_generic_jni_trampoline
+
 DEFINE_FUNCTION art_quick_to_interpreter_bridge
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
     mov %esp, %edx                // remember SP
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index 589c7d9..fe298c8 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -110,6 +110,9 @@
 extern "C" void art_quick_throw_null_pointer_exception();
 extern "C" void art_quick_throw_stack_overflow(void*);
 
+// Generic JNI entrypoint
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+
 extern void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints);
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
@@ -165,6 +168,7 @@
   qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
   qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
   qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+  qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline;
 
   // Locks
   qpoints->pLockObject = art_quick_lock_object;
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index ac238f0..32e8434 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -635,6 +635,12 @@
 UNIMPLEMENTED art_quick_imt_conflict_trampoline
 UNIMPLEMENTED art_quick_resolution_trampoline
 
+
+    /*
+     * Called to do a generic JNI down-call
+     */
+UNIMPLEMENTED art_quick_generic_jni_trampoline
+
     /*
      * Called to bridge from the quick to interpreter ABI. On entry the arguments match those
      * of a quick call:
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 87323f9..6550532 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -184,7 +184,8 @@
       portable_resolution_trampoline_(nullptr),
       quick_resolution_trampoline_(nullptr),
       portable_imt_conflict_trampoline_(nullptr),
-      quick_imt_conflict_trampoline_(nullptr) {
+      quick_imt_conflict_trampoline_(nullptr),
+      quick_generic_jni_trampoline_(nullptr) {
   CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
   memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
 }
@@ -987,6 +988,7 @@
   quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline();
   portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline();
   quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
+  quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
   mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   mirror::ObjectArray<mirror::DexCache>* dex_caches =
       dex_caches_object->AsObjectArray<mirror::DexCache>();
@@ -1623,7 +1625,8 @@
                              const void* portable_code) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   if ((quick_code == nullptr) && (portable_code == nullptr)) {
     // No code: need interpreter.
-    DCHECK(!method->IsNative());
+    // May return true for native code, in the case of generic JNI
+    // DCHECK(!method->IsNative());
     return true;
   }
 #ifdef ART_SEA_IR_MODE
@@ -1678,8 +1681,14 @@
     bool have_portable_code = false;
     if (enter_interpreter) {
       // Use interpreter entry point.
+
+      // check whether the method is native, in which case it's generic JNI
       portable_code = GetPortableToInterpreterBridge();
-      quick_code = GetQuickToInterpreterBridge();
+      if (quick_code == nullptr && portable_code == nullptr && method->IsNative()) {
+        quick_code = GetQuickGenericJniTrampoline();
+      } else {
+        quick_code = GetQuickToInterpreterBridge();
+      }
     } else {
       if (portable_code == nullptr) {
         portable_code = GetPortableToQuickBridge();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 88dbb9c..e31a6cd 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -351,6 +351,10 @@
     return portable_resolution_trampoline_;
   }
 
+  const void* GetQuickGenericJniTrampoline() const {
+      return quick_generic_jni_trampoline_;
+    }
+
   const void* GetQuickResolutionTrampoline() const {
     return quick_resolution_trampoline_;
   }
@@ -643,6 +647,7 @@
   const void* quick_resolution_trampoline_;
   const void* portable_imt_conflict_trampoline_;
   const void* quick_imt_conflict_trampoline_;
+  const void* quick_generic_jni_trampoline_;
 
   friend class ImageWriter;  // for GetClassRoots
   FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 2ced942..a8fb6c1 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -733,6 +733,11 @@
   return reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
 }
 
+extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+static inline const void* GetQuickGenericJniTrampoline() {
+  return reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+}
+
 static inline const void* GetQuickToPortableBridge() {
   // TODO: quick to portable bridge. Bug: 8196384
   return GetQuickToInterpreterBridge();
@@ -754,6 +759,10 @@
   return class_linker->GetQuickImtConflictTrampoline();
 }
 
+static inline const void* GetQuickGenericJniTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetQuickGenericJniTrampoline();
+}
+
 extern "C" void art_portable_proxy_invoke_handler();
 static inline const void* GetPortableProxyInvokeHandler() {
   return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h
index 011e926..5c3b824 100644
--- a/runtime/entrypoints/quick/quick_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_entrypoints.h
@@ -87,6 +87,7 @@
   mirror::Object* (*pJniMethodEndWithReference)(jobject result, uint32_t cookie, Thread* self);
   mirror::Object* (*pJniMethodEndWithReferenceSynchronized)(jobject result, uint32_t cookie,
                                                     jobject locked, Thread* self);
+  void (*pQuickGenericJniTrampoline)(mirror::ArtMethod*);
 
   // Locks
   void (*pLockObject)(void*);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 5339b5e..ef40be8 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -817,4 +817,13 @@
   return code;
 }
 
+extern "C" const void* artQuickGenericJniTrampoline(mirror::ArtMethod* called,
+                                                    mirror::Object* receiver,
+                                                    Thread* thread, mirror::ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  LOG(FATAL) << "artQuickGenericJniTrampoline not implemented: "
+      << PrettyMethod(called);
+  return NULL;
+}
+
 }  // namespace art
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 945cd77..c8eb3e2 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '1', '5', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '6', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
@@ -67,6 +67,7 @@
   portable_imt_conflict_trampoline_offset_ = 0;
   portable_resolution_trampoline_offset_ = 0;
   portable_to_interpreter_bridge_offset_ = 0;
+  quick_generic_jni_trampoline_offset_ = 0;
   quick_imt_conflict_trampoline_offset_ = 0;
   quick_resolution_trampoline_offset_ = 0;
   quick_to_interpreter_bridge_offset_ = 0;
@@ -239,18 +240,37 @@
   UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
 }
 
+const void* OatHeader::GetQuickGenericJniTrampoline() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetQuickGenericJniTrampolineOffset();
+}
+
+uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(quick_generic_jni_trampoline_offset_, portable_to_interpreter_bridge_offset_);
+  return quick_generic_jni_trampoline_offset_;
+}
+
+void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
+
+  quick_generic_jni_trampoline_offset_ = offset;
+  UpdateChecksum(&quick_generic_jni_trampoline_offset_, sizeof(offset));
+}
+
 const void* OatHeader::GetQuickImtConflictTrampoline() const {
   return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
 }
 
 uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
   DCHECK(IsValid());
-  CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_);
+  CHECK_GE(quick_imt_conflict_trampoline_offset_, quick_generic_jni_trampoline_offset_);
   return quick_imt_conflict_trampoline_offset_;
 }
 
 void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
-  CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
+  CHECK(offset == 0 || offset >= quick_generic_jni_trampoline_offset_);
   DCHECK(IsValid());
   DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
 
diff --git a/runtime/oat.h b/runtime/oat.h
index de840b5..2851f5c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -70,6 +70,9 @@
   uint32_t GetPortableToInterpreterBridgeOffset() const;
   void SetPortableToInterpreterBridgeOffset(uint32_t offset);
 
+  const void* GetQuickGenericJniTrampoline() const;
+  uint32_t GetQuickGenericJniTrampolineOffset() const;
+  void SetQuickGenericJniTrampolineOffset(uint32_t offset);
   const void* GetQuickResolutionTrampoline() const;
   uint32_t GetQuickResolutionTrampolineOffset() const;
   void SetQuickResolutionTrampolineOffset(uint32_t offset);
@@ -103,6 +106,7 @@
   uint32_t portable_imt_conflict_trampoline_offset_;
   uint32_t portable_resolution_trampoline_offset_;
   uint32_t portable_to_interpreter_bridge_offset_;
+  uint32_t quick_generic_jni_trampoline_offset_;
   uint32_t quick_imt_conflict_trampoline_offset_;
   uint32_t quick_resolution_trampoline_offset_;
   uint32_t quick_to_interpreter_bridge_offset_;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 4fe9169..3862ae2 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1752,6 +1752,7 @@
   QUICK_ENTRY_POINT_INFO(pThrowNoSuchMethod),
   QUICK_ENTRY_POINT_INFO(pThrowNullPointer),
   QUICK_ENTRY_POINT_INFO(pThrowStackOverflow),
+  QUICK_ENTRY_POINT_INFO(pQuickGenericJniTrampoline),
 };
 #undef QUICK_ENTRY_POINT_INFO