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/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index d034b79..3bdc95e 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -203,8 +203,11 @@
       method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
     } else {
       // No code? You must mean to go into the interpreter.
-      const void* method_code = kUsePortableCompiler ? GetPortableToInterpreterBridge()
-                                                     : GetQuickToInterpreterBridge();
+      // Or the generic JNI...
+      const void* method_code = method->IsNative() ? GetQuickGenericJniTrampoline()
+                                                   : (kUsePortableCompiler
+                                                        ? GetPortableToInterpreterBridge()
+                                                        : GetQuickToInterpreterBridge());
       OatFile::OatMethod oat_method = CreateOatMethod(method_code,
                                                       kStackAlignment,
                                                       0,
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index b9a26d6..ee88041 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -63,6 +63,7 @@
   bool verbose;
   const CompilerBackend* compiler_backend;
   InstructionSet instruction_set;
+  bool target64;
 
   InstructionSetFeatures GetInstructionSetFeatures() {
     return compiler_driver->GetInstructionSetFeatures();
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 2619258..b55b471 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -148,7 +148,9 @@
   cu.compiler_driver = &driver;
   cu.class_linker = class_linker;
   cu.instruction_set = driver.GetInstructionSet();
+  cu.target64 = cu.instruction_set == kX86_64;
   cu.compiler_backend = compiler_backend;
+  // TODO: x86_64 is not yet implemented.
   DCHECK((cu.instruction_set == kThumb2) ||
          (cu.instruction_set == kX86) ||
          (cu.instruction_set == kMips));
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index db7bdc8..eb6f9d1 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -374,21 +374,21 @@
   return AddWordData(constant_list_p, val_lo);
 }
 
-static void PushWord(std::vector<uint8_t>&buf, int data) {
+static void Push32(std::vector<uint8_t>&buf, int data) {
   buf.push_back(data & 0xff);
   buf.push_back((data >> 8) & 0xff);
   buf.push_back((data >> 16) & 0xff);
   buf.push_back((data >> 24) & 0xff);
 }
 
-// Push 8 bytes on 64-bit systems; 4 on 32-bit systems.
-static void PushPointer(std::vector<uint8_t>&buf, void const* pointer) {
-  uintptr_t data = reinterpret_cast<uintptr_t>(pointer);
-  if (sizeof(void*) == sizeof(uint64_t)) {
-    PushWord(buf, (data >> (sizeof(void*) * 4)) & 0xFFFFFFFF);
-    PushWord(buf, data & 0xFFFFFFFF);
+// Push 8 bytes on 64-bit target systems; 4 on 32-bit target systems.
+static void PushPointer(std::vector<uint8_t>&buf, const void* pointer, bool target64) {
+  uint64_t data = reinterpret_cast<uintptr_t>(pointer);
+  if (target64) {
+    Push32(buf, data & 0xFFFFFFFF);
+    Push32(buf, (data >> 32) & 0xFFFFFFFF);
   } else {
-    PushWord(buf, data);
+    Push32(buf, static_cast<uint32_t>(data));
   }
 }
 
@@ -403,7 +403,7 @@
   AlignBuffer(code_buffer_, data_offset_);
   LIR* data_lir = literal_list_;
   while (data_lir != NULL) {
-    PushWord(code_buffer_, data_lir->operands[0]);
+    Push32(code_buffer_, data_lir->operands[0]);
     data_lir = NEXT_LIR(data_lir);
   }
   // Push code and method literals, record offsets for the compiler to patch.
@@ -419,7 +419,7 @@
                                        code_buffer_.size());
     const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target);
     // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &id);
+    PushPointer(code_buffer_, &id, cu_->target64);
     data_lir = NEXT_LIR(data_lir);
   }
   data_lir = method_literal_list_;
@@ -434,7 +434,7 @@
                                          code_buffer_.size());
     const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target);
     // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &id);
+    PushPointer(code_buffer_, &id, cu_->target64);
     data_lir = NEXT_LIR(data_lir);
   }
   // Push class literals.
@@ -448,7 +448,7 @@
                                         code_buffer_.size());
     const DexFile::TypeId& id = cu_->dex_file->GetTypeId(target);
     // unique value based on target to ensure code deduplication works
-    PushPointer(code_buffer_, &id);
+    PushPointer(code_buffer_, &id, cu_->target64);
     data_lir = NEXT_LIR(data_lir);
   }
 }
