diff options
author | Andreas Gampe <agampe@google.com> | 2014-02-27 12:26:20 -0800 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-03-03 23:27:12 +0000 |
commit | 2da882315a61072664f7ce3c212307342e907207 (patch) | |
tree | 67d777be044f5b60e2f13ab7968b63c581904ea9 | |
parent | 762d4e5b9e777ae64c4ba581af9c84b78a5e96a6 (diff) | |
download | art-2da882315a61072664f7ce3c212307342e907207.zip art-2da882315a61072664f7ce3c212307342e907207.tar.gz art-2da882315a61072664f7ce3c212307342e907207.tar.bz2 |
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
27 files changed, 156 insertions, 29 deletions
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 @@ 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 b9a26d6..ee88041 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 2619258..b55b471 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 db7bdc8..eb6f9d1 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 501ea7c..fc22add 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 57c2908..80a6796 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 aa16885..964cfe9 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 a1504ee..dff33ba 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 6dbba9f..93c3502 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 a400bdd..181240e 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 3d4b48a..bab1a26 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 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_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 ed8bc13..71dcd7f 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 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_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 d23be47..c3ae563 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 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_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 8683a56..b24bfd5 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 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_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 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_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 87323f9..6550532 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 88dbb9c..e31a6cd 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 2ced942..a8fb6c1 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 011e926..5c3b824 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 5339b5e..ef40be8 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 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 @@ 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 de840b5..2851f5c 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 4fe9169..3862ae2 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 |