diff options
27 files changed, 156 insertions, 29 deletions
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index d034b7922e..3bdc95ea54 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -203,8 +203,11 @@ class CommonCompilerTest : public CommonRuntimeTest { 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 b9a26d6dbb..ee880417ac 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -63,6 +63,7 @@ struct CompilationUnit { 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 26192589e1..b55b4715eb 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -148,7 +148,9 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, 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 db7bdc84e8..eb6f9d1f7e 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -374,21 +374,21 @@ LIR* Mir2Lir::AddWideData(LIR* *constant_list_p, int val_lo, int val_hi) { 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 @@ void Mir2Lir::InstallLiteralPools() { 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 @@ void Mir2Lir::InstallLiteralPools() { 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 @@ void Mir2Lir::InstallLiteralPools() { 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 @@ void Mir2Lir::InstallLiteralPools() { 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 @@ void Mir2Lir::InstallSwitchTables() { << 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 @@ void Mir2Lir::InstallSwitchTables() { 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 501ea7c130..fc22addbf1 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -440,6 +440,11 @@ const std::vector<uint8_t>* CompilerDriver::CreatePortableToInterpreterBridge() 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 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t 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 57c2908bfa..80a6796a4e 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -164,6 +164,8 @@ class CompilerDriver { 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 aa16885039..964cfe99b2 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -104,6 +104,8 @@ bool ImageWriter::Write(const std::string& image_filename, 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 @@ void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) { 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 @@ void ImageWriter::PatchOatCodeAndMethods() { 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 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch 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 @@ void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch 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 a1504eeca8..dff33bad1e 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -41,8 +41,8 @@ class ImageWriter { : 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 @@ class ImageWriter { 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 6dbba9fddd..93c35022f2 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -175,7 +175,7 @@ TEST_F(OatTest, WriteRead) { 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 a400bdde6c..181240ead3 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -60,6 +60,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, 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 @@ size_t OatWriter::InitOatCode(size_t offset) { 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 @@ size_t OatWriter::InitOatCode(size_t offset) { 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 @@ bool OatWriter::Write(OutputStream* out) { 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 @@ size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) { 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 3d4b48ae42..bab1a26d44 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -243,6 +243,7 @@ class OatWriter { 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 @@ class OatWriter { 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_; diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 5166d29096..fc85ae370c 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_no_such_method(int32_t method_idx); 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 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, 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 ed8bc13fc5..71dcd7f7a6 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -939,6 +939,8 @@ ENTRY art_quick_resolution_trampoline 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 e1b441ac9d..41d79c2743 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_no_such_method(int32_t method_idx); 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 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, 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 d23be47804..c3ae5630d4 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -1007,6 +1007,8 @@ ENTRY art_quick_resolution_trampoline 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 888310ac51..763cbde705 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_no_such_method(int32_t method_idx); 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 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, 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 8683a56855..b24bfd586b 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -1170,6 +1170,11 @@ DEFINE_FUNCTION art_quick_resolution_trampoline 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 589c7d9dc9..fe298c837c 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_no_such_method(int32_t method_idx); 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 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, 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 ac238f0d50..32e8434a6c 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_proxy_invoke_handler 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 87323f91e7..6550532f3b 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -184,7 +184,8 @@ ClassLinker::ClassLinker(InternTable* intern_table) 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 @@ void ClassLinker::InitFromImage() { 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 @@ static bool NeedsInterpreter(mirror::ArtMethod* method, const void* quick_code, 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 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { 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 88dbb9c44e..e31a6cdcf0 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -351,6 +351,10 @@ class ClassLinker { 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 @@ class ClassLinker { 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 2ced942240..a8fb6c14a1 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -733,6 +733,11 @@ static inline const void* GetQuickToInterpreterBridge() { 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 @@ static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linke 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 011e92693e..5c3b8243ff 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -87,6 +87,7 @@ struct PACKED(4) QuickEntryPoints { 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 5339b5ea1f..ef40be825a 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -817,4 +817,13 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, 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 945cd77703..c8eb3e27ae 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 @@ OatHeader::OatHeader(InstructionSet instruction_set, 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 @@ void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) { 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 de840b5870..2851f5c14d 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -70,6 +70,9 @@ class PACKED(4) OatHeader { 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 @@ class PACKED(4) OatHeader { 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 4fe9169f9b..3862ae2520 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1752,6 +1752,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { 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 |