@@ -492,8 +492,8 @@
                     << std::hex << keys[elems] << ", disp: 0x"
                     << std::hex << disp;
         }
-        PushWord(code_buffer_, keys[elems]);
-        PushWord(code_buffer_,
+        Push32(code_buffer_, keys[elems]);
+        Push32(code_buffer_,
           tab_rec->targets[elems]->offset - bx_offset);
       }
     } else {
@@ -505,7 +505,7 @@
           LOG(INFO) << "  Case[" << elems << "] disp: 0x"
                     << std::hex << disp;
         }
-        PushWord(code_buffer_, tab_rec->targets[elems]->offset - bx_offset);
+        Push32(code_buffer_, tab_rec->targets[elems]->offset - bx_offset);
       }
     }
   }
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 501ea7c..fc22add 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -440,6 +440,11 @@
                           PORTABLE_ENTRYPOINT_OFFSET(pPortableToInterpreterBridge));
 }
 
+const std::vector<uint8_t>* CompilerDriver::CreateQuickGenericJniTrampoline() const {
+  return CreateTrampoline(instruction_set_, kQuickAbi,
+                          QUICK_ENTRYPOINT_OFFSET(pQuickGenericJniTrampoline));
+}
+
 const std::vector<uint8_t>* CompilerDriver::CreateQuickImtConflictTrampoline() const {
   return CreateTrampoline(instruction_set_, kQuickAbi,
                           QUICK_ENTRYPOINT_OFFSET(pQuickImtConflictTrampoline));
@@ -1920,8 +1925,12 @@
   uint64_t start_ns = NanoTime();
 
   if ((access_flags & kAccNative) != 0) {
+#if defined(__x86_64__)
+    // leaving this empty will trigger the generic JNI version
+#else
     compiled_method = compiler_backend_->JniCompile(*this, access_flags, method_idx, dex_file);
     CHECK(compiled_method != NULL);
+#endif
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     MethodReference method_ref(&dex_file, method_idx);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 57c2908..80a6796 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -164,6 +164,8 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreatePortableToInterpreterBridge() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateQuickGenericJniTrampoline() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreateQuickImtConflictTrampoline() const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index aa16885..964cfe9 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -104,6 +104,8 @@
   portable_to_interpreter_bridge_offset_ =
       oat_file_->GetOatHeader().GetPortableToInterpreterBridgeOffset();
 
+  quick_generic_jni_trampoline_offset_ =
+      oat_file_->GetOatHeader().GetQuickGenericJniTrampolineOffset();
   quick_imt_conflict_trampoline_offset_ =
       oat_file_->GetOatHeader().GetQuickImtConflictTrampolineOffset();
   quick_resolution_trampoline_offset_ =
@@ -638,7 +640,12 @@
       if (quick_code != nullptr) {
         copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(quick_code);
       } else {
-        copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
+        if (orig->IsNative() && !orig->IsStatic()) {
+          // non-static native method missing compiled code, use generic JNI version
+          copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_generic_jni_trampoline_offset_));
+        } else {
+          copy->SetEntryPointFromQuickCompiledCode<kVerifyNone>(GetOatAddress(quick_resolution_trampoline_offset_));
+        }
       }
       const byte* portable_code = GetOatAddress(orig->GetPortableOatCodeOffset());
       if (portable_code != nullptr) {
@@ -807,6 +814,12 @@
       uintptr_t value = quick_code - patch_location + patch->RelativeOffset();
       SetPatchLocation(patch, value);
     } else {
+      // generic JNI, not interpreter bridge from GetQuickOatCodeFor().
+      if (target->IsNative() &&
+          quick_code == reinterpret_cast<uintptr_t>(GetQuickToInterpreterBridge())) {
+        code_offset = quick_generic_jni_trampoline_offset_;
+      }
+
       SetPatchLocation(patch, PointerToLowMemUInt32(GetOatAddress(code_offset)));
     }
   }
