summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--compiler/common_compiler_test.h7
-rw-r--r--compiler/dex/compiler_ir.h1
-rw-r--r--compiler/dex/frontend.cc2
-rw-r--r--compiler/dex/quick/codegen_util.cc30
-rw-r--r--compiler/driver/compiler_driver.cc9
-rw-r--r--compiler/driver/compiler_driver.h2
-rw-r--r--compiler/image_writer.cc19
-rw-r--r--compiler/image_writer.h5
-rw-r--r--compiler/oat_test.cc2
-rw-r--r--compiler/oat_writer.cc5
-rw-r--r--compiler/oat_writer.h2
-rw-r--r--runtime/arch/arm/entrypoints_init_arm.cc4
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S2
-rw-r--r--runtime/arch/mips/entrypoints_init_mips.cc4
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S2
-rw-r--r--runtime/arch/x86/entrypoints_init_x86.cc4
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S5
-rw-r--r--runtime/arch/x86_64/entrypoints_init_x86_64.cc4
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S6
-rw-r--r--runtime/class_linker.cc15
-rw-r--r--runtime/class_linker.h5
-rw-r--r--runtime/entrypoints/entrypoint_utils.h9
-rw-r--r--runtime/entrypoints/quick/quick_entrypoints.h1
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc9
-rw-r--r--runtime/oat.cc26
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/thread.cc1
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