diff options
author | 2019-11-06 17:09:30 +0000 | |
---|---|---|
committer | 2019-11-27 10:02:22 +0000 | |
commit | 7dac864d7eae3d731eeacf55cfc7f71b4df6cee3 (patch) | |
tree | 9f27bb1c0b6f076c2dd1b721441200f9f7a78022 | |
parent | 047081a1509762879a9eb51981982af65f419bac (diff) |
Clean up JNI dlsym lookup trampoline.
Make sure the GenericJniTrampoline recognizes the trampoline
in primary boot image oat file. Rename that trampoline, add
a test and flag some issues in the code.
Test: New test 178-app-image-native-method.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: testrunner.py --host -t 178-app-image-native-method
Bug: 112189621
Change-Id: I8f8cd11998af536fd3842dd4183a25f0367655a6
-rw-r--r-- | dex2oat/driver/compiler_driver.cc | 2 | ||||
-rw-r--r-- | dex2oat/driver/compiler_driver.h | 2 | ||||
-rw-r--r-- | dex2oat/linker/image_writer.cc | 10 | ||||
-rw-r--r-- | dex2oat/linker/image_writer.h | 2 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 10 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 4 | ||||
-rw-r--r-- | imgdiag/imgdiag.cc | 4 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 6 | ||||
-rw-r--r-- | runtime/class_linker.cc | 12 | ||||
-rw-r--r-- | runtime/class_linker.h | 1 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 8 | ||||
-rw-r--r-- | runtime/oat.cc | 20 | ||||
-rw-r--r-- | runtime/oat.h | 8 | ||||
-rwxr-xr-x | test/178-app-image-native-method/check | 18 | ||||
-rw-r--r-- | test/178-app-image-native-method/expected.txt | 6 | ||||
-rw-r--r-- | test/178-app-image-native-method/info.txt | 1 | ||||
-rw-r--r-- | test/178-app-image-native-method/native_methods.cc | 118 | ||||
-rw-r--r-- | test/178-app-image-native-method/profile | 8 | ||||
-rw-r--r-- | test/178-app-image-native-method/run | 25 | ||||
-rw-r--r-- | test/178-app-image-native-method/src/Main.java | 254 | ||||
-rw-r--r-- | test/Android.bp | 1 |
21 files changed, 482 insertions, 38 deletions
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc index 99895b14a3..ae73f49508 100644 --- a/dex2oat/driver/compiler_driver.cc +++ b/dex2oat/driver/compiler_driver.cc @@ -294,7 +294,7 @@ CompilerDriver::~CompilerDriver() { type ## _ENTRYPOINT_OFFSET(PointerSize::k32, offset)); \ } -std::unique_ptr<const std::vector<uint8_t>> CompilerDriver::CreateJniDlsymLookup() const { +std::unique_ptr<const std::vector<uint8_t>> CompilerDriver::CreateJniDlsymLookupTrampoline() const { CREATE_TRAMPOLINE(JNI, kJniAbi, pDlsymLookup) } diff --git a/dex2oat/driver/compiler_driver.h b/dex2oat/driver/compiler_driver.h index b474de5f8d..4aeb34de90 100644 --- a/dex2oat/driver/compiler_driver.h +++ b/dex2oat/driver/compiler_driver.h @@ -121,7 +121,7 @@ class CompilerDriver { } // Generate the trampolines that are invoked by unresolved direct methods. - std::unique_ptr<const std::vector<uint8_t>> CreateJniDlsymLookup() const; + std::unique_ptr<const std::vector<uint8_t>> CreateJniDlsymLookupTrampoline() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickGenericJniTrampoline() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickImtConflictTrampoline() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const; diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 13f22d92e8..3d998c9e3e 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -3355,8 +3355,8 @@ const uint8_t* ImageWriter::GetOatAddress(StubType type) const { // TODO: We could maybe clean this up if we stored them in an array in the oat header. case StubType::kQuickGenericJNITrampoline: return static_cast<const uint8_t*>(header.GetQuickGenericJniTrampoline()); - case StubType::kJNIDlsymLookup: - return static_cast<const uint8_t*>(header.GetJniDlsymLookup()); + case StubType::kJNIDlsymLookupTrampoline: + return static_cast<const uint8_t*>(header.GetJniDlsymLookupTrampoline()); case StubType::kQuickIMTConflictTrampoline: return static_cast<const uint8_t*>(header.GetQuickImtConflictTrampoline()); case StubType::kQuickResolutionTrampoline: @@ -3471,7 +3471,7 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, // The native method's pointer is set to a stub to lookup via dlsym. // Note this is not the code_ pointer, that is handled above. copy->SetEntryPointFromJniPtrSize( - GetOatAddress(StubType::kJNIDlsymLookup), target_ptr_size_); + GetOatAddress(StubType::kJNIDlsymLookupTrampoline), target_ptr_size_); } else { CHECK(copy->GetDataPtrSize(target_ptr_size_) == nullptr); } @@ -3606,8 +3606,8 @@ void ImageWriter::UpdateOatFileHeader(size_t oat_index, const OatHeader& oat_hea if (oat_index == GetDefaultOatIndex()) { // Primary oat file, read the trampolines. - cur_image_info.SetStubOffset(StubType::kJNIDlsymLookup, - oat_header.GetJniDlsymLookupOffset()); + cur_image_info.SetStubOffset(StubType::kJNIDlsymLookupTrampoline, + oat_header.GetJniDlsymLookupTrampolineOffset()); cur_image_info.SetStubOffset(StubType::kQuickGenericJNITrampoline, oat_header.GetQuickGenericJniTrampolineOffset()); cur_image_info.SetStubOffset(StubType::kQuickIMTConflictTrampoline, diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index b2b811f541..22b7739b8b 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -233,7 +233,7 @@ class ImageWriter final { friend std::ostream& operator<<(std::ostream& stream, const NativeObjectRelocationType& type); enum class StubType { - kJNIDlsymLookup, + kJNIDlsymLookupTrampoline, kQuickGenericJNITrampoline, kQuickIMTConflictTrampoline, kQuickResolutionTrampoline, diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 92de151416..d75f427639 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -416,7 +416,7 @@ OatWriter::OatWriter(const CompilerOptions& compiler_options, size_quickening_info_alignment_(0), size_interpreter_to_interpreter_bridge_(0), size_interpreter_to_compiled_code_bridge_(0), - size_jni_dlsym_lookup_(0), + size_jni_dlsym_lookup_trampoline_(0), size_quick_generic_jni_trampoline_(0), size_quick_imt_conflict_trampoline_(0), size_quick_resolution_trampoline_(0), @@ -2207,7 +2207,7 @@ size_t OatWriter::InitOatCode(size_t offset) { } \ offset += (field)->size(); - DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup); + DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_, JniDlsymLookupTrampoline); DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline); DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline); DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline); @@ -2215,7 +2215,7 @@ size_t OatWriter::InitOatCode(size_t offset) { #undef DO_TRAMPOLINE } else { - oat_header_->SetJniDlsymLookupOffset(0); + oat_header_->SetJniDlsymLookupTrampolineOffset(0); oat_header_->SetQuickGenericJniTrampolineOffset(0); oat_header_->SetQuickImtConflictTrampolineOffset(0); oat_header_->SetQuickResolutionTrampolineOffset(0); @@ -2754,7 +2754,7 @@ bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relat DO_STAT(size_quickening_info_alignment_); DO_STAT(size_interpreter_to_interpreter_bridge_); DO_STAT(size_interpreter_to_compiled_code_bridge_); - DO_STAT(size_jni_dlsym_lookup_); + DO_STAT(size_jni_dlsym_lookup_trampoline_); DO_STAT(size_quick_generic_jni_trampoline_); DO_STAT(size_quick_imt_conflict_trampoline_); DO_STAT(size_quick_resolution_trampoline_); @@ -3085,7 +3085,7 @@ size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relati DCHECK_OFFSET(); \ } while (false) - DO_TRAMPOLINE(jni_dlsym_lookup_); + DO_TRAMPOLINE(jni_dlsym_lookup_trampoline_); DO_TRAMPOLINE(quick_generic_jni_trampoline_); DO_TRAMPOLINE(quick_imt_conflict_trampoline_); DO_TRAMPOLINE(quick_resolution_trampoline_); diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index 19c0cfefa2..5015ec3156 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -474,7 +474,7 @@ class OatWriter { dchecked_vector<OatDexFile> oat_dex_files_; dchecked_vector<OatClassHeader> oat_class_headers_; dchecked_vector<OatClass> oat_classes_; - std::unique_ptr<const std::vector<uint8_t>> jni_dlsym_lookup_; + std::unique_ptr<const std::vector<uint8_t>> jni_dlsym_lookup_trampoline_; std::unique_ptr<const std::vector<uint8_t>> quick_generic_jni_trampoline_; std::unique_ptr<const std::vector<uint8_t>> quick_imt_conflict_trampoline_; std::unique_ptr<const std::vector<uint8_t>> quick_resolution_trampoline_; @@ -494,7 +494,7 @@ class OatWriter { uint32_t size_quickening_info_alignment_; uint32_t size_interpreter_to_interpreter_bridge_; uint32_t size_interpreter_to_compiled_code_bridge_; - uint32_t size_jni_dlsym_lookup_; + uint32_t size_jni_dlsym_lookup_trampoline_; uint32_t size_quick_generic_jni_trampoline_; uint32_t size_quick_imt_conflict_trampoline_; uint32_t size_quick_resolution_trampoline_; diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index bc63ab1235..10f4015015 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -849,9 +849,9 @@ class RegionSpecializedBase<ArtMethod> : public RegionCommon<ArtMethod> { std::vector<const OatFile*> boot_oat_files = oat_file_manager.GetBootOatFiles(); for (const OatFile* oat_file : boot_oat_files) { const OatHeader& oat_header = oat_file->GetOatHeader(); - const void* jdl = oat_header.GetJniDlsymLookup(); + const void* jdl = oat_header.GetJniDlsymLookupTrampoline(); if (jdl != nullptr) { - entry_point_names_[jdl] = "JniDlsymLookup (from boot oat file)"; + entry_point_names_[jdl] = "JniDlsymLookupTrampoline (from boot oat file)"; } const void* qgjt = oat_header.GetQuickGenericJniTrampoline(); if (qgjt != nullptr) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 5679a7c2d5..95f085c627 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -195,7 +195,7 @@ class OatSymbolizer final { info.code_size = 0; /* The symbol lasts until the next symbol. */ \ method_debug_infos_.push_back(std::move(info)); \ } - DO_TRAMPOLINE(JniDlsymLookup); + DO_TRAMPOLINE(JniDlsymLookupTrampoline); DO_TRAMPOLINE(QuickGenericJniTrampoline); DO_TRAMPOLINE(QuickImtConflictTrampoline); DO_TRAMPOLINE(QuickResolutionTrampoline); @@ -445,8 +445,8 @@ class OatDumper { os << StringPrintf("\n\n"); DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset); - DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP", - GetJniDlsymLookupOffset); + DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP TRAMPOLINE", + GetJniDlsymLookupTrampolineOffset); DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE", GetQuickGenericJniTrampolineOffset); DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE", diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 438d5cb709..3f904f3546 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -611,6 +611,7 @@ ClassLinker::ClassLinker(InternTable* intern_table, bool fast_class_not_found_ex log_new_roots_(false), intern_table_(intern_table), fast_class_not_found_exceptions_(fast_class_not_found_exceptions), + jni_dlsym_lookup_trampoline_(nullptr), quick_resolution_trampoline_(nullptr), quick_imt_conflict_trampoline_(nullptr), quick_generic_jni_trampoline_(nullptr), @@ -834,8 +835,10 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); if (!runtime->IsAotCompiler()) { // We need to set up the generic trampolines since we don't have an image. + jni_dlsym_lookup_trampoline_ = GetJniDlsymLookupStub(); quick_resolution_trampoline_ = GetQuickResolutionStub(); quick_imt_conflict_trampoline_ = GetQuickImtConflictStub(); + quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); quick_to_interpreter_bridge_trampoline_ = GetQuickToInterpreterBridge(); } @@ -1183,6 +1186,7 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { runtime->GetOatFileManager().RegisterImageOatFiles(spaces); DCHECK(!oat_files.empty()); const OatHeader& default_oat_header = oat_files[0]->GetOatHeader(); + jni_dlsym_lookup_trampoline_ = default_oat_header.GetJniDlsymLookupTrampoline(); quick_resolution_trampoline_ = default_oat_header.GetQuickResolutionTrampoline(); quick_imt_conflict_trampoline_ = default_oat_header.GetQuickImtConflictTrampoline(); quick_generic_jni_trampoline_ = default_oat_header.GetQuickGenericJniTrampoline(); @@ -1191,6 +1195,8 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { // Check that the other images use the same trampoline. for (size_t i = 1; i < oat_files.size(); ++i) { const OatHeader& ith_oat_header = oat_files[i]->GetOatHeader(); + const void* ith_jni_dlsym_lookup_trampoline_ = + ith_oat_header.GetJniDlsymLookupTrampoline(); const void* ith_quick_resolution_trampoline = ith_oat_header.GetQuickResolutionTrampoline(); const void* ith_quick_imt_conflict_trampoline = @@ -1199,7 +1205,8 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { ith_oat_header.GetQuickGenericJniTrampoline(); const void* ith_quick_to_interpreter_bridge_trampoline = ith_oat_header.GetQuickToInterpreterBridge(); - if (ith_quick_resolution_trampoline != quick_resolution_trampoline_ || + if (ith_jni_dlsym_lookup_trampoline_ != jni_dlsym_lookup_trampoline_ || + ith_quick_resolution_trampoline != quick_resolution_trampoline_ || ith_quick_imt_conflict_trampoline != quick_imt_conflict_trampoline_ || ith_quick_generic_jni_trampoline != quick_generic_jni_trampoline_ || ith_quick_to_interpreter_bridge_trampoline != quick_to_interpreter_bridge_trampoline_) { @@ -9506,7 +9513,8 @@ bool ClassLinker::IsQuickGenericJniStub(const void* entry_point) const { } bool ClassLinker::IsJniDlsymLookupStub(const void* entry_point) const { - return entry_point == GetJniDlsymLookupStub(); + return entry_point == GetJniDlsymLookupStub() || + (jni_dlsym_lookup_trampoline_ == entry_point); } const void* ClassLinker::GetRuntimeQuickGenericJniStub() const { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index a1ba461270..877b9647aa 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -1404,6 +1404,7 @@ class ClassLinker { // Trampolines within the image the bounce to runtime entrypoints. Done so that there is a single // patch point within the image. TODO: make these proper relocations. + const void* jni_dlsym_lookup_trampoline_; const void* quick_resolution_trampoline_; const void* quick_imt_conflict_trampoline_; const void* quick_generic_jni_trampoline_; diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 6a52d24f38..1cc4d24b58 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -2389,7 +2389,7 @@ extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** // Ensure static method's class is initialized. StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(declaring_class)); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { + if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { DCHECK(Thread::Current()->IsExceptionPending()) << called->PrettyMethod(); self->PopHandleScope(); // A negative value denotes an error. @@ -2432,7 +2432,11 @@ extern "C" TwoWordReturn artQuickGenericJniTrampoline(Thread* self, ArtMethod** // In the second case, we need to execute the binding and continue with the actual native function // pointer. DCHECK(nativeCode != nullptr); - if (nativeCode == GetJniDlsymLookupStub()) { + if (runtime->GetClassLinker()->IsJniDlsymLookupStub(nativeCode)) { + // FIXME: This is broken for @FastNative and @CriticalNative as we're still runnable. + // Calls from compiled stubs are also broken. + // TODO: We could just let the GenericJNI stub call the ArtFindNativeMethod() + // rather than calling it explicitly here. nativeCode = artFindNativeMethod(self); if (nativeCode == nullptr) { diff --git a/runtime/oat.cc b/runtime/oat.cc index 3fceec9364..bc52ec0f55 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -72,7 +72,7 @@ OatHeader::OatHeader(InstructionSet instruction_set, dex_file_count_(dex_file_count), oat_dex_files_offset_(0), executable_offset_(0), - jni_dlsym_lookup_offset_(0), + jni_dlsym_lookup_trampoline_offset_(0), quick_generic_jni_trampoline_offset_(0), quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0), @@ -200,20 +200,20 @@ static const void* GetTrampoline(const OatHeader& header, uint32_t offset) { return (offset != 0u) ? reinterpret_cast<const uint8_t*>(&header) + offset : nullptr; } -const void* OatHeader::GetJniDlsymLookup() const { - return GetTrampoline(*this, GetJniDlsymLookupOffset()); +const void* OatHeader::GetJniDlsymLookupTrampoline() const { + return GetTrampoline(*this, GetJniDlsymLookupTrampolineOffset()); } -uint32_t OatHeader::GetJniDlsymLookupOffset() const { +uint32_t OatHeader::GetJniDlsymLookupTrampolineOffset() const { DCHECK(IsValid()); - return jni_dlsym_lookup_offset_; + return jni_dlsym_lookup_trampoline_offset_; } -void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) { +void OatHeader::SetJniDlsymLookupTrampolineOffset(uint32_t offset) { DCHECK(IsValid()); - DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset; + DCHECK_EQ(jni_dlsym_lookup_trampoline_offset_, 0U) << offset; - jni_dlsym_lookup_offset_ = offset; + jni_dlsym_lookup_trampoline_offset_ = offset; } const void* OatHeader::GetQuickGenericJniTrampoline() const { @@ -222,12 +222,12 @@ const void* OatHeader::GetQuickGenericJniTrampoline() const { uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const { DCHECK(IsValid()); - CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_offset_); + CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_trampoline_offset_); return quick_generic_jni_trampoline_offset_; } void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + CHECK(offset == 0 || offset >= jni_dlsym_lookup_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset; diff --git a/runtime/oat.h b/runtime/oat.h index 352b9e892e..a3f87221e9 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -69,9 +69,9 @@ class PACKED(4) OatHeader { uint32_t GetExecutableOffset() const; void SetExecutableOffset(uint32_t executable_offset); - const void* GetJniDlsymLookup() const; - uint32_t GetJniDlsymLookupOffset() const; - void SetJniDlsymLookupOffset(uint32_t offset); + const void* GetJniDlsymLookupTrampoline() const; + uint32_t GetJniDlsymLookupTrampolineOffset() const; + void SetJniDlsymLookupTrampolineOffset(uint32_t offset); const void* GetQuickGenericJniTrampoline() const; uint32_t GetQuickGenericJniTrampolineOffset() const; @@ -122,7 +122,7 @@ class PACKED(4) OatHeader { uint32_t dex_file_count_; uint32_t oat_dex_files_offset_; uint32_t executable_offset_; - uint32_t jni_dlsym_lookup_offset_; + uint32_t jni_dlsym_lookup_trampoline_offset_; uint32_t quick_generic_jni_trampoline_offset_; uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; diff --git a/test/178-app-image-native-method/check b/test/178-app-image-native-method/check new file mode 100755 index 0000000000..53362959d8 --- /dev/null +++ b/test/178-app-image-native-method/check @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Filter out error messages for missing native methods. +grep -v 'No implementation found for ' "$2" | diff -q "$1" - >/dev/null diff --git a/test/178-app-image-native-method/expected.txt b/test/178-app-image-native-method/expected.txt new file mode 100644 index 0000000000..02384cd2d0 --- /dev/null +++ b/test/178-app-image-native-method/expected.txt @@ -0,0 +1,6 @@ +JNI_OnLoad called +test +testMissing +JNI_OnLoad called +test +testMissing diff --git a/test/178-app-image-native-method/info.txt b/test/178-app-image-native-method/info.txt new file mode 100644 index 0000000000..4cf01fe80f --- /dev/null +++ b/test/178-app-image-native-method/info.txt @@ -0,0 +1 @@ +Tests that native methods in app image using compiled stubs or Generic JNI work correctly. diff --git a/test/178-app-image-native-method/native_methods.cc b/test/178-app-image-native-method/native_methods.cc new file mode 100644 index 0000000000..5c4fb3ee82 --- /dev/null +++ b/test/178-app-image-native-method/native_methods.cc @@ -0,0 +1,118 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jni.h" + +namespace art { + +static inline bool VerifyManyParameters( + jint i1, jlong l1, jfloat f1, jdouble d1, + jint i2, jlong l2, jfloat f2, jdouble d2, + jint i3, jlong l3, jfloat f3, jdouble d3, + jint i4, jlong l4, jfloat f4, jdouble d4, + jint i5, jlong l5, jfloat f5, jdouble d5, + jint i6, jlong l6, jfloat f6, jdouble d6, + jint i7, jlong l7, jfloat f7, jdouble d7, + jint i8, jlong l8, jfloat f8, jdouble d8) { + return + (i1 == 11) && (l1 == 12) && (f1 == 13.0) && (d1 == 14.0) && + (i2 == 21) && (l2 == 22) && (f2 == 23.0) && (d2 == 24.0) && + (i3 == 31) && (l3 == 32) && (f3 == 33.0) && (d3 == 34.0) && + (i4 == 41) && (l4 == 42) && (f4 == 43.0) && (d4 == 44.0) && + (i5 == 51) && (l5 == 52) && (f5 == 53.0) && (d5 == 54.0) && + (i6 == 61) && (l6 == 62) && (f6 == 63.0) && (d6 == 64.0) && + (i7 == 71) && (l7 == 72) && (f7 == 73.0) && (d7 == 74.0) && + (i8 == 81) && (l8 == 82) && (f8 == 83.0) && (d8 == 84.0); +} + +extern "C" JNIEXPORT jint JNICALL Java_Test_nativeMethod(JNIEnv*, jclass, jint i) { + return i; +} + +extern "C" JNIEXPORT jint JNICALL Java_Test_nativeMethodWithManyParameters( + JNIEnv*, jclass, + jint i1, jlong l1, jfloat f1, jdouble d1, + jint i2, jlong l2, jfloat f2, jdouble d2, + jint i3, jlong l3, jfloat f3, jdouble d3, + jint i4, jlong l4, jfloat f4, jdouble d4, + jint i5, jlong l5, jfloat f5, jdouble d5, + jint i6, jlong l6, jfloat f6, jdouble d6, + jint i7, jlong l7, jfloat f7, jdouble d7, + jint i8, jlong l8, jfloat f8, jdouble d8) { + bool ok = VerifyManyParameters( + i1, l1, f1, d1, + i2, l2, f2, d2, + i3, l3, f3, d3, + i4, l4, f4, d4, + i5, l5, f5, d5, + i6, l6, f6, d6, + i7, l7, f7, d7, + i8, l8, f8, d8); + return ok ? 42 : -1; +} + +extern "C" JNIEXPORT jint JNICALL Java_TestFast_nativeMethod(JNIEnv*, jclass, jint i) { + return i; +} + +extern "C" JNIEXPORT jint JNICALL Java_TestFast_nativeMethodWithManyParameters( + JNIEnv*, jclass, + jint i1, jlong l1, jfloat f1, jdouble d1, + jint i2, jlong l2, jfloat f2, jdouble d2, + jint i3, jlong l3, jfloat f3, jdouble d3, + jint i4, jlong l4, jfloat f4, jdouble d4, + jint i5, jlong l5, jfloat f5, jdouble d5, + jint i6, jlong l6, jfloat f6, jdouble d6, + jint i7, jlong l7, jfloat f7, jdouble d7, + jint i8, jlong l8, jfloat f8, jdouble d8) { + bool ok = VerifyManyParameters( + i1, l1, f1, d1, + i2, l2, f2, d2, + i3, l3, f3, d3, + i4, l4, f4, d4, + i5, l5, f5, d5, + i6, l6, f6, d6, + i7, l7, f7, d7, + i8, l8, f8, d8); + return ok ? 42 : -1; +} + +extern "C" JNIEXPORT jint JNICALL Java_TestCritical_nativeMethod(jint i) { + return i; +} + +extern "C" JNIEXPORT jint JNICALL Java_TestCritical_nativeMethodWithManyParameters( + jint i1, jlong l1, jfloat f1, jdouble d1, + jint i2, jlong l2, jfloat f2, jdouble d2, + jint i3, jlong l3, jfloat f3, jdouble d3, + jint i4, jlong l4, jfloat f4, jdouble d4, + jint i5, jlong l5, jfloat f5, jdouble d5, + jint i6, jlong l6, jfloat f6, jdouble d6, + jint i7, jlong l7, jfloat f7, jdouble d7, + jint i8, jlong l8, jfloat f8, jdouble d8) { + bool ok = VerifyManyParameters( + i1, l1, f1, d1, + i2, l2, f2, d2, + i3, l3, f3, d3, + i4, l4, f4, d4, + i5, l5, f5, d5, + i6, l6, f6, d6, + i7, l7, f7, d7, + i8, l8, f8, d8); + return ok ? 42 : -1; +} + +} // namespace art diff --git a/test/178-app-image-native-method/profile b/test/178-app-image-native-method/profile new file mode 100644 index 0000000000..597dde1af9 --- /dev/null +++ b/test/178-app-image-native-method/profile @@ -0,0 +1,8 @@ +LMain; +LTest; +HSPLMain;->test()V +HSPLMain;->testFast()V +HSPLMain;->testCritical()V +HSPLMain;->testMissing()V +HSPLMain;->testMissingFast()V +HSPLMain;->testMissingCritical()V diff --git a/test/178-app-image-native-method/run b/test/178-app-image-native-method/run new file mode 100644 index 0000000000..3cb4d09d0d --- /dev/null +++ b/test/178-app-image-native-method/run @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Use a profile to put specific classes in the app image. +${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile +return_status1=$? + +# Also run with the verify filter to avoid compiling JNI stubs. +${RUN} ${@} --profile -Xcompiler-option --compiler-filter=verify +return_status2=$? + +(exit ${return_status1}) # && (exit ${return_status2}) diff --git a/test/178-app-image-native-method/src/Main.java b/test/178-app-image-native-method/src/Main.java new file mode 100644 index 0000000000..d63d11273b --- /dev/null +++ b/test/178-app-image-native-method/src/Main.java @@ -0,0 +1,254 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import dalvik.annotation.optimization.FastNative; +import dalvik.annotation.optimization.CriticalNative; + +public class Main { + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + + if (!checkAppImageLoaded()) { + System.out.println("AppImage not loaded."); + } + // To avoid going through resolution trampoline, make test classes visibly initialized. + new Test(); + new TestFast(); + new TestCritical(); + new TestMissing(); + new TestMissingFast(); + new TestMissingCritical(); + makeVisiblyInitialized(); // Make sure they are visibly initialized. + + // FIXME: @FastNative and @CriticalNative fail a state check in artFindNativeMethod(). + test(); + // testFast(); + // testCritical(); + testMissing(); + // testMissingFast(); + // testMissingCritical(); + } + + static void test() { + System.out.println("test"); + assertEquals(42, Test.nativeMethod(42)); + assertEquals(42, Test.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d)); + } + + static void testFast() { + System.out.println("testFast"); + assertEquals(42, TestFast.nativeMethod(42)); + assertEquals(42, TestFast.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d)); + } + + static void testCritical() { + System.out.println("testCritical"); + assertEquals(42, TestCritical.nativeMethod(42)); + assertEquals(42, TestCritical.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d)); + } + + static void testMissing() { + System.out.println("testMissing"); + + try { + TestMissing.nativeMethod(42); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + + try { + TestMissing.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + } + + static void testMissingFast() { + System.out.println("testMissingFast"); + + try { + TestMissingFast.nativeMethod(42); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + + try { + TestMissingFast.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + } + + static void testMissingCritical() { + System.out.println("testMissingCritical"); + + try { + TestMissingCritical.nativeMethod(42); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + + try { + TestMissingCritical.nativeMethodWithManyParameters( + 11, 12L, 13.0f, 14.0d, + 21, 22L, 23.0f, 24.0d, + 31, 32L, 33.0f, 34.0d, + 41, 42L, 43.0f, 44.0d, + 51, 52L, 53.0f, 54.0d, + 61, 62L, 63.0f, 64.0d, + 71, 72L, 73.0f, 74.0d, + 81, 82L, 83.0f, 84.0d); + throw new Error("UNREACHABLE"); + } catch (LinkageError expected) {} + } + + static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new AssertionError("Expected " + expected + " got " + actual); + } + } + + public static native boolean checkAppImageLoaded(); + public static native void makeVisiblyInitialized(); +} + +class Test { + public static native int nativeMethod(int i); + + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} + +class TestFast { + @FastNative + public static native int nativeMethod(int i); + + @FastNative + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} + +class TestCritical { + @CriticalNative + public static native int nativeMethod(int i); + + @CriticalNative + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} + +class TestMissing { + public static native int nativeMethod(int i); + + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} + +class TestMissingFast { + @FastNative + public static native int nativeMethod(int i); + + @FastNative + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} + +class TestMissingCritical { + @CriticalNative + public static native int nativeMethod(int i); + + @CriticalNative + public static native int nativeMethodWithManyParameters( + int i1, long l1, float f1, double d1, + int i2, long l2, float f2, double d2, + int i3, long l3, float f3, double d3, + int i4, long l4, float f4, double d4, + int i5, long l5, float f5, double d5, + int i6, long l6, float f6, double d6, + int i7, long l7, float f7, double d7, + int i8, long l8, float f8, double d8); +} diff --git a/test/Android.bp b/test/Android.bp index f10d3788bf..de2ab3f5bb 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -543,6 +543,7 @@ cc_defaults { "169-threadgroup-jni/jni_daemon_thread.cc", "172-app-image-twice/debug_print_class.cc", "177-visibly-initialized-deadlock/visibly_initialized.cc", + "178-app-image-native-method/native_methods.cc", "1945-proxy-method-arguments/get_args.cc", "203-multi-checkpoint/multi_checkpoint.cc", "305-other-fault-handler/fault_handler.cc", |