summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2024-03-07 17:45:56 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-03-08 11:22:13 +0000
commita6f0274f4190c196736993ce6ad9138e687df569 (patch)
treeb7c608052b56049530f0c6967d0d1053c34bac65
parent00464160ac51fb1ece69fe883fcaefb484a3932a (diff)
Revert "Reuse boot JNI stub for native methods"
This reverts commit c8b6e26aa56bb6761bb781d1095b36f84c4c65d4. Bug: 288983053 Reason for revert: Failure on luci bots. Change-Id: Ieae0f47f2114efbfcb0bc4d8ffb0868001c22653
-rw-r--r--compiler/common_compiler_test.h2
-rw-r--r--dex2oat/driver/compiler_driver.cc16
-rw-r--r--dex2oat/linker/image_writer.cc68
-rw-r--r--dex2oat/linker/image_writer.h16
-rw-r--r--libartbase/base/hash_map.h7
-rw-r--r--runtime/Android.bp2
-rw-r--r--runtime/class_linker.cc38
-rw-r--r--runtime/class_linker.h16
-rw-r--r--runtime/gc/space/image_space.cc3
-rw-r--r--runtime/oat/image-inl.h30
-rw-r--r--runtime/oat/image.cc7
-rw-r--r--runtime/oat/image.h12
-rw-r--r--runtime/oat/jni_stub_hash_map.cc355
-rw-r--r--runtime/oat/jni_stub_hash_map.h112
-rw-r--r--runtime/oat/jni_stub_hash_map_test.cc304
-rw-r--r--runtime/runtime_image.cc11
-rw-r--r--runtime/stack.cc23
-rw-r--r--test/667-jit-jni-stub/src/Main.java9
-rw-r--r--test/MyClassNatives/MyClassNatives.java119
-rw-r--r--test/common/runtime_state.cc16
20 files changed, 22 insertions, 1144 deletions
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 89f3fb40ad..9b49c93ea6 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -89,10 +89,10 @@ class EXPORT CommonCompilerTestImpl {
protected:
virtual ClassLinker* GetClassLinker() = 0;
virtual Runtime* GetRuntime() = 0;
- class OneCompiledMethodStorage;
private:
class CodeAndMetadata;
+ class OneCompiledMethodStorage;
std::vector<CodeAndMetadata> code_and_metadata_;
};
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index 39a68537e2..824319b299 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -488,18 +488,10 @@ static void CompileMethodQuick(
// Query any JNI optimization annotations such as @FastNative or @CriticalNative.
access_flags |= annotations::GetNativeMethodAnnotationAccessFlags(
dex_file, dex_file.GetClassDef(class_def_idx), method_idx);
- const void* boot_jni_stub = nullptr;
- if (!Runtime::Current()->GetHeap()->GetBootImageSpaces().empty()) {
- // Skip the compilation for native method if found an usable boot JNI stub.
- ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- std::string_view shorty = dex_file.GetMethodShortyView(dex_file.GetMethodId(method_idx));
- boot_jni_stub = class_linker->FindBootJniStub(access_flags, shorty);
- }
- if (boot_jni_stub == nullptr) {
- compiled_method =
- driver->GetCompiler()->JniCompile(access_flags, method_idx, dex_file, dex_cache);
- CHECK(compiled_method != nullptr);
- }
+
+ compiled_method = driver->GetCompiler()->JniCompile(
+ access_flags, method_idx, dex_file, dex_cache);
+ CHECK(compiled_method != nullptr);
}
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index d5ab5d3345..b663d32e2e 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -571,7 +571,6 @@ bool ImageWriter::Write(int image_fd,
for (size_t i = 0; i < oat_filenames_.size(); ++i) {
CreateHeader(i, component_count);
CopyAndFixupNativeData(i);
- CopyAndFixupJniStubMethods(i);
}
}
@@ -1464,14 +1463,6 @@ void ImageWriter::RecordNativeRelocations(ObjPtr<mirror::Class> klass, size_t oa
for (auto& m : klass->GetMethods(target_ptr_size_)) {
AssignMethodOffset(&m, type, oat_index);
}
- // Only write JNI stub methods in boot images, but not in boot image extensions and app images.
- if (compiler_options_.IsBootImage() && compiler_options_.IsJniCompilationEnabled()) {
- for (auto& m : klass->GetMethods(target_ptr_size_)) {
- if (m.IsNative() && !m.IsIntrinsic()) {
- AssignJniStubMethodOffset(&m, oat_index);
- }
- }
- }
(any_dirty ? dirty_methods_ : clean_methods_) += num_methods;
}
// Assign offsets for all runtime methods in the IMT since these may hold conflict tables
@@ -1553,20 +1544,6 @@ void ImageWriter::AssignMethodOffset(ArtMethod* method,
image_info.IncrementBinSlotSize(bin_type, ArtMethod::Size(target_ptr_size_));
}
-void ImageWriter::AssignJniStubMethodOffset(ArtMethod* method, size_t oat_index) {
- CHECK(method->IsNative());
- auto it = jni_stub_map_.find(JniStubKey(method));
- if (it == jni_stub_map_.end()) {
- ImageInfo& image_info = GetImageInfo(oat_index);
- constexpr Bin bin_type = Bin::kJniStubMethod;
- size_t offset = image_info.GetBinSlotSize(bin_type);
- jni_stub_map_.Put(std::make_pair(
- JniStubKey(method),
- std::make_pair(method, JniStubMethodRelocation{oat_index, offset})));
- image_info.IncrementBinSlotSize(bin_type, static_cast<size_t>(target_ptr_size_));
- }
-}
-
class ImageWriter::LayoutHelper {
public:
explicit LayoutHelper(ImageWriter* image_writer)
@@ -2630,14 +2607,6 @@ void ImageWriter::CalculateNewObjectOffsets() {
ImageInfo& image_info = GetImageInfo(relocation.oat_index);
relocation.offset += image_info.GetBinSlotOffset(bin_type);
}
-
- // Update the JNI stub methods by adding their bin sums.
- for (auto& pair : jni_stub_map_) {
- JniStubMethodRelocation& relocation = pair.second.second;
- constexpr Bin bin_type = Bin::kJniStubMethod;
- ImageInfo& image_info = GetImageInfo(relocation.oat_index);
- relocation.offset += image_info.GetBinSlotOffset(bin_type);
- }
}
std::pair<size_t, dchecked_vector<ImageSection>>
@@ -2686,17 +2655,11 @@ ImageWriter::ImageInfo::CreateImageSections() const {
ImageSection(GetBinSlotOffset(Bin::kRuntimeMethod), GetBinSlotSize(Bin::kRuntimeMethod));
/*
- * JNI Stub Methods section
- */
- sections[ImageHeader::kSectionJniStubMethods] =
- ImageSection(GetBinSlotOffset(Bin::kJniStubMethod), GetBinSlotSize(Bin::kJniStubMethod));
-
- /*
* Interned Strings section
*/
// Round up to the alignment the string table expects. See HashSet::WriteToMemory.
- size_t cur_pos = RoundUp(sections[ImageHeader::kSectionJniStubMethods].End(), sizeof(uint64_t));
+ size_t cur_pos = RoundUp(sections[ImageHeader::kSectionRuntimeMethods].End(), sizeof(uint64_t));
const ImageSection& interned_strings_section =
sections[ImageHeader::kSectionInternedStrings] =
@@ -3067,21 +3030,6 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) {
}
}
-void ImageWriter::CopyAndFixupJniStubMethods(size_t oat_index) {
- const ImageInfo& image_info = GetImageInfo(oat_index);
- // Copy method's address to JNI stub methods section.
- for (auto& pair : jni_stub_map_) {
- JniStubMethodRelocation& relocation = pair.second.second;
- // Only work with JNI stubs that are in the current oat file.
- if (relocation.oat_index != oat_index) {
- continue;
- }
- void** address = reinterpret_cast<void**>(image_info.image_.Begin() + relocation.offset);
- ArtMethod* method = pair.second.first;
- CopyAndFixupPointer(address, method);
- }
-}
-
void ImageWriter::CopyAndFixupMethodPointerArray(mirror::PointerArray* arr) {
// Pointer arrays are processed early and each is visited just once.
// Therefore we know that this array has not been copied yet.
@@ -3566,18 +3514,6 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig,
// JNI entrypoint:
if (orig->IsNative()) {
- // Find boot JNI stub for those methods that skipped AOT compilation and don't need
- // clinit check.
- bool still_needs_clinit_check = orig->StillNeedsClinitCheck<kWithoutReadBarrier>();
- if (!still_needs_clinit_check &&
- !compiler_options_.IsBootImage() &&
- quick_code == GetOatAddress(StubType::kQuickGenericJNITrampoline)) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const void* boot_jni_stub = class_linker->FindBootJniStub(orig);
- if (boot_jni_stub != nullptr) {
- quick_code = boot_jni_stub;
- }
- }
// 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.
StubType stub_type = orig->IsCriticalNative() ? StubType::kJNIDlsymLookupCriticalTrampoline
@@ -3748,8 +3684,6 @@ ImageWriter::ImageWriter(const CompilerOptions& compiler_options,
image_objects_offset_begin_(0),
target_ptr_size_(InstructionSetPointerSize(compiler_options.GetInstructionSet())),
image_infos_(oat_filenames.size()),
- jni_stub_map_(JniStubKeyHash(compiler_options.GetInstructionSet()),
- JniStubKeyEquals(compiler_options.GetInstructionSet())),
dirty_methods_(0u),
clean_methods_(0u),
app_class_loader_(class_loader),
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 20509a9ed1..9dd6c7850e 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -45,7 +45,6 @@
#include "lock_word.h"
#include "mirror/dex_cache.h"
#include "oat/image.h"
-#include "oat/jni_stub_hash_map.h"
#include "oat/oat.h"
#include "oat/oat_file.h"
#include "obj_ptr.h"
@@ -210,8 +209,6 @@ class ImageWriter final {
kIMTConflictTable,
// Runtime methods (always clean, do not have a length prefix array).
kRuntimeMethod,
- // Methods with unique JNI stubs.
- kJniStubMethod,
// Metadata bin for data that is temporary during image lifetime.
kMetadata,
kLast = kMetadata,
@@ -453,7 +450,6 @@ class ImageWriter final {
// Creates the contiguous image in memory and adjusts pointers.
void CopyAndFixupNativeData(size_t oat_index) REQUIRES_SHARED(Locks::mutator_lock_);
- void CopyAndFixupJniStubMethods(size_t oat_index) REQUIRES_SHARED(Locks::mutator_lock_);
void CopyAndFixupObjects() REQUIRES_SHARED(Locks::mutator_lock_);
void CopyAndFixupObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_);
template <bool kCheckIfDone>
@@ -499,10 +495,6 @@ class ImageWriter final {
size_t oat_index)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Assign the offset for a method with unique JNI stub.
- void AssignJniStubMethodOffset(ArtMethod* method, size_t oat_index)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Return true if imt was newly inserted.
bool TryAssignImTableOffset(ImTable* imt, size_t oat_index) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -538,11 +530,6 @@ class ImageWriter final {
NativeObjectRelocationType type;
};
- struct JniStubMethodRelocation {
- size_t oat_index;
- uintptr_t offset;
- };
-
NativeObjectRelocation GetNativeRelocation(void* obj) REQUIRES_SHARED(Locks::mutator_lock_);
// Location of where the object will be when the image is loaded at runtime.
@@ -658,9 +645,6 @@ class ImageWriter final {
// image objects (aka sum of bin_slot_sizes_). ArtMethods are placed right after the ArtFields.
HashMap<void*, NativeObjectRelocation> native_object_relocations_;
- // HashMap used for generating JniStubMethodsSection.
- JniStubHashMap<std::pair<ArtMethod*, JniStubMethodRelocation>> jni_stub_map_;
-
// Runtime ArtMethods which aren't reachable from any Class but need to be copied into the image.
ArtMethod* image_methods_[ImageHeader::kImageMethodsCount];
diff --git a/libartbase/base/hash_map.h b/libartbase/base/hash_map.h
index 07245e5816..8823c8bb4d 100644
--- a/libartbase/base/hash_map.h
+++ b/libartbase/base/hash_map.h
@@ -26,8 +26,6 @@ namespace art {
template <typename Key, typename Value, typename HashFn>
class HashMapHashWrapper {
public:
- HashMapHashWrapper() : hash_fn_(HashFn()) {}
- explicit HashMapHashWrapper(const HashFn& hashfn) : hash_fn_(hashfn) {}
size_t operator()(const Key& key) const {
return hash_fn_(key);
}
@@ -43,8 +41,6 @@ class HashMapHashWrapper {
template <typename Key, typename Value, typename PredFn>
class HashMapPredWrapper {
public:
- HashMapPredWrapper() : pred_fn_(PredFn()) {}
- explicit HashMapPredWrapper(const PredFn& predfn) : pred_fn_(predfn) {}
bool operator()(const std::pair<Key, Value>& a, const std::pair<Key, Value>& b) const {
return pred_fn_(a.first, b.first);
}
@@ -90,9 +86,6 @@ class HashMap : public HashSet<std::pair<Key, Value>,
public:
// Inherit constructors.
using Base::Base;
- HashMap(HashFn hashfn, Pred pred)
- : Base(HashMapHashWrapper<Key, Value, HashFn>(hashfn),
- HashMapPredWrapper<Key, Value, Pred>(pred)) {}
// Used to insert a new mapping.
typename Base::iterator Overwrite(const Key& k, const Value& v) {
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 72879e8929..17f09cf814 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -382,7 +382,6 @@ cc_defaults {
"oat/elf_file.cc",
"oat/image.cc",
"oat/index_bss_mapping.cc",
- "oat/jni_stub_hash_map.cc",
"oat/oat.cc",
"oat/oat_file.cc",
"oat/oat_file_assistant.cc",
@@ -1078,7 +1077,6 @@ art_cc_defaults {
"monitor_pool_test.cc",
"monitor_test.cc",
"native_stack_dump_test.cc",
- "oat/jni_stub_hash_map_test.cc",
"oat/oat_file_assistant_test.cc",
"oat/oat_file_test.cc",
"parsed_options_test.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5a94f57bb6..57dbd6d259 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -408,15 +408,6 @@ void ClassLinker::ForceClassInitialized(Thread* self, Handle<mirror::Class> klas
MakeInitializedClassesVisiblyInitialized(self, /*wait=*/true);
}
-const void* ClassLinker::FindBootJniStub(JniStubKey key) {
- auto it = boot_image_jni_stubs_.find(key);
- if (it == boot_image_jni_stubs_.end()) {
- return nullptr;
- } else {
- return it->second;
- }
-}
-
ClassLinker::VisiblyInitializedCallback* ClassLinker::MarkClassInitialized(
Thread* self, Handle<mirror::Class> klass) {
if (kRuntimeISA == InstructionSet::kX86 || kRuntimeISA == InstructionSet::kX86_64) {
@@ -625,8 +616,6 @@ ClassLinker::ClassLinker(InternTable* intern_table, bool fast_class_not_found_ex
visibly_initialize_classes_with_membarier_(RegisterMemBarrierForClassInitialization()),
critical_native_code_with_clinit_check_lock_("critical native code with clinit check lock"),
critical_native_code_with_clinit_check_(),
- boot_image_jni_stubs_(JniStubKeyHash(Runtime::Current()->GetInstructionSet()),
- JniStubKeyEquals(Runtime::Current()->GetInstructionSet())),
cha_(Runtime::Current()->IsAotCompiler() ? nullptr : new ClassHierarchyAnalysis()) {
// For CHA disabled during Aot, see b/34193647.
@@ -1448,16 +1437,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
error_msg)) {
return false;
}
- for (gc::space::ImageSpace* space : spaces) {
- const ImageHeader& header = space->GetImageHeader();
- header.VisitJniStubMethods([&](ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- const void* stub = method->GetOatMethodQuickCode(image_pointer_size_);
- boot_image_jni_stubs_.Put(std::make_pair(JniStubKey(method), stub));
- return method;
- }, space->Begin(), image_pointer_size_);
- }
-
InitializeObjectVirtualMethodHashes(GetClassRoot<mirror::Object>(this),
image_pointer_size_,
ArrayRef<uint32_t>(object_virtual_method_hashes_));
@@ -3699,15 +3678,7 @@ void ClassLinker::FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> kla
for (size_t method_index = 0; method_index < num_direct_methods; ++method_index) {
ArtMethod* method = klass->GetDirectMethod(method_index, pointer_size);
if (method->NeedsClinitCheckBeforeCall()) {
- const void* quick_code = instrumentation->GetCodeForInvoke(method);
- if (method->IsNative() && IsQuickGenericJniStub(quick_code)) {
- const void* boot_jni_stub = FindBootJniStub(method);
- if (boot_jni_stub != nullptr) {
- // Use boot JNI stub if found.
- quick_code = boot_jni_stub;
- }
- }
- instrumentation->UpdateMethodsCode(method, quick_code);
+ instrumentation->UpdateMethodsCode(method, instrumentation->GetCodeForInvoke(method));
}
}
// Ignore virtual methods on the iterator.
@@ -3751,13 +3722,6 @@ static void LinkCode(ClassLinker* class_linker,
const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
quick_code = oat_method.GetQuickCode();
}
- if (method->IsNative() && quick_code == nullptr) {
- const void* boot_jni_stub = class_linker->FindBootJniStub(method);
- if (boot_jni_stub != nullptr) {
- // Use boot JNI stub if found.
- quick_code = boot_jni_stub;
- }
- }
runtime->GetInstrumentation()->InitializeMethodsCode(method, quick_code);
if (method->IsNative()) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 73b3153c45..5597149178 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -41,7 +41,6 @@
#include "jni.h"
#include "mirror/class.h"
#include "mirror/object.h"
-#include "oat/jni_stub_hash_map.h"
#include "oat/oat_file.h"
#include "verifier/verifier_enums.h"
@@ -889,17 +888,6 @@ class EXPORT ClassLinker {
ClassTable* GetBootClassTable() REQUIRES_SHARED(Locks::classlinker_classes_lock_) {
return boot_class_table_.get();
}
- // Find a matching JNI stub from boot images that we could reuse as entrypoint.
- const void* FindBootJniStub(ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- return FindBootJniStub(JniStubKey(method));
- }
-
- const void* FindBootJniStub(uint32_t flags, std::string_view shorty) {
- return FindBootJniStub(JniStubKey(flags, shorty));
- }
-
- const void* FindBootJniStub(JniStubKey key);
protected:
virtual bool InitializeClass(Thread* self,
@@ -1422,10 +1410,6 @@ class EXPORT ClassLinker {
std::map<ArtMethod*, void*> critical_native_code_with_clinit_check_
GUARDED_BY(critical_native_code_with_clinit_check_lock_);
- // Load unique JNI stubs from boot images. If the subsequently loaded native methods could find a
- // matching stub, then reuse it without JIT/AOT compilation.
- JniStubHashMap<const void*> boot_image_jni_stubs_;
-
std::unique_ptr<ClassHierarchyAnalysis> cha_;
class FindVirtualMethodHolderVisitor;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 6b1aef9721..e3e14cae76 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -2615,9 +2615,6 @@ class ImageSpace::BootImageLoader {
};
image_header.VisitPackedImTables(method_table_visitor, space->Begin(), kPointerSize);
image_header.VisitPackedImtConflictTables(method_table_visitor, space->Begin(), kPointerSize);
- image_header.VisitJniStubMethods</*kUpdate=*/ true>(method_table_visitor,
- space->Begin(),
- kPointerSize);
// Patch the intern table.
if (image_header.GetInternedStringsSection().Size() != 0u) {
diff --git a/runtime/oat/image-inl.h b/runtime/oat/image-inl.h
index b87bcb2313..5995600c27 100644
--- a/runtime/oat/image-inl.h
+++ b/runtime/oat/image-inl.h
@@ -115,36 +115,6 @@ inline void ImageHeader::VisitPackedImtConflictTables(const Visitor& visitor,
}
}
-template <bool kUpdate, typename Visitor>
-inline void ImageHeader::VisitJniStubMethods(const Visitor& visitor,
- uint8_t* base,
- PointerSize pointer_size)
- const REQUIRES_SHARED(Locks::mutator_lock_) {
- const ImageSection& section = GetJniStubMethodsSection();
- uint8_t* updated_base = base + section.Offset();
- for (size_t pos = 0; pos < section.Size(); pos += static_cast<size_t>(pointer_size)) {
- uint8_t* ptr = updated_base + pos;
- ArtMethod* orig;
- if (pointer_size == PointerSize::k32) {
- uint32_t value = *reinterpret_cast<uint32_t*>(ptr);
- orig = reinterpret_cast32<ArtMethod*>(value);
- } else {
- uint64_t value = *reinterpret_cast<uint64_t*>(ptr);
- orig = reinterpret_cast64<ArtMethod*>(value);
- }
- ArtMethod* updated = visitor(orig);
- if (kUpdate){
- if (pointer_size == PointerSize::k32) {
- *reinterpret_cast<uint32_t*>(ptr) = reinterpret_cast32<uint32_t>(updated);
- } else {
- *reinterpret_cast<uint64_t*>(ptr) = reinterpret_cast64<uint64_t>(updated);
- }
- } else {
- DCHECK_EQ(updated, orig);
- }
- }
-}
-
} // namespace art
#endif // ART_RUNTIME_OAT_IMAGE_INL_H_
diff --git a/runtime/oat/image.cc b/runtime/oat/image.cc
index 7bdc4f8e50..a7ac8e0ebd 100644
--- a/runtime/oat/image.cc
+++ b/runtime/oat/image.cc
@@ -34,8 +34,8 @@
namespace art HIDDEN {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-// Last change: Add JniStubMethodsSection.
-const uint8_t ImageHeader::kImageVersion[] = { '1', '1', '0', '\0' };
+// Last change: Split intrinsics list - with and without HIR.
+const uint8_t ImageHeader::kImageVersion[] = { '1', '0', '9', '\0' };
ImageHeader::ImageHeader(uint32_t image_reservation_size,
uint32_t component_count,
@@ -264,10 +264,9 @@ const char* ImageHeader::GetImageSectionName(ImageSections index) {
case kSectionObjects: return "Objects";
case kSectionArtFields: return "ArtFields";
case kSectionArtMethods: return "ArtMethods";
+ case kSectionRuntimeMethods: return "RuntimeMethods";
case kSectionImTables: return "ImTables";
case kSectionIMTConflictTables: return "IMTConflictTables";
- case kSectionRuntimeMethods: return "RuntimeMethods";
- case kSectionJniStubMethods: return "JniStubMethods";
case kSectionInternedStrings: return "InternedStrings";
case kSectionClassTable: return "ClassTable";
case kSectionStringReferenceOffsets: return "StringReferenceOffsets";
diff --git a/runtime/oat/image.h b/runtime/oat/image.h
index cd479f1a81..23c92a1aa8 100644
--- a/runtime/oat/image.h
+++ b/runtime/oat/image.h
@@ -263,10 +263,9 @@ class PACKED(8) ImageHeader {
kSectionObjects,
kSectionArtFields,
kSectionArtMethods,
+ kSectionRuntimeMethods,
kSectionImTables,
kSectionIMTConflictTables,
- kSectionRuntimeMethods,
- kSectionJniStubMethods,
kSectionInternedStrings,
kSectionClassTable,
kSectionStringReferenceOffsets,
@@ -336,10 +335,6 @@ class PACKED(8) ImageHeader {
return GetImageSection(kSectionMetadata);
}
- const ImageSection& GetJniStubMethodsSection() const {
- return GetImageSection(kSectionJniStubMethods);
- }
-
const ImageSection& GetImageBitmapSection() const {
return GetImageSection(kSectionImageBitmap);
}
@@ -408,11 +403,6 @@ class PACKED(8) ImageHeader {
uint8_t* base,
PointerSize pointer_size) const;
- template <bool kUpdate = false, typename Visitor>
- void VisitJniStubMethods(const Visitor& visitor,
- uint8_t* base,
- PointerSize pointer_size) const REQUIRES_SHARED(Locks::mutator_lock_);
-
IterationRange<const Block*> GetBlocks() const {
return GetBlocks(GetImageBegin());
}
diff --git a/runtime/oat/jni_stub_hash_map.cc b/runtime/oat/jni_stub_hash_map.cc
deleted file mode 100644
index fccf697b7d..0000000000
--- a/runtime/oat/jni_stub_hash_map.cc
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2024 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_stub_hash_map.h"
-
-#include "arch/arm64/jni_frame_arm64.h"
-#include "arch/instruction_set.h"
-#include "arch/riscv64/jni_frame_riscv64.h"
-#include "arch/x86_64/jni_frame_x86_64.h"
-#include "base/macros.h"
-
-namespace art HIDDEN {
-
-static char TranslateArgToJniShorty(char ch) {
- // Byte, char, int, short, boolean are treated the same(e.g., Wx registers for arm64) when
- // generating JNI stub, so their JNI shorty characters are same.
- // ABCDEFGHIJKLMNOPQRSTUVWXYZ
- static constexpr char kTranslations[] = ".PPD.F..PJ.L......P......P";
- DCHECK_GE(ch, 'A');
- DCHECK_LE(ch, 'Z');
- DCHECK_NE(kTranslations[ch - 'A'], '.');
- return kTranslations[ch - 'A'];
-}
-
-static char TranslateReturnTypeToJniShorty(char ch, InstructionSet isa = InstructionSet::kNone) {
- // For all archs, reference type has a different JNI shorty character than others as it needs to
- // be decoded in stub.
- // For arm64, small return types need sign-/zero-extended.
- // For x86_64, small return types need sign-/zero-extended, and RAX needs to be preserved and
- // restored when thread state changes.
- // Other archs keeps untranslated for simplicity.
- // TODO: support riscv64 with an optimized version.
- // ABCDEFGHIJKLMNOPQRSTUVWXYZ
- static constexpr char kArm64Translations[] = ".BCP.P..PP.L......S..P...Z";
- static constexpr char kX86_64Translations[] = ".BCP.P..RR.L......S..P...Z";
- static constexpr char kOtherTranslations[] = ".BCD.F..IJ.L......S..V...Z";
- DCHECK_GE(ch, 'A');
- DCHECK_LE(ch, 'Z');
- switch (isa) {
- case InstructionSet::kArm64:
- DCHECK_NE(kArm64Translations[ch - 'A'], '.');
- return kArm64Translations[ch - 'A'];
- case InstructionSet::kX86_64:
- DCHECK_NE(kX86_64Translations[ch - 'A'], '.');
- return kX86_64Translations[ch - 'A'];
- default:
- DCHECK_NE(kOtherTranslations[ch - 'A'], '.');
- return kOtherTranslations[ch - 'A'];
- }
-}
-
-static constexpr size_t GetMaxIntLikeRegisterArgs(InstructionSet isa) {
- switch (isa) {
- case InstructionSet::kArm64:
- return arm64::kMaxIntLikeRegisterArguments;
- case InstructionSet::kX86_64:
- return x86_64::kMaxIntLikeRegisterArguments;
- default:
- LOG(FATAL) << "Unrecognized isa: " << isa << " for " << __FUNCTION__;
- UNREACHABLE();
- }
-}
-
-static constexpr size_t GetMaxFloatOrDoubleRegisterArgs(InstructionSet isa) {
- switch (isa) {
- case InstructionSet::kArm64:
- return arm64::kMaxFloatOrDoubleRegisterArguments;
- case InstructionSet::kX86_64:
- return x86_64::kMaxFloatOrDoubleRegisterArguments;
- default:
- LOG(FATAL) << "Unrecognized isa: " << isa << " for " << __FUNCTION__;
- UNREACHABLE();
- }
-}
-
-static size_t StackOffset(char ch) {
- if (ch == 'J' || ch == 'D') {
- return 8;
- } else {
- return 4;
- }
-}
-
-static bool IsFloatOrDoubleArg(char ch) {
- return ch == 'F' || ch == 'D';
-}
-
-static bool IsIntegralArg(char ch) {
- return ch == 'B' || ch == 'C' || ch == 'I' || ch == 'J' || ch == 'S' || ch == 'Z';
-}
-
-static bool IsReferenceArg(char ch) {
- return ch == 'L';
-}
-
-template<InstructionSet kIsa>
-size_t JniStubKeyOptimizedHash(const JniStubKey& key) {
- bool is_static = key.Flags() & kAccStatic;
- std::string_view shorty = key.Shorty();
- size_t result = key.Flags();
- result ^= TranslateReturnTypeToJniShorty(shorty[0], kIsa);
- constexpr size_t kMaxFloatOrDoubleRegisterArgs = GetMaxFloatOrDoubleRegisterArgs(kIsa);
- constexpr size_t kMaxIntLikeRegisterArgs = GetMaxIntLikeRegisterArgs(kIsa);
- size_t float_or_double_args = 0;
- // ArtMethod* and 'Object* this' for non-static method.
- // ArtMethod* for static method.
- size_t int_like_args = is_static ? 1 : 2;
- size_t stack_offset = 0;
- for (char c : shorty.substr(1u)) {
- bool stack_offset_matters = false;
- stack_offset += StackOffset(c);
- if (IsFloatOrDoubleArg(c)) {
- ++float_or_double_args;
- if (float_or_double_args > kMaxFloatOrDoubleRegisterArgs) {
- // Stack offset matters if we run out of float-like (float, double) argument registers
- // because the subsequent float-like args should be passed on the stack.
- stack_offset_matters = true;
- } else {
- // Floating-point register arguments are not touched when generating JNI stub, so could be
- // ignored when calculating hash value.
- continue;
- }
- } else {
- ++int_like_args;
- if (int_like_args > kMaxIntLikeRegisterArgs || IsReferenceArg(c)) {
- // Stack offset matters if we run out of integer-like (pointer, object, long, int, short,
- // bool, etc) argument registers because the subsequent integer-like args should be passed
- // on the stack. It also matters if current arg is reference type because it needs to be
- // spilled as raw data even if it's in a register.
- stack_offset_matters = true;
- } else if (!is_static) {
- // For non-static method, two managed arguments 'ArtMethod*' and 'Object* this' correspond
- // to two native arguments 'JNIEnv*' and 'jobject'. So trailing integral (long, int, short,
- // bool, etc) arguments will remain in the same registers, which do not need any generated
- // code.
- // But for static method, we have only one leading managed argument 'ArtMethod*' but two
- // native arguments 'JNIEnv*' and 'jclass'. So trailing integral arguments are always
- // shuffled around and affect the generated code.
- continue;
- }
- }
- // int_like_args is needed for reference type because it will determine from which register
- // we take the value to construct jobject.
- if (IsReferenceArg(c)) {
- result = result * 31u * int_like_args ^ TranslateArgToJniShorty(c);
- } else {
- result = result * 31u ^ TranslateArgToJniShorty(c);
- }
- if (stack_offset_matters) {
- result += stack_offset;
- }
- }
- return result;
-}
-
-size_t JniStubKeyGenericHash(const JniStubKey& key) {
- std::string_view shorty = key.Shorty();
- size_t result = key.Flags();
- result ^= TranslateReturnTypeToJniShorty(shorty[0]);
- for (char c : shorty.substr(1u)) {
- result = result * 31u ^ TranslateArgToJniShorty(c);
- }
- return result;
-}
-
-JniStubKeyHash::JniStubKeyHash(InstructionSet isa) {
- switch (isa) {
- case InstructionSet::kArm:
- case InstructionSet::kThumb2:
- case InstructionSet::kRiscv64:
- case InstructionSet::kX86:
- hash_func_ = JniStubKeyGenericHash;
- break;
- case InstructionSet::kArm64:
- hash_func_ = JniStubKeyOptimizedHash<InstructionSet::kArm64>;
- break;
- case InstructionSet::kX86_64:
- hash_func_ = JniStubKeyOptimizedHash<InstructionSet::kX86_64>;
- break;
- case InstructionSet::kNone:
- LOG(FATAL) << "No instruction set given for " << __FUNCTION__;
- UNREACHABLE();
- }
-}
-
-template<InstructionSet kIsa>
-bool JniStubKeyOptimizedEquals(const JniStubKey& lhs, const JniStubKey& rhs) {
- if (lhs.Flags() != rhs.Flags()) {
- return false;
- }
- std::string_view shorty_lhs = lhs.Shorty();
- std::string_view shorty_rhs = rhs.Shorty();
- if (TranslateReturnTypeToJniShorty(shorty_lhs[0], kIsa) !=
- TranslateReturnTypeToJniShorty(shorty_rhs[0], kIsa)) {
- return false;
- }
- bool is_static = lhs.Flags() & kAccStatic;
- constexpr size_t kMaxFloatOrDoubleRegisterArgs = GetMaxFloatOrDoubleRegisterArgs(kIsa);
- constexpr size_t kMaxIntLikeRegisterArgs = GetMaxIntLikeRegisterArgs(kIsa);
- size_t float_or_double_args_lhs = 0;
- size_t float_or_double_args_rhs = 0;
- size_t int_like_args_lhs = is_static ? 1 : 2;
- size_t int_like_args_rhs = is_static ? 1 : 2;
- size_t stack_offset_lhs = 0;
- size_t stack_offset_rhs = 0;
- size_t i = 1;
- size_t j = 1;
- while (i < shorty_lhs.length() && j < shorty_rhs.length()) {
- bool should_skip = false;
- bool stack_offset_matters = false;
- char ch_lhs = shorty_lhs[i];
- char ch_rhs = shorty_rhs[j];
-
- if (IsFloatOrDoubleArg(ch_lhs) &&
- float_or_double_args_lhs < kMaxFloatOrDoubleRegisterArgs) {
- // Skip float-like register arguments.
- ++i;
- ++float_or_double_args_lhs;
- stack_offset_lhs += StackOffset(ch_lhs);
- should_skip = true;
- } else if (IsIntegralArg(ch_lhs) &&
- int_like_args_lhs < kMaxIntLikeRegisterArgs) {
- if (!is_static) {
- // Skip integral register arguments for non-static method.
- ++i;
- ++int_like_args_lhs;
- stack_offset_lhs += StackOffset(ch_lhs);
- should_skip = true;
- }
- } else {
- stack_offset_matters = true;
- }
-
- if (IsFloatOrDoubleArg(ch_rhs) &&
- float_or_double_args_rhs < kMaxFloatOrDoubleRegisterArgs) {
- // Skip float-like register arguments.
- ++j;
- ++float_or_double_args_rhs;
- stack_offset_rhs += StackOffset(ch_rhs);
- should_skip = true;
- } else if (IsIntegralArg(ch_rhs) &&
- int_like_args_rhs < kMaxIntLikeRegisterArgs) {
- if (!is_static) {
- // Skip integral register arguments for non-static method.
- ++j;
- ++int_like_args_rhs;
- stack_offset_rhs += StackOffset(ch_rhs);
- should_skip = true;
- }
- } else {
- stack_offset_matters = true;
- }
-
- if (should_skip) {
- continue;
- }
- if (TranslateArgToJniShorty(ch_lhs) != TranslateArgToJniShorty(ch_rhs)) {
- return false;
- }
- if (stack_offset_matters && stack_offset_lhs != stack_offset_rhs) {
- return false;
- }
- // int_like_args needs to be compared for reference type because it will determine from
- // which register we take the value to construct jobject.
- if (IsReferenceArg(ch_lhs) && int_like_args_lhs != int_like_args_rhs) {
- return false;
- }
- // Passed character comparison.
- ++i;
- ++j;
- stack_offset_lhs += StackOffset(ch_lhs);
- stack_offset_rhs += StackOffset(ch_rhs);
- DCHECK_EQ(IsFloatOrDoubleArg(ch_lhs), IsFloatOrDoubleArg(ch_rhs));
- if (IsFloatOrDoubleArg(ch_lhs)) {
- ++float_or_double_args_lhs;
- ++float_or_double_args_rhs;
- } else {
- ++int_like_args_lhs;
- ++int_like_args_rhs;
- }
- }
- auto remaining_shorty =
- i < shorty_lhs.length() ? shorty_lhs.substr(i) : shorty_rhs.substr(j);
- size_t float_or_double_args =
- i < shorty_lhs.length() ? float_or_double_args_lhs : float_or_double_args_rhs;
- size_t int_like_args = i < shorty_lhs.length() ? int_like_args_lhs : int_like_args_rhs;
- for (char c : remaining_shorty) {
- if (IsFloatOrDoubleArg(c) && float_or_double_args < kMaxFloatOrDoubleRegisterArgs) {
- ++float_or_double_args;
- continue;
- }
- if (!is_static && IsIntegralArg(c) && int_like_args < kMaxIntLikeRegisterArgs) {
- ++int_like_args;
- continue;
- }
- return false;
- }
- return true;
-}
-
-bool JniStubKeyGenericEquals(const JniStubKey& lhs, const JniStubKey& rhs) {
- if (lhs.Flags() != rhs.Flags()) {
- return false;
- }
- std::string_view shorty_lhs = lhs.Shorty();
- std::string_view shorty_rhs = rhs.Shorty();
- if (TranslateReturnTypeToJniShorty(shorty_lhs[0]) !=
- TranslateReturnTypeToJniShorty(shorty_rhs[0])) {
- return false;
- }
- if (shorty_lhs.length() != shorty_rhs.length()) {
- return false;
- }
- for (size_t i = 1; i < shorty_lhs.length(); ++i) {
- if (TranslateArgToJniShorty(shorty_lhs[i]) != TranslateArgToJniShorty(shorty_rhs[i])) {
- return false;
- }
- }
- return true;
-}
-
-JniStubKeyEquals::JniStubKeyEquals(InstructionSet isa) {
- switch (isa) {
- case InstructionSet::kArm:
- case InstructionSet::kThumb2:
- case InstructionSet::kRiscv64:
- case InstructionSet::kX86:
- equals_func_ = JniStubKeyGenericEquals;
- break;
- case InstructionSet::kArm64:
- equals_func_ = JniStubKeyOptimizedEquals<InstructionSet::kArm64>;
- break;
- case InstructionSet::kX86_64:
- equals_func_ = JniStubKeyOptimizedEquals<InstructionSet::kX86_64>;
- break;
- case InstructionSet::kNone:
- LOG(FATAL) << "No instruction set given for " << __FUNCTION__;
- UNREACHABLE();
- }
-}
-
-} // namespace art
diff --git a/runtime/oat/jni_stub_hash_map.h b/runtime/oat/jni_stub_hash_map.h
deleted file mode 100644
index 6e4603d3fb..0000000000
--- a/runtime/oat/jni_stub_hash_map.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2024 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.
- */
-
-#ifndef ART_RUNTIME_OAT_JNI_STUB_HASH_MAP_H_
-#define ART_RUNTIME_OAT_JNI_STUB_HASH_MAP_H_
-
-#include <memory>
-#include <string_view>
-
-#include "arch/instruction_set.h"
-#include "art_method.h"
-#include "base/hash_map.h"
-
-namespace art HIDDEN {
-
-class JniStubKey {
- public:
- JniStubKey() = default;
- JniStubKey(const JniStubKey& other) = default;
- JniStubKey& operator=(const JniStubKey& other) = default;
-
- JniStubKey(uint32_t flags, std::string_view shorty)
- : flags_(flags & (kAccStatic | kAccSynchronized | kAccFastNative | kAccCriticalNative)),
- shorty_(shorty) {
- DCHECK(ArtMethod::IsNative(flags));
- }
-
- explicit JniStubKey(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_)
- : JniStubKey(method->GetAccessFlags(), method->GetShortyView()) {}
-
- uint32_t Flags() const {
- return flags_;
- }
-
- std::string_view Shorty() const {
- return shorty_;
- }
-
- bool IsEmpty() const {
- return Shorty().empty();
- }
-
- void MakeEmpty() {
- shorty_ = {};
- }
-
- private:
- uint32_t flags_;
- std::string_view shorty_;
-};
-
-template <typename Value>
-class JniStubKeyEmpty {
- public:
- bool IsEmpty(const std::pair<JniStubKey, Value>& pair) const {
- return pair.first.IsEmpty();
- }
-
- void MakeEmpty(std::pair<JniStubKey, Value>& pair) {
- pair.first.MakeEmpty();
- }
-};
-
-using JniStubKeyHashFunction = size_t (*)(const JniStubKey& key);
-
-class JniStubKeyHash {
- public:
- EXPORT explicit JniStubKeyHash(InstructionSet isa);
-
- size_t operator()(const JniStubKey& key) const {
- return hash_func_(key);
- }
-
- private:
- JniStubKeyHashFunction hash_func_;
-};
-
-using JniStubKeyEqualsFunction = bool (*)(const JniStubKey& lhs, const JniStubKey& rhs);
-
-class JniStubKeyEquals {
- public:
- EXPORT explicit JniStubKeyEquals(InstructionSet isa);
-
- bool operator()(const JniStubKey& lhs, const JniStubKey& rhs) const {
- return equals_func_(lhs, rhs);
- }
-
- private:
- JniStubKeyEqualsFunction equals_func_;
-};
-
-template <typename Value,
- typename Alloc = std::allocator<std::pair<JniStubKey, Value>>>
-using JniStubHashMap =
- HashMap<JniStubKey, Value, JniStubKeyEmpty<Value>, JniStubKeyHash, JniStubKeyEquals>;
-
-} // namespace art
-
-#endif // ART_RUNTIME_OAT_JNI_STUB_HASH_MAP_H_
diff --git a/runtime/oat/jni_stub_hash_map_test.cc b/runtime/oat/jni_stub_hash_map_test.cc
deleted file mode 100644
index 010a25d860..0000000000
--- a/runtime/oat/jni_stub_hash_map_test.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2024 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_stub_hash_map.h"
-
-#include <gtest/gtest.h>
-
-#include <memory>
-#include <ostream>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-#include "android-base/logging.h"
-#include "android-base/stringprintf.h"
-#include "arch/instruction_set.h"
-#include "art_method.h"
-#include "base/array_ref.h"
-#include "base/locks.h"
-#include "base/utils.h"
-#include "class_linker.h"
-#include "common_compiler_test.h"
-#include "common_compiler_test.cc"
-#include "compiler.h"
-#include "gc/heap.h"
-#include "gc/space/image_space.h"
-#include "handle.h"
-#include "handle_scope.h"
-#include "handle_scope-inl.h"
-#include "image.h"
-#include "image-inl.h"
-#include "jni.h"
-#include "mirror/class.h"
-#include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
-#include "obj_ptr.h"
-#include "runtime.h"
-#include "scoped_thread_state_change.h"
-#include "strstream"
-
-namespace art HIDDEN {
-
-// Teach gtest how to print the ArrayRef<const uint8_t>. The customized output is easier used
-// for converting to assembly instructions.
-static void PrintTo(const ArrayRef<const uint8_t>& array, std::ostream* os) {
- *os << "[[[";
- for (const uint8_t& element : array) {
- *os << " ";
- *os << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(element);
- }
- *os << " ]]]";
-}
-
-class JniStubHashMapTest : public CommonCompilerTest {
- protected:
- JniStubHashMapTest()
- : jni_stub_hash_map_(JniStubKeyHash(kRuntimeISA), JniStubKeyEquals(kRuntimeISA)) {
- if (kRuntimeISA == InstructionSet::kArm64 || kRuntimeISA == InstructionSet::kX86_64) {
- // Only arm64 and x86_64 use strict check.
- strict_check_ = true;
- } else {
- // Other archs use loose check.
- strict_check_ = false;
- }
- }
-
- void SetStrictCheck(bool value) {
- strict_check_ = value;
- }
-
- void SetUpForTest() {
- ScopedObjectAccess soa(Thread::Current());
- jobject jclass_loader = LoadDex("MyClassNatives");
- StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
- pointer_size_ = class_linker_->GetImagePointerSize();
- ObjPtr<mirror::Class> klass =
- class_linker_->FindClass(soa.Self(), "LMyClassNatives;", class_loader);
- ASSERT_TRUE(klass != nullptr);
- jklass_ = soa.AddLocalReference<jclass>(klass);
- }
-
- void SetBaseMethod(std::string_view base_method_name, std::string_view base_method_sig) {
- jni_stub_hash_map_.clear();
- Thread* self = Thread::Current();
- ScopedObjectAccess soa(self);
- ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(jklass_);
- base_method_ = klass->FindClassMethod(base_method_name, base_method_sig, pointer_size_);
- ASSERT_TRUE(base_method_ != nullptr);
- ASSERT_TRUE(base_method_->IsNative());
-
- OneCompiledMethodStorage base_method_storage;
- StackHandleScope<1> hs(self);
- std::unique_ptr<Compiler> compiler(
- Compiler::Create(*compiler_options_, &base_method_storage, compiler_kind_));
- const DexFile& dex_file = *base_method_->GetDexFile();
- Handle<mirror::DexCache> dex_cache =
- hs.NewHandle(GetClassLinker()->FindDexCache(self, dex_file));
- compiler->JniCompile(base_method_->GetAccessFlags(),
- base_method_->GetDexMethodIndex(),
- dex_file,
- dex_cache);
- ArrayRef<const uint8_t> code = base_method_storage.GetCode();
- base_method_code_.assign(code.begin(), code.end());
-
- jni_stub_hash_map_.insert(std::make_pair(JniStubKey(base_method_), base_method_));
- }
-
- void CompareMethod(std::string_view cmp_method_name, std::string_view cmp_method_sig) {
- Thread* self = Thread::Current();
- ScopedObjectAccess soa(self);
- ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(jklass_);
- ArtMethod* cmp_method = klass->FindClassMethod(cmp_method_name, cmp_method_sig, pointer_size_);
- ASSERT_TRUE(cmp_method != nullptr);
- ASSERT_TRUE(cmp_method->IsNative());
-
- OneCompiledMethodStorage cmp_method_storage;
- StackHandleScope<1> hs(self);
- std::unique_ptr<Compiler> compiler(
- Compiler::Create(*compiler_options_, &cmp_method_storage, compiler_kind_));
- const DexFile& dex_file = *cmp_method->GetDexFile();
- Handle<mirror::DexCache> dex_cache =
- hs.NewHandle(GetClassLinker()->FindDexCache(self, dex_file));
- compiler->JniCompile(cmp_method->GetAccessFlags(),
- cmp_method->GetDexMethodIndex(),
- dex_file,
- dex_cache);
-
- ArrayRef<const uint8_t> method_code = ArrayRef<const uint8_t>(base_method_code_);
- ArrayRef<const uint8_t> cmp_method_code = cmp_method_storage.GetCode();
- auto it = jni_stub_hash_map_.find(JniStubKey(cmp_method));
- if (it != jni_stub_hash_map_.end()) {
- ASSERT_EQ(method_code, cmp_method_code)
- << "base method: " << base_method_->PrettyMethod() << ", compared method: "
- << cmp_method->PrettyMethod();
- } else if (strict_check_){
- // If the compared method maps to a different entry, then its compiled JNI stub should be
- // also different from the base one.
- ASSERT_NE(method_code, cmp_method_code)
- << "base method: " << base_method_->PrettyMethod() << ", compared method: "
- << cmp_method->PrettyMethod();
- }
- }
-
- bool strict_check_;
- JniStubHashMap<ArtMethod*> jni_stub_hash_map_;
- PointerSize pointer_size_;
- jclass jklass_;
- ArtMethod* base_method_;
- std::vector<uint8_t> base_method_code_;
-};
-
-class JniStubHashMapBootImageTest : public CommonRuntimeTest {
- protected:
- void SetUpRuntimeOptions(RuntimeOptions* options) override {
- std::string runtime_args_image;
- runtime_args_image = android::base::StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str());
- options->push_back(std::make_pair(runtime_args_image, nullptr));
- }
-};
-
-TEST_F(JniStubHashMapTest, ReturnType) {
- SetUpForTest();
- SetBaseMethod("fooI", "(I)I");
- CompareMethod("fooI_V", "(I)V");
- CompareMethod("fooI_B", "(I)B");
- CompareMethod("fooI_C", "(I)C");
- CompareMethod("fooI_S", "(I)S");
- CompareMethod("fooI_Z", "(I)Z");
- CompareMethod("fooI_J", "(I)J");
- CompareMethod("fooI_F", "(I)F");
- CompareMethod("fooI_D", "(I)D");
- CompareMethod("fooI_L", "(I)Ljava/lang/Object;");
-}
-
-TEST_F(JniStubHashMapTest, ArgType) {
- SetUpForTest();
- SetBaseMethod("sfooI", "(I)I");
- CompareMethod("sfooB", "(B)I");
- CompareMethod("sfooC", "(C)I");
- CompareMethod("sfooS", "(S)I");
- CompareMethod("sfooZ", "(Z)I");
- CompareMethod("sfooL", "(Ljava/lang/Object;)I");
-}
-
-TEST_F(JniStubHashMapTest, FloatingPointArg) {
- SetUpForTest();
- SetBaseMethod("sfooI", "(I)I");
- CompareMethod("sfoo7FI", "(FFFFFFFI)I");
- CompareMethod("sfoo3F5DI", "(FFFDDDDDI)I");
- CompareMethod("sfoo3F6DI", "(FFFDDDDDDI)I");
-}
-
-TEST_F(JniStubHashMapTest, IntegralArg) {
- SetUpForTest();
- SetBaseMethod("fooL", "(Ljava/lang/Object;)I");
- CompareMethod("fooL4I", "(Ljava/lang/Object;IIII)I");
- CompareMethod("fooL5I", "(Ljava/lang/Object;IIIII)I");
- CompareMethod("fooL3IJC", "(Ljava/lang/Object;IIIJC)I");
- CompareMethod("fooL3IJCS", "(Ljava/lang/Object;IIIJCS)I");
-}
-
-TEST_F(JniStubHashMapTest, StackOffsetMatters) {
- SetUpForTest();
- SetBaseMethod("foo7FDF", "(FFFFFFFDF)I");
- CompareMethod("foo9F", "(FFFFFFFFF)I");
- CompareMethod("foo7FIFF", "(FFFFFFFIFF)I");
- SetBaseMethod("foo5IJI", "(IIIIIJI)I");
- CompareMethod("foo7I", "(IIIIIII)I");
- CompareMethod("foo5IFII", "(IIIIIFII)I");
- SetBaseMethod("fooFDL", "(FDLjava/lang/Object;)I");
- CompareMethod("foo2FL", "(FFLjava/lang/Object;)I");
- CompareMethod("foo3FL", "(FFFLjava/lang/Object;)I");
- CompareMethod("foo2FIL", "(FFILjava/lang/Object;)I");
-}
-
-TEST_F(JniStubHashMapTest, IntLikeRegsMatters) {
- SetUpForTest();
- SetBaseMethod("fooICFL", "(ICFLjava/lang/Object;)I");
- CompareMethod("foo2IFL", "(IIFLjava/lang/Object;)I");
- CompareMethod("fooICIL", "(ICILjava/lang/Object;)I");
-}
-
-TEST_F(JniStubHashMapTest, FastNative) {
- SetUpForTest();
- SetBaseMethod("fooI_Fast", "(I)I");
- CompareMethod("fooI_Z_Fast", "(I)Z");
- CompareMethod("fooI_J_Fast", "(I)J");
- SetBaseMethod("fooICFL_Fast", "(ICFLjava/lang/Object;)I");
- CompareMethod("foo2IFL_Fast", "(IIFLjava/lang/Object;)I");
- CompareMethod("fooICIL_Fast", "(ICILjava/lang/Object;)I");
- SetBaseMethod("fooFDL_Fast", "(FDLjava/lang/Object;)I");
- CompareMethod("foo2FL_Fast", "(FFLjava/lang/Object;)I");
- CompareMethod("foo3FL_Fast", "(FFFLjava/lang/Object;)I");
- CompareMethod("foo2FIL_Fast", "(FFILjava/lang/Object;)I");
- SetBaseMethod("foo7F_Fast", "(FFFFFFF)I");
- CompareMethod("foo3F5D_Fast", "(FFFDDDDD)I");
- CompareMethod("foo3F6D_Fast", "(FFFDDDDDD)I");
- SetBaseMethod("fooL5I_Fast", "(Ljava/lang/Object;IIIII)I");
- CompareMethod("fooL3IJC_Fast", "(Ljava/lang/Object;IIIJC)I");
- CompareMethod("fooL3IJCS_Fast", "(Ljava/lang/Object;IIIJCS)I");
-}
-
-TEST_F(JniStubHashMapTest, CriticalNative) {
- SetUpForTest();
- if (kRuntimeISA == InstructionSet::kX86_64) {
- // In x86_64, the return type seems be ignored in critical function.
- SetStrictCheck(false);
- }
- SetBaseMethod("returnInt_Critical", "()I");
- CompareMethod("returnDouble_Critical", "()D");
- CompareMethod("returnLong_Critical", "()J");
- SetBaseMethod("foo7F_Critical", "(FFFFFFF)I");
- CompareMethod("foo3F5D_Critical", "(FFFDDDDD)I");
- CompareMethod("foo3F6D_Critical", "(FFFDDDDDD)I");
-}
-
-TEST_F(JniStubHashMapBootImageTest, BootImageSelfCheck) {
- std::vector<gc::space::ImageSpace*> image_spaces =
- Runtime::Current()->GetHeap()->GetBootImageSpaces();
- ASSERT_TRUE(!image_spaces.empty());
- for (gc::space::ImageSpace* space : image_spaces) {
- const ImageHeader& header = space->GetImageHeader();
- PointerSize ptr_size = class_linker_->GetImagePointerSize();
- auto visitor = [&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) {
- if (method.IsNative() && !method.IsIntrinsic()) {
- const void* boot_jni_stub = class_linker_->FindBootJniStub(JniStubKey(&method));
- if (boot_jni_stub != nullptr) {
- const void* cmp_jni_stub = method.GetOatMethodQuickCode(ptr_size);
- size_t boot_jni_stub_size =
- OatQuickMethodHeader::FromEntryPoint(boot_jni_stub)->GetCodeSize();
- size_t cmp_jni_stub_size =
- OatQuickMethodHeader::FromEntryPoint(cmp_jni_stub)->GetCodeSize();
- ArrayRef<const uint8_t> boot_jni_stub_array = ArrayRef(
- reinterpret_cast<const uint8_t*>(EntryPointToCodePointer(boot_jni_stub)),
- boot_jni_stub_size);
- ArrayRef<const uint8_t> cmp_jni_stub_array = ArrayRef(
- reinterpret_cast<const uint8_t*>(EntryPointToCodePointer(cmp_jni_stub)),
- cmp_jni_stub_size);
- ASSERT_EQ(boot_jni_stub_array, cmp_jni_stub_array)
- << "method: " << method.PrettyMethod() << ", size = " << cmp_jni_stub_size;
- }
- }
- };
- header.VisitPackedArtMethods(visitor, space->Begin(), ptr_size);
- }
-}
-
-} // namespace art
diff --git a/runtime/runtime_image.cc b/runtime/runtime_image.cc
index 83e020090e..5d304698bf 100644
--- a/runtime/runtime_image.cc
+++ b/runtime/runtime_image.cc
@@ -955,16 +955,7 @@ class RuntimeImageHelper {
const OatFile* oat_file = image_spaces[0]->GetOatFile();
DCHECK(oat_file != nullptr);
const OatHeader& header = oat_file->GetOatHeader();
- const void* entrypoint = header.GetOatAddress(stub);
- if (method->IsNative() && (is_class_initialized || !method->NeedsClinitCheckBeforeCall())) {
- // Use boot JNI stub if found.
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- const void* boot_jni_stub = class_linker->FindBootJniStub(method);
- if (boot_jni_stub != nullptr) {
- entrypoint = boot_jni_stub;
- }
- }
- copy->SetEntryPointFromQuickCompiledCode(entrypoint);
+ copy->SetEntryPointFromQuickCompiledCode(header.GetOatAddress(stub));
if (method->IsNative()) {
StubType stub_type = method->IsCriticalNative()
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 81c8a8a9e0..942b155261 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -840,7 +840,7 @@ void StackVisitor::WalkStack(bool include_transitions) {
cur_oat_quick_method_header_ = OatQuickMethodHeader::FromCodePointer(code);
} else {
// We are sure we are not running GenericJni here. Though the entry point could still be
- // GenericJnistub. The entry point is usually JITed or AOT code. It could be also a
+ // GenericJnistub. The entry point is usually JITed or AOT code. It could be lso a
// resolution stub if the class isn't visibly initialized yet.
const void* existing_entry_point = method->GetEntryPointFromQuickCompiledCode();
CHECK(existing_entry_point != nullptr);
@@ -856,22 +856,13 @@ void StackVisitor::WalkStack(bool include_transitions) {
if (code != nullptr) {
cur_oat_quick_method_header_ = OatQuickMethodHeader::FromEntryPoint(code);
} else {
- // This may be either a JITed JNI stub frame or boot JNI stub frame. For
- // non-debuggable runtimes we will generate JIT stubs if there are no AOT stubs or
- // boot stubs for native methods. Since we checked for AOT code earlier, we must be
- // running JITed code or boot stub code. For debuggable runtimes we might have JIT
- // code even when AOT stub or boot stub is present but we tag SP in JITed JNI stubs
+ // This must be a JITted JNI stub frame. For non-debuggable runtimes we only generate
+ // JIT stubs if there are no AOT stubs for native methods. Since we checked for AOT
+ // code earlier, we must be running JITed code. For debuggable runtimes we might have
+ // JIT code even when AOT code is present but we tag SP in JITed JNI stubs
// in debuggable runtimes. This case is handled earlier.
- if (runtime->GetJit() != nullptr) {
- code = runtime->GetJit()->GetCodeCache()->GetJniStubCode(method);
- }
- if (code == nullptr) {
- // Check if current method uses the boot JNI stub.
- const void* boot_jni_stub = class_linker->FindBootJniStub(method);
- if (boot_jni_stub != nullptr) {
- code = boot_jni_stub;
- }
- }
+ CHECK(runtime->GetJit() != nullptr);
+ code = runtime->GetJit()->GetCodeCache()->GetJniStubCode(method);
CHECK(code != nullptr) << method->PrettyMethod();
cur_oat_quick_method_header_ = OatQuickMethodHeader::FromCodePointer(code);
}
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
index c0829b5100..179e186f6a 100644
--- a/test/667-jit-jni-stub/src/Main.java
+++ b/test/667-jit-jni-stub/src/Main.java
@@ -24,8 +24,6 @@ public class Main {
return;
}
- // Deoptimize callThrough() to ensure it can be JITed afterwards.
- deoptimizeNativeMethod(Main.class, "callThrough");
testCompilationUseAndCollection();
testMixedFramesOnStack();
}
@@ -138,7 +136,7 @@ public class Main {
if (++count == 50) {
throw new Error("TIMEOUT");
}
- }
+ };
}
public static void assertTrue(boolean value) {
@@ -156,10 +154,9 @@ public class Main {
public static void doNothing() { }
public static void throwError() { throw new Error(); }
- // Note that the callThrough()'s shorty differs from shorties of the other native methods used
- // in this test (except deoptimizeNativeMethod) because of the return type `void.`
+ // Note that the callThrough()'s shorty differs from shorties of the other
+ // native methods used in this test because of the return type `void.`
public native static void callThrough(Class<?> cls, String methodName);
- public native static void deoptimizeNativeMethod(Class<?> cls, String methodName);
public native static void jitGc();
public native static boolean isNextJitGcFull();
diff --git a/test/MyClassNatives/MyClassNatives.java b/test/MyClassNatives/MyClassNatives.java
index 787f53362a..d3bf5ff98e 100644
--- a/test/MyClassNatives/MyClassNatives.java
+++ b/test/MyClassNatives/MyClassNatives.java
@@ -37,38 +37,6 @@ class MyClassNatives {
// Normal native
native int fooI(int x);
// Normal native
- native int fooL(Object x);
- // Normal native
- native void fooI_V(int x);
- // Normal native
- native byte fooI_B(int x);
- // Normal native
- native char fooI_C(int x);
- // Normal native
- native short fooI_S(int x);
- // Normal native
- native boolean fooI_Z(int x);
- // Normal native
- native long fooI_J(int x);
- // Normal native
- native float fooI_F(int x);
- // Normal native
- native double fooI_D(int x);
- // Normal native
- native Object fooI_L(int x);
- // Normal native
- static native int sfooI(int x);
- // Normal native
- static native int sfooB(byte x);
- // Normal native
- static native int sfooC(char x);
- // Normal native
- static native int sfooS(short x);
- // Normal native
- static native int sfooZ(boolean x);
- // Normal native
- static native int sfooL(Object x);
- // Normal native
native int fooII(int x, int y);
// Normal native
native long fooJJ(long x, long y);
@@ -188,52 +156,6 @@ class MyClassNatives {
// Normal native
static native long returnLong();
- // Normal native
- static native int sfoo7FI(float f1, float f2, float f3, float f4, float f5, float f6,
- float f7, int i1);
- // Normal native
- static native int sfoo3F5DI(float f1, float f2, float f3, double d1, double d2, double d3,
- double d4, double d5, int i1);
- // Normal native
- static native int sfoo3F6DI(float f1, float f2, float f3, double d1, double d2, double d3,
- double d4, double d5, double d6, int i1);
- // Normal native
- native int fooL4I(Object o1, int i1, int i2, int i3, int i4);
- // Normal native
- native int fooL5I(Object o1, int i1, int i2, int i3, int i4, int i5);
- // Normal native
- native int fooL3IJC(Object o1, int i1, int i2, int i3, long l1, char c1);
- // Normal native
- native int fooL3IJCS(Object o1, int i1, int i2, int i3, long l1, char c1, short s1);
- // Normal native
- native int foo9F(float f1, float f2, float f3, float f4, float f5, float f6, float f7,
- float f8, float f9);
- // Normal native
- native int foo7FDF(float f1, float f2, float f3, float f4, float f5, float f6, float f7,
- double d1, float f8);
- // Normal native
- native int foo7FIFF(float f1, float f2, float f3, float f4, float f5, float f6, float f7,
- int i1, float f8, float f9);
- // Normal native
- native int foo7I(int i1, int i2, int i3, int i4, int i5, int i6, int i7);
- // Normal native
- native int foo5IJI(int i1, int i2, int i3, int i4, int i5, long l1, int i6);
- // Normal native
- native int foo5IFII(int i1, int i2, int i3, int i4, int i5, float f1, int i6, int i7);
- // Normal native
- native int foo2FL(float f1, float f2, Object o1);
- // Normal native
- native int fooFDL(float f1, double f2, Object o1);
- // Normal native
- native int foo3FL(float f1, float f2, float f3, Object o1);
- // Normal native
- native int foo2FIL(float f1, float f2, int i1, Object o1);
- // Normal native
- native int foo2IFL(int i1, int i2, float f1, Object o1);
- // Normal native
- native int fooICFL(int i1, char c1, float f1, Object o1);
- // Normal native
- native int fooICIL(int i1, char c1, int i2, Object o1);
@FastNative
@@ -362,38 +284,6 @@ class MyClassNatives {
@FastNative
static native long returnLong_Fast();
- @FastNative
- native boolean fooI_Z_Fast(int i);
- @FastNative
- native long fooI_J_Fast(int i);
- @FastNative
- native int fooICFL_Fast(int i1, char c1, float f1, Object o1);
- @FastNative
- native int foo2IFL_Fast(int i1, int i2, float f1, Object o1);
- @FastNative
- native int fooICIL_Fast(int i1, char c1, int i2, Object o1);
- @FastNative
- native int fooFDL_Fast(float f1, double d1, Object o1);
- @FastNative
- native int foo2FL_Fast(float f1, float f2, Object o1);
- @FastNative
- native int foo3FL_Fast(float f1, float f2, float f3, Object o1);
- @FastNative
- native int foo2FIL_Fast(float f1, float f2, int i1, Object o1);
- @FastNative
- native int foo7F_Fast(float f1, float f2, float f3, float f4, float f5, float f6, float f7);
- @FastNative
- native int foo3F5D_Fast(float f1, float f2, float f3, double d1, double d2, double d3,
- double d4, double d5);
- @FastNative
- native int foo3F6D_Fast(float f1, float f2, float f3, double d1, double d2, double d3,
- double d4, double d5, double d6);
- @FastNative
- native int fooL5I_Fast(Object o1, int i1, int i2, int i3, int i4, int i5);
- @FastNative
- native int fooL3IJC_Fast(Object o1, int i1, int i2, int i3, long l1, char c1);
- @FastNative
- native int fooL3IJCS_Fast(Object o1, int i1, int i2, int i3, long l1, char c1, short s1);
@CriticalNative
@@ -436,15 +326,6 @@ class MyClassNatives {
@CriticalNative
static native long returnLong_Critical();
- @CriticalNative
- static native int foo7F_Critical(float f1, float f2, float f3, float f4, float f5, float f6,
- float f7);
- @CriticalNative
- static native int foo3F5D_Critical(float f1, float f2, float f3, double d1, double d2,
- double d3, double d4, double d5);
- @CriticalNative
- static native int foo3F6D_Critical(float f1, float f2, float f3, double d1, double d2,
- double d3, double d4, double d5, double d6);
// Check for @FastNative/@CriticalNative annotation presence [or lack of presence].
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index ed0cc3e1c4..a385f4c8db 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -443,22 +443,6 @@ extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeBootImage(JNIEnv*, jclass)
Runtime::Current()->DeoptimizeBootImage();
}
-extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeNativeMethod(JNIEnv* env,
- jclass,
- jclass cls,
- jstring method_name) {
- Thread* self = Thread::Current();
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- // Make initialized classes visibly initialized to avoid entrypoint being set to boot JNI stub
- // after deoptimize.
- class_linker->MakeInitializedClassesVisiblyInitialized(self, /*wait=*/ true);
- ScopedObjectAccess soa(self);
- ScopedUtfChars chars(env, method_name);
- ArtMethod* method = GetMethod(soa, cls, chars);
- CHECK(method->IsNative());
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
-}
-
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDebuggable(JNIEnv*, jclass) {
return Runtime::Current()->IsJavaDebuggable() ? JNI_TRUE : JNI_FALSE;
}