@@ -845,7 +858,7 @@
     if (patch->IsCall()) {
       const CompilerDriver::CallPatchInformation* cpatch = patch->AsCall();
       const DexFile::MethodId& id = cpatch->GetDexFile().GetMethodId(cpatch->GetTargetMethodIdx());
-      uintptr_t expected = reinterpret_cast<uintptr_t>(&id);
+      uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF;
       uint32_t actual = *patch_location;
       CHECK(actual == expected || actual == value) << std::hex
           << "actual=" << actual
@@ -855,7 +868,7 @@
     if (patch->IsType()) {
       const CompilerDriver::TypePatchInformation* tpatch = patch->AsType();
       const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx());
-      uintptr_t expected = reinterpret_cast<uintptr_t>(&id);
+      uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF;
       uint32_t actual = *patch_location;
       CHECK(actual == expected || actual == value) << std::hex
           << "actual=" << actual
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index a1504ee..dff33ba 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -41,8 +41,8 @@
       : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
         oat_data_begin_(NULL), interpreter_to_interpreter_bridge_offset_(0),
         interpreter_to_compiled_code_bridge_offset_(0), portable_imt_conflict_trampoline_offset_(0),
-        portable_resolution_trampoline_offset_(0), quick_imt_conflict_trampoline_offset_(0),
-        quick_resolution_trampoline_offset_(0) {}
+        portable_resolution_trampoline_offset_(0), quick_generic_jni_trampoline_offset_(0),
+        quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0) {}
 
   ~ImageWriter() {}
 
@@ -195,6 +195,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/compiler/oat_test.cc b/compiler/oat_test.cc
index 6dbba9f..93c3502 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -175,7 +175,7 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(76U, sizeof(OatHeader));
+  EXPECT_EQ(80U, sizeof(OatHeader));
   EXPECT_EQ(28U, sizeof(OatMethodOffsets));
 }
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a400bdd..181240e 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -60,6 +60,7 @@
     size_portable_imt_conflict_trampoline_(0),
     size_portable_resolution_trampoline_(0),
     size_portable_to_interpreter_bridge_(0),
+    size_quick_generic_jni_trampoline_(0),
     size_quick_imt_conflict_trampoline_(0),
     size_quick_resolution_trampoline_(0),
     size_quick_to_interpreter_bridge_(0),
@@ -256,6 +257,7 @@
     DO_TRAMPOLINE(portable_imt_conflict_trampoline_, PortableImtConflictTrampoline);
     DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline);
     DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge);
+    DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
@@ -268,6 +270,7 @@
     oat_header_->SetPortableImtConflictTrampolineOffset(0);
     oat_header_->SetPortableResolutionTrampolineOffset(0);
     oat_header_->SetPortableToInterpreterBridgeOffset(0);
+    oat_header_->SetQuickGenericJniTrampolineOffset(0);
     oat_header_->SetQuickImtConflictTrampolineOffset(0);
     oat_header_->SetQuickResolutionTrampolineOffset(0);
     oat_header_->SetQuickToInterpreterBridgeOffset(0);
@@ -576,6 +579,7 @@
     DO_STAT(size_portable_imt_conflict_trampoline_);
     DO_STAT(size_portable_resolution_trampoline_);
     DO_STAT(size_portable_to_interpreter_bridge_);
+    DO_STAT(size_quick_generic_jni_trampoline_);
     DO_STAT(size_quick_imt_conflict_trampoline_);
     DO_STAT(size_quick_resolution_trampoline_);
     DO_STAT(size_quick_to_interpreter_bridge_);
@@ -675,6 +679,7 @@
     DO_TRAMPOLINE(portable_imt_conflict_trampoline_);
     DO_TRAMPOLINE(portable_resolution_trampoline_);
     DO_TRAMPOLINE(portable_to_interpreter_bridge_);
+    DO_TRAMPOLINE(quick_generic_jni_trampoline_);
     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
     DO_TRAMPOLINE(quick_resolution_trampoline_);
     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 3d4b48a..bab1a26 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -243,6 +243,7 @@
   UniquePtr<const std::vector<uint8_t> > portable_imt_conflict_trampoline_;
   UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_;
   UniquePtr<const std::vector<uint8_t> > portable_to_interpreter_bridge_;
+  UniquePtr<const std::vector<uint8_t> > quick_generic_jni_trampoline_;
   UniquePtr<const std::vector<uint8_t> > quick_imt_conflict_trampoline_;
   UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_;
   UniquePtr<const std::vector<uint8_t> > quick_to_interpreter_bridge_;
@@ -259,6 +260,7 @@
   uint32_t size_portable_imt_conflict_trampoline_;
   uint32_t size_portable_resolution_trampoline_;
   uint32_t size_portable_to_interpreter_bridge_;
+  uint32_t size_quick_generic_jni_trampoline_;
   uint32_t size_quick_imt_conflict_trampoline_;
   uint32_t size_quick_resolution_trampoline_;
   uint32_t size_quick_to_interpreter_bridge_;