diff options
106 files changed, 2353 insertions, 682 deletions
diff --git a/Android.mk b/Android.mk index 0d0003abb0..3438beba3f 100644 --- a/Android.mk +++ b/Android.mk @@ -146,7 +146,10 @@ else test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS) $(TEST_ART_ADB_ROOT_AND_REMOUNT) adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT) - adb push $(ANDROID_PRODUCT_OUT)/data /data +# Push the contents of the `data` dir into `/data` on the device. If +# `/data` already exists on the device, it is not overwritten, but its +# contents are updated. + adb push $(ANDROID_PRODUCT_OUT)/data / endif endif diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index dcde5abbca..291a69de10 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -248,6 +248,7 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/elf_writer_test.cc \ compiler/image_test.cc \ compiler/jni/jni_compiler_test.cc \ + compiler/linker/output_stream_test.cc \ compiler/oat_test.cc \ compiler/optimizing/bounds_check_elimination_test.cc \ compiler/optimizing/dominator_test.cc \ @@ -266,7 +267,6 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/optimizing/ssa_test.cc \ compiler/optimizing/stack_map_test.cc \ compiler/optimizing/suspend_check_test.cc \ - compiler/output_stream_test.cc \ compiler/utils/arena_allocator_test.cc \ compiler/utils/dedupe_set_test.cc \ compiler/utils/swap_space_test.cc \ @@ -382,7 +382,7 @@ LOCAL_MODULE := libart-gtest LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := cc LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc -LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler +LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/cmdline art/compiler LOCAL_SHARED_LIBRARIES := libartd libartd-compiler libdl LOCAL_STATIC_LIBRARIES += libgtest LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk @@ -399,7 +399,7 @@ LOCAL_CPP_EXTENSION := cc LOCAL_CFLAGS := $(ART_HOST_CFLAGS) LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS) LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc -LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler +LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/cmdline art/compiler LOCAL_SHARED_LIBRARIES := libartd libartd-compiler LOCAL_STATIC_LIBRARIES := libgtest_host LOCAL_LDLIBS += -ldl -lpthread @@ -542,7 +542,7 @@ define define-art-gtest endif LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION) LOCAL_SRC_FILES := $$(art_gtest_filename) - LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime $$(art_gtest_extra_c_includes) + LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime art/cmdline $$(art_gtest_extra_c_includes) LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries) libart-gtest libartd-disassembler LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index c594adbc94..47519894eb 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -18,17 +18,17 @@ #define CMDLINE_NDEBUG 1 // Do not output any debugging information for parsing. -#include "cmdline/memory_representation.h" -#include "cmdline/detail/cmdline_debug_detail.h" +#include "memory_representation.h" +#include "detail/cmdline_debug_detail.h" #include "cmdline_type_parser.h" // Includes for the types that are being specialized #include <string> #include "unit.h" #include "jdwp/jdwp.h" -#include "runtime/base/logging.h" -#include "runtime/base/time_utils.h" -#include "runtime/experimental_flags.h" +#include "base/logging.h" +#include "base/time_utils.h" +#include "experimental_flags.h" #include "gc/collector_type.h" #include "gc/space/large_object_space.h" #include "profiler_options.h" diff --git a/cmdline/detail/cmdline_parse_argument_detail.h b/cmdline/detail/cmdline_parse_argument_detail.h index 3009b32162..4b56804ea6 100644 --- a/cmdline/detail/cmdline_parse_argument_detail.h +++ b/cmdline/detail/cmdline_parse_argument_detail.h @@ -25,10 +25,10 @@ #include <numeric> #include <memory> -#include "cmdline/cmdline_parse_result.h" -#include "cmdline/token_range.h" -#include "cmdline/unit.h" -#include "cmdline/cmdline_types.h" +#include "cmdline_parse_result.h" +#include "cmdline_types.h" +#include "token_range.h" +#include "unit.h" namespace art { // Implementation details for the parser. Do not look inside if you hate templates. diff --git a/compiler/Android.mk b/compiler/Android.mk index 0ed843b918..348eabdde5 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -58,6 +58,10 @@ LIBART_COMPILER_SRC_FILES := \ driver/compiler_driver.cc \ driver/compiler_options.cc \ driver/dex_compilation_unit.cc \ + linker/buffered_output_stream.cc \ + linker/file_output_stream.cc \ + linker/output_stream.cc \ + linker/vector_output_stream.cc \ linker/relative_patcher.cc \ jit/jit_compiler.cc \ jni/quick/calling_convention.cc \ @@ -100,16 +104,12 @@ LIBART_COMPILER_SRC_FILES := \ trampolines/trampoline_compiler.cc \ utils/assembler.cc \ utils/swap_space.cc \ - buffered_output_stream.cc \ compiler.cc \ elf_writer.cc \ elf_writer_debug.cc \ elf_writer_quick.cc \ - file_output_stream.cc \ image_writer.cc \ - oat_writer.cc \ - output_stream.cc \ - vector_output_stream.cc + oat_writer.cc LIBART_COMPILER_SRC_FILES_arm := \ dex/quick/arm/assemble_arm.cc \ diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h index 5464ed9c49..c3a3ca9425 100644 --- a/compiler/dwarf/dwarf_test.h +++ b/compiler/dwarf/dwarf_test.h @@ -29,6 +29,7 @@ #include "common_runtime_test.h" #include "elf_builder.h" #include "gtest/gtest.h" +#include "linker/file_output_stream.h" #include "os.h" namespace art { diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index c19bc3db5c..bb07cc2913 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -23,10 +23,9 @@ #include "base/bit_utils.h" #include "base/casts.h" #include "base/unix_file/fd_file.h" -#include "buffered_output_stream.h" #include "elf_utils.h" -#include "file_output_stream.h" #include "leb128.h" +#include "linker/error_delaying_output_stream.h" #include "utils/array_ref.h" namespace art { @@ -121,8 +120,8 @@ class ElfBuilder FINAL { sections.push_back(this); // Align file position. if (header_.sh_type != SHT_NOBITS) { - header_.sh_offset = RoundUp(owner_->Seek(0, kSeekCurrent), header_.sh_addralign); - owner_->Seek(header_.sh_offset, kSeekSet); + header_.sh_offset = RoundUp(owner_->stream_.Seek(0, kSeekCurrent), header_.sh_addralign); + owner_->stream_.Seek(header_.sh_offset, kSeekSet); } // Align virtual memory address. if ((header_.sh_flags & SHF_ALLOC) != 0) { @@ -140,7 +139,7 @@ class ElfBuilder FINAL { CHECK_GT(header_.sh_size, 0u); } else { // Use the current file position to determine section size. - off_t file_offset = owner_->Seek(0, kSeekCurrent); + off_t file_offset = owner_->stream_.Seek(0, kSeekCurrent); CHECK_GE(file_offset, (off_t)header_.sh_offset); header_.sh_size = file_offset - header_.sh_offset; } @@ -162,7 +161,7 @@ class ElfBuilder FINAL { } else { CHECK(started_); CHECK_NE(header_.sh_type, (Elf_Word)SHT_NOBITS); - return owner_->Seek(0, kSeekCurrent) - header_.sh_offset; + return owner_->stream_.Seek(0, kSeekCurrent) - header_.sh_offset; } } @@ -177,21 +176,20 @@ class ElfBuilder FINAL { bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE { CHECK(started_); CHECK(!finished_); - owner_->WriteFully(buffer, byte_count); - return true; + return owner_->stream_.WriteFully(buffer, byte_count); } // This function always succeeds to simplify code. // Use builder's Good() to check the actual status. off_t Seek(off_t offset, Whence whence) OVERRIDE { // Forward the seek as-is and trust the caller to use it reasonably. - return owner_->Seek(offset, whence); + return owner_->stream_.Seek(offset, whence); } // This function flushes the output and returns whether it succeeded. // If there was a previous failure, this does nothing and returns false, i.e. failed. bool Flush() OVERRIDE { - return owner_->Flush(); + return owner_->stream_.Flush(); } Elf_Word GetSectionIndex() const { @@ -277,26 +275,24 @@ class ElfBuilder FINAL { }; ElfBuilder(InstructionSet isa, OutputStream* output) - : isa_(isa), - output_(output), - output_good_(true), - output_offset_(0), - rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), - text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0), - bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), - dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize), - dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_), - hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)), - dynamic_(this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_, 0, kPageSize, sizeof(Elf_Dyn)), - eh_frame_(this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), - eh_frame_hdr_(this, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0), - strtab_(this, ".strtab", 0, kPageSize), - symtab_(this, ".symtab", SHT_SYMTAB, 0, &strtab_), - debug_frame_(this, ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, sizeof(Elf_Addr), 0), - debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0), - debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0), - shstrtab_(this, ".shstrtab", 0, 1), - virtual_address_(0) { + : isa_(isa), + stream_(output), + rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), + text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0), + bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), + dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize), + dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_), + hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)), + dynamic_(this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_, 0, kPageSize, sizeof(Elf_Dyn)), + eh_frame_(this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), + eh_frame_hdr_(this, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0), + strtab_(this, ".strtab", 0, kPageSize), + symtab_(this, ".symtab", SHT_SYMTAB, 0, &strtab_), + debug_frame_(this, ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, sizeof(Elf_Addr), 0), + debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0), + debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0), + shstrtab_(this, ".shstrtab", 0, 1), + virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; dynamic_.phdr_flags_ = PF_R | PF_W; @@ -353,7 +349,7 @@ class ElfBuilder FINAL { // We do not know the number of headers until later, so // it is easiest to just reserve a fixed amount of space. int size = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders; - Seek(size, kSeekSet); + stream_.Seek(size, kSeekSet); virtual_address_ += size; } @@ -377,9 +373,14 @@ class ElfBuilder FINAL { shdrs.push_back(section->header_); } Elf_Off section_headers_offset; - section_headers_offset = RoundUp(Seek(0, kSeekCurrent), sizeof(Elf_Off)); - Seek(section_headers_offset, kSeekSet); - WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0])); + section_headers_offset = RoundUp(stream_.Seek(0, kSeekCurrent), sizeof(Elf_Off)); + stream_.Seek(section_headers_offset, kSeekSet); + stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0])); + + // Flush everything else before writing the program headers. This should prevent + // the OS from reordering writes, so that we don't end up with valid headers + // and partially written data if we suddenly lose power, for example. + stream_.Flush(); // Write the initial file headers. std::vector<Elf_Phdr> phdrs = MakeProgramHeaders(); @@ -389,10 +390,10 @@ class ElfBuilder FINAL { elf_header.e_phnum = phdrs.size(); elf_header.e_shnum = shdrs.size(); elf_header.e_shstrndx = shstrtab_.GetSectionIndex(); - Seek(0, kSeekSet); - WriteFully(&elf_header, sizeof(elf_header)); - WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); - Flush(); + stream_.Seek(0, kSeekSet); + stream_.WriteFully(&elf_header, sizeof(elf_header)); + stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); + stream_.Flush(); } // The running program does not have access to section headers @@ -470,60 +471,15 @@ class ElfBuilder FINAL { // Returns true if all writes and seeks on the output stream succeeded. bool Good() { - return output_good_; + return stream_.Good(); } - private: - // This function always succeeds to simplify code. - // Use Good() to check the actual status of the output stream. - void WriteFully(const void* buffer, size_t byte_count) { - if (output_good_) { - if (!output_->WriteFully(buffer, byte_count)) { - PLOG(ERROR) << "Failed to write " << byte_count - << " bytes to ELF file at offset " << output_offset_; - output_good_ = false; - } - } - output_offset_ += byte_count; - } - - // This function always succeeds to simplify code. - // Use Good() to check the actual status of the output stream. - off_t Seek(off_t offset, Whence whence) { - // We keep shadow copy of the offset so that we return - // the expected value even if the output stream failed. - off_t new_offset; - switch (whence) { - case kSeekSet: - new_offset = offset; - break; - case kSeekCurrent: - new_offset = output_offset_ + offset; - break; - default: - LOG(FATAL) << "Unsupported seek type: " << whence; - UNREACHABLE(); - } - if (output_good_) { - off_t actual_offset = output_->Seek(offset, whence); - if (actual_offset == (off_t)-1) { - PLOG(ERROR) << "Failed to seek in ELF file. Offset=" << offset - << " whence=" << whence << " new_offset=" << new_offset; - output_good_ = false; - } - DCHECK_EQ(actual_offset, new_offset); - } - output_offset_ = new_offset; - return new_offset; - } - - bool Flush() { - if (output_good_) { - output_good_ = output_->Flush(); - } - return output_good_; + // Returns the builder's internal stream. + OutputStream* GetStream() { + return &stream_; } + private: static Elf_Ehdr MakeElfHeader(InstructionSet isa) { Elf_Ehdr elf_header = Elf_Ehdr(); switch (isa) { @@ -675,9 +631,7 @@ class ElfBuilder FINAL { InstructionSet isa_; - OutputStream* output_; - bool output_good_; // True if all writes to output succeeded. - off_t output_offset_; // Keep track of the current position in the stream. + ErrorDelayingOutputStream stream_; Section rodata_; Section text_; diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index 357d5f624e..c5a0fd50bd 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -62,6 +62,11 @@ class ElfWriter { virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0; virtual bool End() = 0; + // Get the ELF writer's stream. This stream can be used for writing data directly + // to a section after the section has been finished. When that's done, the user + // should Seek() back to the position where the stream was before this operation. + virtual OutputStream* GetStream() = 0; + protected: ElfWriter() = default; }; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 9da2af8d3e..e411496980 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -31,6 +31,8 @@ #include "elf_writer_debug.h" #include "globals.h" #include "leb128.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "utils.h" namespace art { @@ -72,6 +74,8 @@ class ElfWriterQuick FINAL : public ElfWriter { void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE; bool End() OVERRIDE; + virtual OutputStream* GetStream() OVERRIDE; + static void EncodeOatPatches(const std::vector<uintptr_t>& locations, std::vector<uint8_t>* buffer); @@ -191,6 +195,11 @@ bool ElfWriterQuick<ElfTypes>::End() { } template <typename ElfTypes> +OutputStream* ElfWriterQuick<ElfTypes>::GetStream() { + return builder_->GetStream(); +} + +template <typename ElfTypes> static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { bool generated_mapping_symbol = false; diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 5f4a92299b..cda6240bd4 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -34,7 +34,6 @@ #include "scoped_thread_state_change.h" #include "signal_catcher.h" #include "utils.h" -#include "vector_output_stream.h" namespace art { diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 341742e4dc..bf1fcdd5f5 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -540,7 +540,10 @@ ImageWriter::BinSlot ImageWriter::GetImageBinSlot(mirror::Object* object) const } bool ImageWriter::AllocMemory() { - const size_t length = RoundUp(image_objects_offset_begin_ + GetBinSizeSum() + intern_table_bytes_, + const size_t length = RoundUp(image_objects_offset_begin_ + + GetBinSizeSum() + + intern_table_bytes_ + + class_table_bytes_, kPageSize); std::string error_msg; image_.reset(MemMap::MapAnonymous("image writer image", @@ -1030,6 +1033,14 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { WalkFieldsInOrder(value); } } + } else if (h_obj->IsClassLoader()) { + // Register the class loader if it has a class table. + // The fake boot class loader should not get registered and we should end up with only one + // class loader. + mirror::ClassLoader* class_loader = h_obj->AsClassLoader(); + if (class_loader->GetClassTable() != nullptr) { + class_loaders_.insert(class_loader); + } } } } @@ -1154,10 +1165,26 @@ void ImageWriter::CalculateNewObjectOffsets() { } // Calculate how big the intern table will be after being serialized. - auto* const intern_table = Runtime::Current()->GetInternTable(); + InternTable* const intern_table = runtime->GetInternTable(); CHECK_EQ(intern_table->WeakSize(), 0u) << " should have strong interned all the strings"; intern_table_bytes_ = intern_table->WriteToMemory(nullptr); + // Write out the class table. + ClassLinker* class_linker = runtime->GetClassLinker(); + if (boot_image_space_ == nullptr) { + // Compiling the boot image, add null class loader. + class_loaders_.insert(nullptr); + } + if (!class_loaders_.empty()) { + CHECK_EQ(class_loaders_.size(), 1u) << "Should only have one real class loader in the image"; + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + for (mirror::ClassLoader* loader : class_loaders_) { + ClassTable* table = class_linker->ClassTableForClassLoader(loader); + CHECK(table != nullptr); + class_table_bytes_ += table->WriteToMemory(nullptr); + } + } + // Note that image_end_ is left at end of used mirror object section. } @@ -1199,6 +1226,12 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { auto* interned_strings_section = §ions[ImageHeader::kSectionInternedStrings]; *interned_strings_section = ImageSection(cur_pos, intern_table_bytes_); cur_pos = interned_strings_section->End(); + // Calculate the size of the class table section. + auto* class_table_section = §ions[ImageHeader::kSectionClassTable]; + *class_table_section = ImageSection(cur_pos, class_table_bytes_); + cur_pos = class_table_section->End(); + // Image end goes right before the start of the image bitmap. + const size_t image_end = static_cast<uint32_t>(cur_pos); // Finally bitmap section. const size_t bitmap_bytes = image_bitmap_->Size(); auto* bitmap_section = §ions[ImageHeader::kSectionImageBitmap]; @@ -1212,7 +1245,6 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { } LOG(INFO) << "Methods: clean=" << clean_methods_ << " dirty=" << dirty_methods_; } - const size_t image_end = static_cast<uint32_t>(interned_strings_section->End()); CHECK_EQ(AlignUp(image_begin_ + image_end, kPageSize), oat_file_begin) << "Oat file should be right after the image."; // Create the header. @@ -1323,23 +1355,48 @@ void ImageWriter::CopyAndFixupNativeData() { } image_header->SetImageMethod(static_cast<ImageHeader::ImageMethod>(i), method); } + FixupRootVisitor root_visitor(this); + // Write the intern table into the image. const ImageSection& intern_table_section = image_header->GetImageSection( ImageHeader::kSectionInternedStrings); - InternTable* const intern_table = Runtime::Current()->GetInternTable(); - uint8_t* const memory_ptr = image_->Begin() + intern_table_section.Offset(); - const size_t intern_table_bytes = intern_table->WriteToMemory(memory_ptr); + Runtime* const runtime = Runtime::Current(); + InternTable* const intern_table = runtime->GetInternTable(); + uint8_t* const intern_table_memory_ptr = image_->Begin() + intern_table_section.Offset(); + const size_t intern_table_bytes = intern_table->WriteToMemory(intern_table_memory_ptr); + CHECK_EQ(intern_table_bytes, intern_table_bytes_); // Fixup the pointers in the newly written intern table to contain image addresses. - InternTable temp_table; + InternTable temp_intern_table; // Note that we require that ReadFromMemory does not make an internal copy of the elements so that // the VisitRoots() will update the memory directly rather than the copies. // This also relies on visit roots not doing any verification which could fail after we update // the roots to be the image addresses. - temp_table.ReadFromMemory(memory_ptr); - CHECK_EQ(temp_table.Size(), intern_table->Size()); - FixupRootVisitor visitor(this); - temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); - CHECK_EQ(intern_table_bytes, intern_table_bytes_); + temp_intern_table.ReadFromMemory(intern_table_memory_ptr); + CHECK_EQ(temp_intern_table.Size(), intern_table->Size()); + temp_intern_table.VisitRoots(&root_visitor, kVisitRootFlagAllRoots); + + // Write the class table(s) into the image. + ClassLinker* const class_linker = runtime->GetClassLinker(); + const ImageSection& class_table_section = image_header->GetImageSection( + ImageHeader::kSectionClassTable); + uint8_t* const class_table_memory_ptr = image_->Begin() + class_table_section.Offset(); + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + size_t class_table_bytes = 0; + for (mirror::ClassLoader* loader : class_loaders_) { + ClassTable* table = class_linker->ClassTableForClassLoader(loader); + CHECK(table != nullptr); + uint8_t* memory_ptr = class_table_memory_ptr + class_table_bytes; + class_table_bytes += table->WriteToMemory(memory_ptr); + // Fixup the pointers in the newly written class table to contain image addresses. See + // above comment for intern tables. + ClassTable temp_class_table; + temp_class_table.ReadFromMemory(memory_ptr); + // CHECK_EQ(temp_class_table.NumNonZygoteClasses(), table->NumNonZygoteClasses()); + BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&root_visitor, + RootInfo(kRootUnknown)); + temp_class_table.VisitRoots(buffered_visitor); + } + CHECK_EQ(class_table_bytes, class_table_bytes_); } void ImageWriter::CopyAndFixupObjects() { @@ -1553,8 +1610,7 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (klass == class_linker->GetClassRoot(ClassLinker::kJavaLangDexCache)) { FixupDexCache(down_cast<mirror::DexCache*>(orig), down_cast<mirror::DexCache*>(copy)); - } else if (klass->IsSubClass(down_cast<mirror::Class*>( - class_linker->GetClassRoot(ClassLinker::kJavaLangClassLoader)))) { + } else if (klass->IsClassLoaderClass()) { // If src is a ClassLoader, set the class table to null so that it gets recreated by the // ClassLoader. down_cast<mirror::ClassLoader*>(copy)->SetClassTable(nullptr); @@ -1840,7 +1896,8 @@ uint8_t* ImageWriter::GetOatFileBegin() const { bin_slot_sizes_[kBinArtMethodDirty] + bin_slot_sizes_[kBinArtMethodClean] + bin_slot_sizes_[kBinDexCacheArray] + - intern_table_bytes_; + intern_table_bytes_ + + class_table_bytes_; return image_begin_ + RoundUp(image_end_ + native_sections_size, kPageSize); } diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 889cd10dc4..386838fde0 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -72,7 +72,8 @@ class ImageWriter FINAL { intern_table_bytes_(0u), image_method_array_(ImageHeader::kImageMethodsCount), dirty_methods_(0u), - clean_methods_(0u) { + clean_methods_(0u), + class_table_bytes_(0u) { CHECK_NE(image_begin, 0U); std::fill_n(image_methods_, arraysize(image_methods_), nullptr); std::fill_n(oat_address_offsets_, arraysize(oat_address_offsets_), 0); @@ -453,6 +454,12 @@ class ImageWriter FINAL { // Prune class memoization table to speed up ContainsBootClassLoaderNonImageClass. std::unordered_map<mirror::Class*, bool> prune_class_memo_; + // Class loaders with a class table to write out. Should only be one currently. + std::unordered_set<mirror::ClassLoader*> class_loaders_; + + // Number of image class table bytes. + size_t class_table_bytes_; + friend class ContainsBootClassLoaderNonImageClassVisitor; friend class FixupClassVisitor; friend class FixupRootVisitor; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 2125c9a26a..d001495442 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -170,18 +170,6 @@ bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) { self->AssertNoPendingException(); Runtime* runtime = Runtime::Current(); - // Check if the method is already compiled. - if (runtime->GetJit()->GetCodeCache()->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { - VLOG(jit) << "Already compiled " << PrettyMethod(method); - return true; - } - - // Don't compile the method if we are supposed to be deoptimized. - instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation(); - if (instrumentation->AreAllMethodsDeoptimized() || instrumentation->IsDeoptimized(method)) { - return false; - } - // Ensure the class is initialized. Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { @@ -190,13 +178,13 @@ bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) { } // Do the compilation. - JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache(); bool success = false; { TimingLogger::ScopedTiming t2("Compiling", &logger); // If we get a request to compile a proxy method, we pass the actual Java method // of that proxy method, as the compiler does not expect a proxy method. ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*)); + JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache(); success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method_to_compile); } diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index 13754fdaa1..73b0facf4b 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -17,9 +17,9 @@ #include "linker/arm/relative_patcher_arm_base.h" #include "compiled_method.h" +#include "linker/output_stream.h" #include "oat.h" #include "oat_quick_method_header.h" -#include "output_stream.h" namespace art { namespace linker { diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 57018af840..3d4c2184f1 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -20,10 +20,10 @@ #include "art_method.h" #include "compiled_method.h" #include "driver/compiler_driver.h" -#include "utils/arm64/assembler_arm64.h" +#include "linker/output_stream.h" #include "oat.h" #include "oat_quick_method_header.h" -#include "output_stream.h" +#include "utils/arm64/assembler_arm64.h" namespace art { namespace linker { diff --git a/compiler/buffered_output_stream.cc b/compiler/linker/buffered_output_stream.cc index 4c66c764a9..4c66c764a9 100644 --- a/compiler/buffered_output_stream.cc +++ b/compiler/linker/buffered_output_stream.cc diff --git a/compiler/buffered_output_stream.h b/compiler/linker/buffered_output_stream.h index 1da3a6932f..a2eefbbf17 100644 --- a/compiler/buffered_output_stream.h +++ b/compiler/linker/buffered_output_stream.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_BUFFERED_OUTPUT_STREAM_H_ -#define ART_COMPILER_BUFFERED_OUTPUT_STREAM_H_ +#ifndef ART_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_ +#define ART_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_ #include <memory> @@ -51,4 +51,4 @@ class BufferedOutputStream FINAL : public OutputStream { } // namespace art -#endif // ART_COMPILER_BUFFERED_OUTPUT_STREAM_H_ +#endif // ART_COMPILER_LINKER_BUFFERED_OUTPUT_STREAM_H_ diff --git a/compiler/linker/error_delaying_output_stream.h b/compiler/linker/error_delaying_output_stream.h new file mode 100644 index 0000000000..99410e4bb1 --- /dev/null +++ b/compiler/linker/error_delaying_output_stream.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 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_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_ +#define ART_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_ + +#include "output_stream.h" + +#include "base/logging.h" + +namespace art { + +// OutputStream wrapper that delays reporting an error until Flush(). +class ErrorDelayingOutputStream FINAL : public OutputStream { + public: + explicit ErrorDelayingOutputStream(OutputStream* output) + : OutputStream(output->GetLocation()), + output_(output), + output_good_(true), + output_offset_(0) { } + + // This function always succeeds to simplify code. + // Use Good() to check the actual status of the output stream. + bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE { + if (output_good_) { + if (!output_->WriteFully(buffer, byte_count)) { + PLOG(ERROR) << "Failed to write " << byte_count + << " bytes to " << GetLocation() << " at offset " << output_offset_; + output_good_ = false; + } + } + output_offset_ += byte_count; + return true; + } + + // This function always succeeds to simplify code. + // Use Good() to check the actual status of the output stream. + off_t Seek(off_t offset, Whence whence) OVERRIDE { + // We keep shadow copy of the offset so that we return + // the expected value even if the output stream failed. + off_t new_offset; + switch (whence) { + case kSeekSet: + new_offset = offset; + break; + case kSeekCurrent: + new_offset = output_offset_ + offset; + break; + default: + LOG(FATAL) << "Unsupported seek type: " << whence; + UNREACHABLE(); + } + if (output_good_) { + off_t actual_offset = output_->Seek(offset, whence); + if (actual_offset == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to seek in " << GetLocation() << ". Offset=" << offset + << " whence=" << whence << " new_offset=" << new_offset; + output_good_ = false; + } + DCHECK_EQ(actual_offset, new_offset); + } + output_offset_ = new_offset; + return new_offset; + } + + // Flush the output and return whether all operations have succeeded. + // Do nothing if we already have a pending error. + bool Flush() OVERRIDE { + if (output_good_) { + output_good_ = output_->Flush(); + } + return output_good_; + } + + // Check (without flushing) whether all operations have succeeded so far. + bool Good() const { + return output_good_; + } + + private: + OutputStream* output_; + bool output_good_; // True if all writes to output succeeded. + off_t output_offset_; // Keep track of the current position in the stream. +}; + +} // namespace art + +#endif // ART_COMPILER_LINKER_ERROR_DELAYING_OUTPUT_STREAM_H_ diff --git a/compiler/file_output_stream.cc b/compiler/linker/file_output_stream.cc index bbfbdfdca8..bbfbdfdca8 100644 --- a/compiler/file_output_stream.cc +++ b/compiler/linker/file_output_stream.cc diff --git a/compiler/file_output_stream.h b/compiler/linker/file_output_stream.h index 6917d83f29..f2d845379f 100644 --- a/compiler/file_output_stream.h +++ b/compiler/linker/file_output_stream.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_FILE_OUTPUT_STREAM_H_ -#define ART_COMPILER_FILE_OUTPUT_STREAM_H_ +#ifndef ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_ +#define ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_ #include "output_stream.h" @@ -43,4 +43,4 @@ class FileOutputStream FINAL : public OutputStream { } // namespace art -#endif // ART_COMPILER_FILE_OUTPUT_STREAM_H_ +#endif // ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_ diff --git a/compiler/output_stream.cc b/compiler/linker/output_stream.cc index a8b64ca1ce..a8b64ca1ce 100644 --- a/compiler/output_stream.cc +++ b/compiler/linker/output_stream.cc diff --git a/compiler/output_stream.h b/compiler/linker/output_stream.h index 8f6b6d8235..96a5f489f0 100644 --- a/compiler/output_stream.h +++ b/compiler/linker/output_stream.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_OUTPUT_STREAM_H_ -#define ART_COMPILER_OUTPUT_STREAM_H_ +#ifndef ART_COMPILER_LINKER_OUTPUT_STREAM_H_ +#define ART_COMPILER_LINKER_OUTPUT_STREAM_H_ #include <ostream> #include <string> @@ -61,4 +61,4 @@ class OutputStream { } // namespace art -#endif // ART_COMPILER_OUTPUT_STREAM_H_ +#endif // ART_COMPILER_LINKER_OUTPUT_STREAM_H_ diff --git a/compiler/output_stream_test.cc b/compiler/linker/output_stream_test.cc index 84c76f2c6c..84c76f2c6c 100644 --- a/compiler/output_stream_test.cc +++ b/compiler/linker/output_stream_test.cc diff --git a/compiler/vector_output_stream.cc b/compiler/linker/vector_output_stream.cc index 3d33673e1a..f758005c52 100644 --- a/compiler/vector_output_stream.cc +++ b/compiler/linker/vector_output_stream.cc @@ -21,7 +21,7 @@ namespace art { VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>* vector) - : OutputStream(location), offset_(vector->size()), vector_(vector) {} + : OutputStream(location), offset_(vector->size()), vector_(vector) {} off_t VectorOutputStream::Seek(off_t offset, Whence whence) { CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence; diff --git a/compiler/vector_output_stream.h b/compiler/linker/vector_output_stream.h index a3c58d0800..321014374e 100644 --- a/compiler/vector_output_stream.h +++ b/compiler/linker/vector_output_stream.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ -#define ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ +#ifndef ART_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_ +#define ART_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_ #include "output_stream.h" @@ -66,4 +66,4 @@ class VectorOutputStream FINAL : public OutputStream { } // namespace art -#endif // ART_COMPILER_VECTOR_OUTPUT_STREAM_H_ +#endif // ART_COMPILER_LINKER_VECTOR_OUTPUT_STREAM_H_ diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index c305b120cb..b8610d0a7a 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -31,13 +31,13 @@ #include "elf_writer.h" #include "elf_writer_quick.h" #include "entrypoints/quick/quick_entrypoints.h" +#include "linker/vector_output_stream.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "oat_file-inl.h" #include "oat_writer.h" #include "scoped_thread_state_change.h" -#include "vector_output_stream.h" namespace art { diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 901580079a..e8e775f2c8 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -36,6 +36,7 @@ #include "gc/space/space.h" #include "handle_scope-inl.h" #include "image_writer.h" +#include "linker/output_stream.h" #include "linker/relative_patcher.h" #include "mirror/array.h" #include "mirror/class_loader.h" @@ -43,7 +44,6 @@ #include "mirror/object-inl.h" #include "oat_quick_method_header.h" #include "os.h" -#include "output_stream.h" #include "safe_map.h" #include "scoped_thread_state_change.h" #include "type_lookup_table.h" diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index a44830207d..7dbfd7c58e 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -1228,19 +1228,26 @@ class BCEVisitor : public HGraphVisitor { InductionVarRange::Value v2; bool needs_finite_test = false; induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test); - if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) && - v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) { - DCHECK(v1.a_constant == 1 || v1.instruction == nullptr); - DCHECK(v2.a_constant == 1 || v2.instruction == nullptr); - ValueRange index_range(GetGraph()->GetArena(), - ValueBound(v1.instruction, v1.b_constant), - ValueBound(v2.instruction, v2.b_constant)); - // If analysis reveals a certain OOB, disable dynamic BCE. - *try_dynamic_bce = !index_range.GetLower().LessThan(array_range->GetLower()) && - !index_range.GetUpper().GreaterThan(array_range->GetUpper()); - // Use analysis for static bce only if loop is finite. - return !needs_finite_test && index_range.FitsIn(array_range); - } + do { + if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) && + v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) { + DCHECK(v1.a_constant == 1 || v1.instruction == nullptr); + DCHECK(v2.a_constant == 1 || v2.instruction == nullptr); + ValueRange index_range(GetGraph()->GetArena(), + ValueBound(v1.instruction, v1.b_constant), + ValueBound(v2.instruction, v2.b_constant)); + // If analysis reveals a certain OOB, disable dynamic BCE. + if (index_range.GetLower().LessThan(array_range->GetLower()) || + index_range.GetUpper().GreaterThan(array_range->GetUpper())) { + *try_dynamic_bce = false; + return false; + } + // Use analysis for static bce only if loop is finite. + if (!needs_finite_test && index_range.FitsIn(array_range)) { + return true; + } + } + } while (induction_range_.RefineOuter(&v1, &v2)); return false; } diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index 2ac1e152e1..9d0cde7c9f 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -119,6 +119,17 @@ void InductionVarRange::GetInductionRange(HInstruction* context, } } +bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) { + Value v1 = RefineOuter(*min_val, /* is_min */ true); + Value v2 = RefineOuter(*max_val, /* is_min */ false); + if (v1.instruction != min_val->instruction || v2.instruction != max_val->instruction) { + *min_val = v1; + *max_val = v2; + return true; + } + return false; +} + bool InductionVarRange::CanGenerateCode(HInstruction* context, HInstruction* instruction, /*out*/bool* needs_finite_test, @@ -202,6 +213,8 @@ InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction, } else if (IsIntAndGet(instruction->InputAt(1), &value)) { return AddValue(GetFetch(instruction->InputAt(0), trip, in_body, is_min), Value(value)); } + } else if (instruction->IsArrayLength() && instruction->InputAt(0)->IsNewArray()) { + return GetFetch(instruction->InputAt(0)->InputAt(0), trip, in_body, is_min); } else if (is_min) { // Special case for finding minimum: minimum of trip-count in loop-body is 1. if (trip != nullptr && in_body && instruction == trip->op_a->fetch) { @@ -404,6 +417,25 @@ InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is return Value(); } +InductionVarRange::Value InductionVarRange::RefineOuter(Value v, bool is_min) { + if (v.instruction != nullptr) { + HLoopInformation* loop = + v.instruction->GetBlock()->GetLoopInformation(); // closest enveloping loop + if (loop != nullptr) { + // Set up loop information. + bool in_body = true; // use is always in body of outer loop + HInductionVarAnalysis::InductionInfo* info = + induction_analysis_->LookupInfo(loop, v.instruction); + HInductionVarAnalysis::InductionInfo* trip = + induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction()); + // Try to refine "a x instruction + b" with outer loop range information on instruction. + return AddValue(MulValue(Value(v.a_constant), GetVal(info, trip, in_body, is_min)), + Value(v.b_constant)); + } + } + return v; +} + bool InductionVarRange::GenerateCode(HInstruction* context, HInstruction* instruction, HGraph* graph, diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h index 7984871b08..71b0b1b4c3 100644 --- a/compiler/optimizing/induction_var_range.h +++ b/compiler/optimizing/induction_var_range.h @@ -68,6 +68,9 @@ class InductionVarRange { /*out*/Value* max_val, /*out*/bool* needs_finite_test); + /** Refines the values with induction of next outer loop. Returns true on change. */ + bool RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val); + /** * Returns true if range analysis is able to generate code for the lower and upper * bound expressions on the instruction in the given context. The need_finite_test @@ -149,6 +152,12 @@ class InductionVarRange { static Value MergeVal(Value v1, Value v2, bool is_min); /** + * Returns refined value using induction of next outer loop or the input value if no + * further refinement is possible. + */ + Value RefineOuter(Value val, bool is_min); + + /** * Generates code for lower/upper/taken-test in the HIR. Returns true on success. * With values nullptr, the method can be used to determine if code generation * would be successful without generating actual code yet. diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc index c2ba157ed8..128b5bb811 100644 --- a/compiler/optimizing/induction_var_range_test.cc +++ b/compiler/optimizing/induction_var_range_test.cc @@ -473,16 +473,19 @@ TEST_F(InductionVarRangeTest, ConstantTripCountUp) { EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); // In context of loop-body: known. range.GetInductionRange(increment_, condition_->InputAt(0), &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(999), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); range.GetInductionRange(increment_, increment_, &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(1), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); } TEST_F(InductionVarRangeTest, ConstantTripCountDown) { @@ -498,16 +501,19 @@ TEST_F(InductionVarRangeTest, ConstantTripCountDown) { EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); // In context of loop-body: known. range.GetInductionRange(increment_, condition_->InputAt(0), &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(1), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); range.GetInductionRange(increment_, increment_, &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(999), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); } TEST_F(InductionVarRangeTest, SymbolicTripCountUp) { @@ -527,16 +533,19 @@ TEST_F(InductionVarRangeTest, SymbolicTripCountUp) { EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); // In context of loop-body: known. range.GetInductionRange(increment_, condition_->InputAt(0), &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(0), v1); ExpectEqual(Value(parameter, 1, -1), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); range.GetInductionRange(increment_, increment_, &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(1), v1); ExpectEqual(Value(parameter, 1, 0), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); HInstruction* lower = nullptr; HInstruction* upper = nullptr; @@ -597,16 +606,19 @@ TEST_F(InductionVarRangeTest, SymbolicTripCountDown) { EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); // In context of loop-body: known. range.GetInductionRange(increment_, condition_->InputAt(0), &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(parameter, 1, 1), v1); ExpectEqual(Value(1000), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); range.GetInductionRange(increment_, increment_, &v1, &v2, &needs_finite_test); EXPECT_FALSE(needs_finite_test); ExpectEqual(Value(parameter, 1, 0), v1); ExpectEqual(Value(999), v2); + EXPECT_FALSE(range.RefineOuter(&v1, &v2)); HInstruction* lower = nullptr; HInstruction* upper = nullptr; diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 6d93be37a7..a4dcb3aeba 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -171,13 +171,37 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, const DexFile& dex_file, uint32_t referrer_index) SHARED_REQUIRES(Locks::mutator_lock_) { - if (method->GetDexFile()->GetLocation().compare(dex_file.GetLocation()) == 0) { + if (IsSameDexFile(*method->GetDexFile(), dex_file)) { return method->GetDexMethodIndex(); } else { return method->FindDexMethodIndexInOtherDexFile(dex_file, referrer_index); } } +static uint32_t FindClassIndexIn(mirror::Class* cls, const DexFile& dex_file) + SHARED_REQUIRES(Locks::mutator_lock_) { + if (cls->GetDexCache() == nullptr) { + DCHECK(cls->IsArrayClass()); + // TODO: find the class in `dex_file`. + return DexFile::kDexNoIndex; + } else if (cls->GetDexTypeIndex() == DexFile::kDexNoIndex16) { + // TODO: deal with proxy classes. + return DexFile::kDexNoIndex; + } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) { + // Update the dex cache to ensure the class is in. The generated code will + // consider it is. We make it safe by updating the dex cache, as other + // dex files might also load the class, and there is no guarantee the dex + // cache of the dex file of the class will be updated. + if (cls->GetDexCache()->GetResolvedType(cls->GetDexTypeIndex()) == nullptr) { + cls->GetDexCache()->SetResolvedType(cls->GetDexTypeIndex(), cls); + } + return cls->GetDexTypeIndex(); + } else { + // TODO: find the class in `dex_file`. + return DexFile::kDexNoIndex; + } +} + bool HInliner::TryInline(HInvoke* invoke_instruction) { if (invoke_instruction->IsInvokeUnresolved()) { return false; // Don't bother to move further if we know the method is unresolved. @@ -214,53 +238,176 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { return false; } - if (!invoke_instruction->IsInvokeStaticOrDirect()) { - resolved_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method); - if (resolved_method == nullptr) { + if (invoke_instruction->IsInvokeStaticOrDirect()) { + return TryInline(invoke_instruction, resolved_method); + } + + // Check if we can statically find the method. + ArtMethod* actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method); + if (actual_method != nullptr) { + return TryInline(invoke_instruction, actual_method); + } + + // Check if we can use an inline cache. + ArtMethod* caller = graph_->GetArtMethod(); + size_t pointer_size = class_linker->GetImagePointerSize(); + // Under JIT, we should always know the caller. + DCHECK(!Runtime::Current()->UseJit() || (caller != nullptr)); + if (caller != nullptr && caller->GetProfilingInfo(pointer_size) != nullptr) { + ProfilingInfo* profiling_info = caller->GetProfilingInfo(pointer_size); + const InlineCache& ic = *profiling_info->GetInlineCache(invoke_instruction->GetDexPc()); + if (ic.IsUnitialized()) { VLOG(compiler) << "Interface or virtual call to " << PrettyMethod(method_index, caller_dex_file) - << " could not be statically determined"; + << " is not hit and not inlined"; return false; - } - // We have found a method, but we need to find where that method is for the caller's - // dex file. - method_index = FindMethodIndexIn(resolved_method, caller_dex_file, method_index); - if (method_index == DexFile::kDexNoIndex) { + } else if (ic.IsMonomorphic()) { + MaybeRecordStat(kMonomorphicCall); + return TryInlineMonomorphicCall(invoke_instruction, resolved_method, ic); + } else if (ic.IsPolymorphic()) { + MaybeRecordStat(kPolymorphicCall); + return TryInlinePolymorphicCall(invoke_instruction, resolved_method, ic); + } else { + DCHECK(ic.IsMegamorphic()); VLOG(compiler) << "Interface or virtual call to " - << PrettyMethod(resolved_method) - << " cannot be inlined because unaccessible to caller"; + << PrettyMethod(method_index, caller_dex_file) + << " is megamorphic and not inlined"; + MaybeRecordStat(kMegamorphicCall); return false; } } - bool same_dex_file = - IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *resolved_method->GetDexFile()); + VLOG(compiler) << "Interface or virtual call to " + << PrettyMethod(method_index, caller_dex_file) + << " could not be statically determined"; + return false; +} - const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); +bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, + ArtMethod* resolved_method, + const InlineCache& ic) { + const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); + uint32_t class_index = FindClassIndexIn(ic.GetMonomorphicType(), caller_dex_file); + if (class_index == DexFile::kDexNoIndex) { + VLOG(compiler) << "Call to " << PrettyMethod(resolved_method) + << " from inline cache is not inlined because its class is not" + << " accessible to the caller"; + return false; + } + + ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); + size_t pointer_size = class_linker->GetImagePointerSize(); + if (invoke_instruction->IsInvokeInterface()) { + resolved_method = ic.GetMonomorphicType()->FindVirtualMethodForInterface( + resolved_method, pointer_size); + } else { + DCHECK(invoke_instruction->IsInvokeVirtual()); + resolved_method = ic.GetMonomorphicType()->FindVirtualMethodForVirtual( + resolved_method, pointer_size); + } + DCHECK(resolved_method != nullptr); + HInstruction* receiver = invoke_instruction->InputAt(0); + HInstruction* cursor = invoke_instruction->GetPrevious(); + HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); + + if (!TryInline(invoke_instruction, resolved_method, /* do_rtp */ false)) { + return false; + } + + // We successfully inlined, now add a guard. + ArtField* field = class_linker->GetClassRoot(ClassLinker::kJavaLangObject)->GetInstanceField(0); + DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_"); + HInstanceFieldGet* field_get = new (graph_->GetArena()) HInstanceFieldGet( + receiver, + Primitive::kPrimNot, + field->GetOffset(), + field->IsVolatile(), + field->GetDexFieldIndex(), + field->GetDeclaringClass()->GetDexClassDefIndex(), + *field->GetDexFile(), + handles_->NewHandle(field->GetDexCache()), + invoke_instruction->GetDexPc()); + + bool is_referrer = + (ic.GetMonomorphicType() == outermost_graph_->GetArtMethod()->GetDeclaringClass()); + HLoadClass* load_class = new (graph_->GetArena()) HLoadClass(graph_->GetCurrentMethod(), + class_index, + caller_dex_file, + is_referrer, + invoke_instruction->GetDexPc(), + /* needs_access_check */ false, + /* is_in_dex_cache */ true); + + HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, field_get); + HDeoptimize* deoptimize = new (graph_->GetArena()) HDeoptimize( + compare, invoke_instruction->GetDexPc()); + // TODO: Extend reference type propagation to understand the guard. + if (cursor != nullptr) { + bb_cursor->InsertInstructionAfter(load_class, cursor); + } else { + bb_cursor->InsertInstructionBefore(load_class, bb_cursor->GetFirstInstruction()); + } + bb_cursor->InsertInstructionAfter(field_get, load_class); + bb_cursor->InsertInstructionAfter(compare, field_get); + bb_cursor->InsertInstructionAfter(deoptimize, compare); + deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment()); + + // Run type propagation to get the guard typed, and eventually propagate the + // type of the receiver. + ReferenceTypePropagation rtp_fixup(graph_, handles_); + rtp_fixup.Run(); + + MaybeRecordStat(kInlinedMonomorphicCall); + return true; +} + +bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction ATTRIBUTE_UNUSED, + ArtMethod* resolved_method, + const InlineCache& ic ATTRIBUTE_UNUSED) { + // TODO + VLOG(compiler) << "Unimplemented polymorphic inlining for " + << PrettyMethod(resolved_method); + return false; +} + +bool HInliner::TryInline(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) { + const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); + uint32_t method_index = FindMethodIndexIn( + method, caller_dex_file, invoke_instruction->GetDexMethodIndex()); + if (method_index == DexFile::kDexNoIndex) { + VLOG(compiler) << "Call to " + << PrettyMethod(method) + << " cannot be inlined because unaccessible to caller"; + return false; + } + + bool same_dex_file = IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *method->GetDexFile()); + + const DexFile::CodeItem* code_item = method->GetCodeItem(); if (code_item == nullptr) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) + VLOG(compiler) << "Method " << PrettyMethod(method) << " is not inlined because it is native"; return false; } size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits(); if (code_item->insns_size_in_code_units_ > inline_max_code_units) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) + VLOG(compiler) << "Method " << PrettyMethod(method) << " is too big to inline"; return false; } if (code_item->tries_size_ != 0) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) + VLOG(compiler) << "Method " << PrettyMethod(method) << " is not inlined because of try block"; return false; } - if (!resolved_method->GetDeclaringClass()->IsVerified()) { - uint16_t class_def_idx = resolved_method->GetDeclaringClass()->GetDexClassDefIndex(); + if (!method->GetDeclaringClass()->IsVerified()) { + uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); if (!compiler_driver_->IsMethodVerifiedWithoutFailures( - resolved_method->GetDexMethodIndex(), class_def_idx, *resolved_method->GetDexFile())) { + method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) << " couldn't be verified, so it cannot be inlined"; return false; @@ -277,7 +424,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { return false; } - if (!TryBuildAndInline(resolved_method, invoke_instruction, same_dex_file)) { + if (!TryBuildAndInline(method, invoke_instruction, same_dex_file, do_rtp)) { return false; } @@ -288,7 +435,8 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file) { + bool same_dex_file, + bool do_rtp) { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); @@ -341,6 +489,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, invoke_type, graph_->IsDebuggable(), graph_->GetCurrentInstructionId()); + callee_graph->SetArtMethod(resolved_method); OptimizingCompilerStats inline_stats; HGraphBuilder builder(callee_graph, @@ -422,6 +571,7 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, size_t number_of_instructions_budget = kMaximumNumberOfHInstructions; if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) { HInliner inliner(callee_graph, + outermost_graph_, codegen_, outer_compilation_unit_, dex_compilation_unit, @@ -533,9 +683,9 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, HNullConstant* null_constant = graph_->GetNullConstant(); if (!null_constant->GetReferenceTypeInfo().IsValid()) { ReferenceTypeInfo::TypeHandle obj_handle = - handles_->NewHandle(class_linker->GetClassRoot(ClassLinker::kJavaLangObject)); + handles_->NewHandle(class_linker->GetClassRoot(ClassLinker::kJavaLangObject)); null_constant->SetReferenceTypeInfo( - ReferenceTypeInfo::Create(obj_handle, false /* is_exact */)); + ReferenceTypeInfo::Create(obj_handle, false /* is_exact */)); } // Check the integrity of reference types and run another type propagation if needed. @@ -554,14 +704,16 @@ bool HInliner::TryBuildAndInline(ArtMethod* resolved_method, return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */)); } - // If the return type is a refinement of the declared type run the type propagation again. - ReferenceTypeInfo return_rti = return_replacement->GetReferenceTypeInfo(); - ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo(); - if (invoke_rti.IsStrictSupertypeOf(return_rti) - || (return_rti.IsExact() && !invoke_rti.IsExact()) - || !return_replacement->CanBeNull()) { - ReferenceTypePropagation rtp_fixup(graph_, handles_); - rtp_fixup.Run(); + if (do_rtp) { + // If the return type is a refinement of the declared type run the type propagation again. + ReferenceTypeInfo return_rti = return_replacement->GetReferenceTypeInfo(); + ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo(); + if (invoke_rti.IsStrictSupertypeOf(return_rti) + || (return_rti.IsExact() && !invoke_rti.IsExact()) + || !return_replacement->CanBeNull()) { + ReferenceTypePropagation rtp_fixup(graph_, handles_); + rtp_fixup.Run(); + } } } diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 0f6a9453be..7b9fb73ccf 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -27,11 +27,13 @@ class CompilerDriver; class DexCompilationUnit; class HGraph; class HInvoke; +class InlineCache; class OptimizingCompilerStats; class HInliner : public HOptimization { public: HInliner(HGraph* outer_graph, + HGraph* outermost_graph, CodeGenerator* codegen, const DexCompilationUnit& outer_compilation_unit, const DexCompilationUnit& caller_compilation_unit, @@ -40,6 +42,7 @@ class HInliner : public HOptimization { OptimizingCompilerStats* stats, size_t depth = 0) : HOptimization(outer_graph, kInlinerPassName, stats), + outermost_graph_(outermost_graph), outer_compilation_unit_(outer_compilation_unit), caller_compilation_unit_(caller_compilation_unit), codegen_(codegen), @@ -54,10 +57,33 @@ class HInliner : public HOptimization { private: bool TryInline(HInvoke* invoke_instruction); + + // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether + // reference type propagation can run after the inlining. + bool TryInline(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp = true) + SHARED_REQUIRES(Locks::mutator_lock_); + + // Try to inline the target of a monomorphic call. If successful, the code + // in the graph will look like: + // if (receiver.getClass() != ic.GetMonomorphicType()) deopt + // ... // inlined code + bool TryInlineMonomorphicCall(HInvoke* invoke_instruction, + ArtMethod* resolved_method, + const InlineCache& ic) + SHARED_REQUIRES(Locks::mutator_lock_); + + // Try to inline targets of a polymorphic call. Currently unimplemented. + bool TryInlinePolymorphicCall(HInvoke* invoke_instruction, + ArtMethod* resolved_method, + const InlineCache& ic) + SHARED_REQUIRES(Locks::mutator_lock_); + bool TryBuildAndInline(ArtMethod* resolved_method, HInvoke* invoke_instruction, - bool same_dex_file); + bool same_dex_file, + bool do_rtp = true); + HGraph* const outermost_graph_; const DexCompilationUnit& outer_compilation_unit_; const DexCompilationUnit& caller_compilation_unit_; CodeGenerator* const codegen_; diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index d2017da221..5329b5c1b7 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -113,10 +113,10 @@ void IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { @@ -127,10 +127,10 @@ void IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } void IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -358,7 +358,7 @@ void IntrinsicLocationsBuilderARM::VisitIntegerRotateRight(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitIntegerRotateRight(HInvoke* invoke) { - GenIntegerRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); + GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false); } void IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) { @@ -377,7 +377,7 @@ void IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitLongRotateRight(HInvoke* invoke) { - GenLongRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); + GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false); } void IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) { @@ -390,7 +390,7 @@ void IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitIntegerRotateLeft(HInvoke* invoke) { - GenIntegerRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); + GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true); } void IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) { @@ -409,7 +409,7 @@ void IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitLongRotateLeft(HInvoke* invoke) { - GenLongRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); + GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true); } static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { @@ -429,7 +429,7 @@ void IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), true, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { @@ -437,7 +437,7 @@ void IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), false, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { @@ -486,7 +486,7 @@ void IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), false, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } @@ -495,7 +495,7 @@ void IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), true, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } static void GenMinMax(LocationSummary* locations, @@ -526,7 +526,7 @@ void IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); } void IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { @@ -534,7 +534,7 @@ void IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); } void IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) { @@ -742,22 +742,22 @@ void IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) } void IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); } static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, @@ -787,31 +787,34 @@ static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, } void IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, true, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ true, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, true, invoke); + CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ true, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); + CreateIntIntIntIntToVoid( + arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); + CreateIntIntIntIntToVoid( + arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); } void IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, true, invoke); + CreateIntIntIntIntToVoid( + arena_, features_, Primitive::kPrimLong, /* is_volatile */ true, invoke); } static void GenUnsafePut(LocationSummary* locations, @@ -873,31 +876,67 @@ static void GenUnsafePut(LocationSummary* locations, } void IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, @@ -1245,7 +1284,8 @@ void IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { - GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); + GenerateVisitStringIndexOf( + invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); } void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { @@ -1265,7 +1305,8 @@ void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { - GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); + GenerateVisitStringIndexOf( + invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } void IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { @@ -1644,7 +1685,7 @@ void IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) { temp2, dest, Register(kNoRegister), - false); + /* can_be_null */ false); __ Bind(slow_path->GetExitLabel()); } diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index b04dcceb05..962c4d5167 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -202,10 +202,10 @@ void IntrinsicLocationsBuilderARM64::VisitDoubleLongBitsToDouble(HInvoke* invoke } void IntrinsicCodeGeneratorARM64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetVIXLAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); } void IntrinsicCodeGeneratorARM64::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetVIXLAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { @@ -216,10 +216,10 @@ void IntrinsicLocationsBuilderARM64::VisitFloatIntBitsToFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetVIXLAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetVIXLAssembler()); } void IntrinsicCodeGeneratorARM64::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetVIXLAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetVIXLAssembler()); } static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -477,7 +477,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), true, GetVIXLAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathAbsFloat(HInvoke* invoke) { @@ -485,7 +485,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), false, GetVIXLAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetVIXLAssembler()); } static void CreateIntToInt(ArenaAllocator* arena, HInvoke* invoke) { @@ -514,7 +514,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathAbsInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathAbsInt(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), false, GetVIXLAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathAbsLong(HInvoke* invoke) { @@ -522,7 +522,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathAbsLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathAbsLong(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), true, GetVIXLAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetVIXLAssembler()); } static void GenMinMaxFP(LocationSummary* locations, @@ -557,7 +557,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMinDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, true, GetVIXLAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMinFloatFloat(HInvoke* invoke) { @@ -565,7 +565,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMinFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, false, GetVIXLAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMaxDoubleDouble(HInvoke* invoke) { @@ -573,7 +573,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMaxDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, true, GetVIXLAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMaxFloatFloat(HInvoke* invoke) { @@ -581,7 +581,8 @@ void IntrinsicLocationsBuilderARM64::VisitMathMaxFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, false, GetVIXLAssembler()); + GenMinMaxFP( + invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetVIXLAssembler()); } static void GenMinMax(LocationSummary* locations, @@ -614,7 +615,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMinIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, false, GetVIXLAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMinLongLong(HInvoke* invoke) { @@ -622,7 +623,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMinLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, true, GetVIXLAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMaxIntInt(HInvoke* invoke) { @@ -630,7 +631,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMaxIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, false, GetVIXLAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathMaxLongLong(HInvoke* invoke) { @@ -638,7 +639,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathMaxLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, true, GetVIXLAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathSqrt(HInvoke* invoke) { @@ -714,7 +715,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathRoundDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathRoundDouble(HInvoke* invoke) { - GenMathRound(invoke->GetLocations(), true, GetVIXLAssembler()); + GenMathRound(invoke->GetLocations(), /* is_double */ true, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMathRoundFloat(HInvoke* invoke) { @@ -722,7 +723,7 @@ void IntrinsicLocationsBuilderARM64::VisitMathRoundFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitMathRoundFloat(HInvoke* invoke) { - GenMathRound(invoke->GetLocations(), false, GetVIXLAssembler()); + GenMathRound(invoke->GetLocations(), /* is_double */ false, GetVIXLAssembler()); } void IntrinsicLocationsBuilderARM64::VisitMemoryPeekByte(HInvoke* invoke) { @@ -895,22 +896,22 @@ void IntrinsicLocationsBuilderARM64::VisitUnsafeGetObjectVolatile(HInvoke* invok } void IntrinsicCodeGeneratorARM64::VisitUnsafeGet(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeGetVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLong(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObject(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); } static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) { @@ -1001,31 +1002,67 @@ static void GenUnsafePut(LocationSummary* locations, } void IntrinsicCodeGeneratorARM64::VisitUnsafePut(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutObject(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutLong(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } void IntrinsicCodeGeneratorARM64::VisitUnsafePutLongVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, HInvoke* invoke) { @@ -1379,7 +1416,8 @@ void IntrinsicLocationsBuilderARM64::VisitStringIndexOf(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitStringIndexOf(HInvoke* invoke) { - GenerateVisitStringIndexOf(invoke, GetVIXLAssembler(), codegen_, GetAllocator(), true); + GenerateVisitStringIndexOf( + invoke, GetVIXLAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); } void IntrinsicLocationsBuilderARM64::VisitStringIndexOfAfter(HInvoke* invoke) { @@ -1399,7 +1437,8 @@ void IntrinsicLocationsBuilderARM64::VisitStringIndexOfAfter(HInvoke* invoke) { } void IntrinsicCodeGeneratorARM64::VisitStringIndexOfAfter(HInvoke* invoke) { - GenerateVisitStringIndexOf(invoke, GetVIXLAssembler(), codegen_, GetAllocator(), false); + GenerateVisitStringIndexOf( + invoke, GetVIXLAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } void IntrinsicLocationsBuilderARM64::VisitStringNewStringFromBytes(HInvoke* invoke) { diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 326844526e..9ecce0e93a 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -43,6 +43,14 @@ ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() { return codegen_->GetGraph()->GetArena(); } +inline bool IntrinsicCodeGeneratorMIPS::IsR2OrNewer() { + return codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2(); +} + +inline bool IntrinsicCodeGeneratorMIPS::IsR6() { + return codegen_->GetInstructionSetFeatures().IsR6(); +} + #define __ codegen->GetAssembler()-> static void MoveFromReturnRegister(Location trg, @@ -168,7 +176,7 @@ void IntrinsicLocationsBuilderMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invo } void IntrinsicCodeGeneratorMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } // int java.lang.Float.floatToRawIntBits(float) @@ -177,7 +185,7 @@ void IntrinsicLocationsBuilderMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -210,7 +218,7 @@ void IntrinsicLocationsBuilderMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } // float java.lang.Float.intBitsToFloat(int) @@ -219,24 +227,29 @@ void IntrinsicLocationsBuilderMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } -static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { +static void CreateIntToIntLocations(ArenaAllocator* arena, + HInvoke* invoke, + Location::OutputOverlap overlaps = Location::kNoOutputOverlap) { LocationSummary* locations = new (arena) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); locations->SetInAt(0, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->SetOut(Location::RequiresRegister(), overlaps); } -static void GenReverseBytes(LocationSummary* locations, - Primitive::Type type, - MipsAssembler* assembler, - bool isR2OrNewer) { +static void GenReverse(LocationSummary* locations, + Primitive::Type type, + bool isR2OrNewer, + bool isR6, + bool reverseBits, + MipsAssembler* assembler) { DCHECK(type == Primitive::kPrimShort || type == Primitive::kPrimInt || type == Primitive::kPrimLong); + DCHECK(type != Primitive::kPrimShort || !reverseBits); if (type == Primitive::kPrimShort) { Register in = locations->InAt(0).AsRegister<Register>(); @@ -273,6 +286,30 @@ static void GenReverseBytes(LocationSummary* locations, __ And(out, out, AT); __ Or(out, out, TMP); } + if (reverseBits) { + if (isR6) { + __ Bitswap(out, out); + } else { + __ LoadConst32(AT, 0x0F0F0F0F); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 4); + __ Srl(out, out, 4); + __ And(out, out, AT); + __ Or(out, TMP, out); + __ LoadConst32(AT, 0x33333333); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 2); + __ Srl(out, out, 2); + __ And(out, out, AT); + __ Or(out, TMP, out); + __ LoadConst32(AT, 0x55555555); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 1); + __ Srl(out, out, 1); + __ And(out, out, AT); + __ Or(out, TMP, out); + } + } } else if (type == Primitive::kPrimLong) { Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); @@ -314,6 +351,46 @@ static void GenReverseBytes(LocationSummary* locations, __ And(out_lo, out_lo, AT); __ Or(out_lo, out_lo, TMP); } + if (reverseBits) { + if (isR6) { + __ Bitswap(out_hi, out_hi); + __ Bitswap(out_lo, out_lo); + } else { + __ LoadConst32(AT, 0x0F0F0F0F); + __ And(TMP, out_hi, AT); + __ Sll(TMP, TMP, 4); + __ Srl(out_hi, out_hi, 4); + __ And(out_hi, out_hi, AT); + __ Or(out_hi, TMP, out_hi); + __ And(TMP, out_lo, AT); + __ Sll(TMP, TMP, 4); + __ Srl(out_lo, out_lo, 4); + __ And(out_lo, out_lo, AT); + __ Or(out_lo, TMP, out_lo); + __ LoadConst32(AT, 0x33333333); + __ And(TMP, out_hi, AT); + __ Sll(TMP, TMP, 2); + __ Srl(out_hi, out_hi, 2); + __ And(out_hi, out_hi, AT); + __ Or(out_hi, TMP, out_hi); + __ And(TMP, out_lo, AT); + __ Sll(TMP, TMP, 2); + __ Srl(out_lo, out_lo, 2); + __ And(out_lo, out_lo, AT); + __ Or(out_lo, TMP, out_lo); + __ LoadConst32(AT, 0x55555555); + __ And(TMP, out_hi, AT); + __ Sll(TMP, TMP, 1); + __ Srl(out_hi, out_hi, 1); + __ And(out_hi, out_hi, AT); + __ Or(out_hi, TMP, out_hi); + __ And(TMP, out_lo, AT); + __ Sll(TMP, TMP, 1); + __ Srl(out_lo, out_lo, 1); + __ And(out_lo, out_lo, AT); + __ Or(out_lo, TMP, out_lo); + } + } } } @@ -323,10 +400,12 @@ void IntrinsicLocationsBuilderMIPS::VisitIntegerReverseBytes(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) { - GenReverseBytes(invoke->GetLocations(), - Primitive::kPrimInt, - GetAssembler(), - codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()); + GenReverse(invoke->GetLocations(), + Primitive::kPrimInt, + IsR2OrNewer(), + IsR6(), + false, + GetAssembler()); } // long java.lang.Long.reverseBytes(long) @@ -335,10 +414,12 @@ void IntrinsicLocationsBuilderMIPS::VisitLongReverseBytes(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) { - GenReverseBytes(invoke->GetLocations(), - Primitive::kPrimLong, - GetAssembler(), - codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()); + GenReverse(invoke->GetLocations(), + Primitive::kPrimLong, + IsR2OrNewer(), + IsR6(), + false, + GetAssembler()); } // short java.lang.Short.reverseBytes(short) @@ -347,10 +428,397 @@ void IntrinsicLocationsBuilderMIPS::VisitShortReverseBytes(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) { - GenReverseBytes(invoke->GetLocations(), - Primitive::kPrimShort, - GetAssembler(), - codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()); + GenReverse(invoke->GetLocations(), + Primitive::kPrimShort, + IsR2OrNewer(), + IsR6(), + false, + GetAssembler()); +} + +static void GenNumberOfLeadingZeroes(LocationSummary* locations, + bool is64bit, + bool isR6, + MipsAssembler* assembler) { + Register out = locations->Out().AsRegister<Register>(); + if (is64bit) { + Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + + if (isR6) { + __ ClzR6(AT, in_hi); + __ ClzR6(TMP, in_lo); + __ Seleqz(TMP, TMP, in_hi); + } else { + __ ClzR2(AT, in_hi); + __ ClzR2(TMP, in_lo); + __ Movn(TMP, ZERO, in_hi); + } + __ Addu(out, AT, TMP); + } else { + Register in = locations->InAt(0).AsRegister<Register>(); + + if (isR6) { + __ ClzR6(out, in); + } else { + __ ClzR2(out, in); + } + } +} + +// int java.lang.Integer.numberOfLeadingZeros(int i) +void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { + GenNumberOfLeadingZeroes(invoke->GetLocations(), false, IsR6(), GetAssembler()); +} + +// int java.lang.Long.numberOfLeadingZeros(long i) +void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { + GenNumberOfLeadingZeroes(invoke->GetLocations(), true, IsR6(), GetAssembler()); +} + +static void GenNumberOfTrailingZeroes(LocationSummary* locations, + bool is64bit, + bool isR6, + bool isR2OrNewer, + MipsAssembler* assembler) { + Register out = locations->Out().AsRegister<Register>(); + Register in_lo; + Register in; + + if (is64bit) { + MipsLabel done; + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + + in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + + // If in_lo is zero then count the number of trailing zeroes in in_hi; + // otherwise count the number of trailing zeroes in in_lo. + // AT = in_lo ? in_lo : in_hi; + if (isR6) { + __ Seleqz(out, in_hi, in_lo); + __ Selnez(TMP, in_lo, in_lo); + __ Or(out, out, TMP); + } else { + __ Movz(out, in_hi, in_lo); + __ Movn(out, in_lo, in_lo); + } + + in = out; + } else { + in = locations->InAt(0).AsRegister<Register>(); + // Give in_lo a dummy value to keep the compiler from complaining. + // Since we only get here in the 32-bit case, this value will never + // be used. + in_lo = in; + } + + // We don't have an instruction to count the number of trailing zeroes. + // Start by flipping the bits end-for-end so we can count the number of + // leading zeroes instead. + if (isR2OrNewer) { + __ Rotr(out, in, 16); + __ Wsbh(out, out); + } else { + // MIPS32r1 + // __ Rotr(out, in, 16); + __ Sll(TMP, in, 16); + __ Srl(out, in, 16); + __ Or(out, out, TMP); + // __ Wsbh(out, out); + __ LoadConst32(AT, 0x00FF00FF); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 8); + __ Srl(out, out, 8); + __ And(out, out, AT); + __ Or(out, out, TMP); + } + + if (isR6) { + __ Bitswap(out, out); + __ ClzR6(out, out); + } else { + __ LoadConst32(AT, 0x0F0F0F0F); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 4); + __ Srl(out, out, 4); + __ And(out, out, AT); + __ Or(out, TMP, out); + __ LoadConst32(AT, 0x33333333); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 2); + __ Srl(out, out, 2); + __ And(out, out, AT); + __ Or(out, TMP, out); + __ LoadConst32(AT, 0x55555555); + __ And(TMP, out, AT); + __ Sll(TMP, TMP, 1); + __ Srl(out, out, 1); + __ And(out, out, AT); + __ Or(out, TMP, out); + __ ClzR2(out, out); + } + + if (is64bit) { + // If in_lo is zero, then we counted the number of trailing zeroes in in_hi so we must add the + // number of trailing zeroes in in_lo (32) to get the correct final count + __ LoadConst32(TMP, 32); + if (isR6) { + __ Seleqz(TMP, TMP, in_lo); + } else { + __ Movn(TMP, ZERO, in_lo); + } + __ Addu(out, out, TMP); + } +} + +// int java.lang.Integer.numberOfTrailingZeros(int i) +void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeroes(invoke->GetLocations(), false, IsR6(), IsR2OrNewer(), GetAssembler()); +} + +// int java.lang.Long.numberOfTrailingZeros(long i) +void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeroes(invoke->GetLocations(), true, IsR6(), IsR2OrNewer(), GetAssembler()); +} + +enum RotationDirection { + kRotateRight, + kRotateLeft, +}; + +static void GenRotate(HInvoke* invoke, + Primitive::Type type, + bool isR2OrNewer, + RotationDirection direction, + MipsAssembler* assembler) { + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + + LocationSummary* locations = invoke->GetLocations(); + if (invoke->InputAt(1)->IsIntConstant()) { + int32_t shift = static_cast<int32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()); + if (type == Primitive::kPrimInt) { + Register in = locations->InAt(0).AsRegister<Register>(); + Register out = locations->Out().AsRegister<Register>(); + + shift &= 0x1f; + if (direction == kRotateLeft) { + shift = (32 - shift) & 0x1F; + } + + if (isR2OrNewer) { + if ((shift != 0) || (out != in)) { + __ Rotr(out, in, shift); + } + } else { + if (shift == 0) { + if (out != in) { + __ Move(out, in); + } + } else { + __ Srl(AT, in, shift); + __ Sll(out, in, 32 - shift); + __ Or(out, out, AT); + } + } + } else { // Primitive::kPrimLong + Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register out_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); + + shift &= 0x3f; + if (direction == kRotateLeft) { + shift = (64 - shift) & 0x3F; + } + + if (shift == 0) { + __ Move(out_lo, in_lo); + __ Move(out_hi, in_hi); + } else if (shift == 32) { + __ Move(out_lo, in_hi); + __ Move(out_hi, in_lo); + } else if (shift < 32) { + __ Srl(AT, in_lo, shift); + __ Sll(out_lo, in_hi, 32 - shift); + __ Or(out_lo, out_lo, AT); + __ Srl(AT, in_hi, shift); + __ Sll(out_hi, in_lo, 32 - shift); + __ Or(out_hi, out_hi, AT); + } else { + __ Sll(AT, in_lo, 64 - shift); + __ Srl(out_lo, in_hi, shift - 32); + __ Or(out_lo, out_lo, AT); + __ Sll(AT, in_hi, 64 - shift); + __ Srl(out_hi, in_lo, shift - 32); + __ Or(out_hi, out_hi, AT); + } + } + } else { // !invoke->InputAt(1)->IsIntConstant() + Register shamt = locations->InAt(1).AsRegister<Register>(); + if (type == Primitive::kPrimInt) { + Register in = locations->InAt(0).AsRegister<Register>(); + Register out = locations->Out().AsRegister<Register>(); + + if (isR2OrNewer) { + if (direction == kRotateRight) { + __ Rotrv(out, in, shamt); + } else { + // negu tmp, shamt + __ Subu(TMP, ZERO, shamt); + __ Rotrv(out, in, TMP); + } + } else { + if (direction == kRotateRight) { + __ Srlv(AT, in, shamt); + __ Subu(TMP, ZERO, shamt); + __ Sllv(out, in, TMP); + __ Or(out, out, AT); + } else { + __ Sllv(AT, in, shamt); + __ Subu(TMP, ZERO, shamt); + __ Srlv(out, in, TMP); + __ Or(out, out, AT); + } + } + } else { // Primitive::kPrimLong + Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register out_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); + + MipsLabel done; + + if (direction == kRotateRight) { + __ Nor(TMP, ZERO, shamt); + __ Srlv(AT, in_lo, shamt); + __ Sll(out_lo, in_hi, 1); + __ Sllv(out_lo, out_lo, TMP); + __ Or(out_lo, out_lo, AT); + __ Srlv(AT, in_hi, shamt); + __ Sll(out_hi, in_lo, 1); + __ Sllv(out_hi, out_hi, TMP); + __ Or(out_hi, out_hi, AT); + } else { + __ Nor(TMP, ZERO, shamt); + __ Sllv(AT, in_lo, shamt); + __ Srl(out_lo, in_hi, 1); + __ Srlv(out_lo, out_lo, TMP); + __ Or(out_lo, out_lo, AT); + __ Sllv(AT, in_hi, shamt); + __ Srl(out_hi, in_lo, 1); + __ Srlv(out_hi, out_hi, TMP); + __ Or(out_hi, out_hi, AT); + } + + __ Andi(TMP, shamt, 32); + __ Beqz(TMP, &done); + __ Move(TMP, out_hi); + __ Move(out_hi, out_lo); + __ Move(out_lo, TMP); + + __ Bind(&done); + } + } +} + +// int java.lang.Integer.rotateRight(int i, int distance) +void IntrinsicLocationsBuilderMIPS::VisitIntegerRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitIntegerRotateRight(HInvoke* invoke) { + GenRotate(invoke, Primitive::kPrimInt, IsR2OrNewer(), kRotateRight, GetAssembler()); +} + +// long java.lang.Long.rotateRight(long i, int distance) +void IntrinsicLocationsBuilderMIPS::VisitLongRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitLongRotateRight(HInvoke* invoke) { + GenRotate(invoke, Primitive::kPrimLong, IsR2OrNewer(), kRotateRight, GetAssembler()); +} + +// int java.lang.Integer.rotateLeft(int i, int distance) +void IntrinsicLocationsBuilderMIPS::VisitIntegerRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitIntegerRotateLeft(HInvoke* invoke) { + GenRotate(invoke, Primitive::kPrimInt, IsR2OrNewer(), kRotateLeft, GetAssembler()); +} + +// long java.lang.Long.rotateLeft(long i, int distance) +void IntrinsicLocationsBuilderMIPS::VisitLongRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorMIPS::VisitLongRotateLeft(HInvoke* invoke) { + GenRotate(invoke, Primitive::kPrimLong, IsR2OrNewer(), kRotateLeft, GetAssembler()); +} + +// int java.lang.Integer.reverse(int) +void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) { + GenReverse(invoke->GetLocations(), + Primitive::kPrimInt, + IsR2OrNewer(), + IsR6(), + true, + GetAssembler()); +} + +// long java.lang.Long.reverse(long) +void IntrinsicLocationsBuilderMIPS::VisitLongReverse(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) { + GenReverse(invoke->GetLocations(), + Primitive::kPrimLong, + IsR2OrNewer(), + IsR6(), + true, + GetAssembler()); } // boolean java.lang.String.equals(Object anObject) @@ -463,10 +931,6 @@ void IntrinsicLocationsBuilderMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUS void IntrinsicCodeGeneratorMIPS::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ } -UNIMPLEMENTED_INTRINSIC(IntegerReverse) -UNIMPLEMENTED_INTRINSIC(LongReverse) -UNIMPLEMENTED_INTRINSIC(LongNumberOfLeadingZeros) -UNIMPLEMENTED_INTRINSIC(IntegerNumberOfLeadingZeros) UNIMPLEMENTED_INTRINSIC(MathAbsDouble) UNIMPLEMENTED_INTRINSIC(MathAbsFloat) UNIMPLEMENTED_INTRINSIC(MathAbsInt) @@ -519,12 +983,6 @@ UNIMPLEMENTED_INTRINSIC(StringIndexOfAfter) UNIMPLEMENTED_INTRINSIC(StringNewStringFromBytes) UNIMPLEMENTED_INTRINSIC(StringNewStringFromChars) UNIMPLEMENTED_INTRINSIC(StringNewStringFromString) -UNIMPLEMENTED_INTRINSIC(LongRotateLeft) -UNIMPLEMENTED_INTRINSIC(LongRotateRight) -UNIMPLEMENTED_INTRINSIC(LongNumberOfTrailingZeros) -UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) -UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) -UNIMPLEMENTED_INTRINSIC(IntegerNumberOfTrailingZeros) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h index c71b3c68b7..19ad5255d5 100644 --- a/compiler/optimizing/intrinsics_mips.h +++ b/compiler/optimizing/intrinsics_mips.h @@ -67,6 +67,9 @@ INTRINSICS_LIST(OPTIMIZING_INTRINSICS) #undef INTRINSICS_LIST #undef OPTIMIZING_INTRINSICS + bool IsR2OrNewer(void); + bool IsR6(void); + private: MipsAssembler* GetAssembler(); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index ecee11dea6..36e1b20e4e 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -162,7 +162,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* in } void IntrinsicCodeGeneratorMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } // int java.lang.Float.floatToRawIntBits(float) @@ -171,7 +171,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invok } void IntrinsicCodeGeneratorMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -199,7 +199,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invok } void IntrinsicCodeGeneratorMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } // float java.lang.Float.intBitsToFloat(int) @@ -208,7 +208,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -290,7 +290,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* } void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { - GenNumberOfLeadingZeroes(invoke->GetLocations(), false, GetAssembler()); + GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } // int java.lang.Long.numberOfLeadingZeros(long i) @@ -299,7 +299,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* inv } void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { - GenNumberOfLeadingZeroes(invoke->GetLocations(), true, GetAssembler()); + GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } static void GenNumberOfTrailingZeroes(LocationSummary* locations, @@ -327,7 +327,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* } void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { - GenNumberOfTrailingZeroes(invoke->GetLocations(), false, GetAssembler()); + GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } // int java.lang.Long.numberOfTrailingZeros(long i) @@ -336,7 +336,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* in } void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { - GenNumberOfTrailingZeroes(invoke->GetLocations(), true, GetAssembler()); + GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } static void GenRotateRight(HInvoke* invoke, @@ -525,7 +525,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), true, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } // float java.lang.Math.abs(float) @@ -534,7 +534,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), false, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToInt(ArenaAllocator* arena, HInvoke* invoke) { @@ -566,7 +566,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathAbsInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathAbsInt(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), false, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } // long java.lang.Math.abs(long) @@ -575,7 +575,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathAbsLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathAbsLong(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), true, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } static void GenMinMaxFP(LocationSummary* locations, @@ -616,7 +616,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler()); } // float java.lang.Math.min(float, float) @@ -625,7 +625,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler()); } // double java.lang.Math.max(double, double) @@ -634,7 +634,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler()); } // float java.lang.Math.max(float, float) @@ -643,7 +643,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler()); } static void GenMinMax(LocationSummary* locations, @@ -713,7 +713,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMinIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); } // long java.lang.Math.min(long, long) @@ -722,7 +722,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMinLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); } // int java.lang.Math.max(int, int) @@ -731,7 +731,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMaxIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); } // long java.lang.Math.max(long, long) @@ -740,7 +740,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitMathMaxLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); } // double java.lang.Math.sqrt(double) @@ -1045,7 +1045,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGet(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGet(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); } // int sun.misc.Unsafe.getIntVolatile(Object o, long offset) @@ -1054,7 +1054,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); } // long sun.misc.Unsafe.getLong(Object o, long offset) @@ -1063,7 +1063,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLong(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); } // long sun.misc.Unsafe.getLongVolatile(Object o, long offset) @@ -1072,7 +1072,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); } // Object sun.misc.Unsafe.getObject(Object o, long offset) @@ -1081,7 +1081,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObject(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObject(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); } // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset) @@ -1090,7 +1090,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invo } void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); } static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) { @@ -1151,7 +1151,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePut(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePut(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } // void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x) @@ -1160,7 +1164,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } // void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x) @@ -1169,7 +1177,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimInt, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } // void sun.misc.Unsafe.putObject(Object o, long offset, Object x) @@ -1178,7 +1190,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObject(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObject(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } // void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x) @@ -1187,7 +1203,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invok } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } // void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x) @@ -1196,7 +1216,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invo } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimNot, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } // void sun.misc.Unsafe.putLong(Object o, long offset, long x) @@ -1205,7 +1229,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLong(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ false, + codegen_); } // void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x) @@ -1214,7 +1242,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ false, + /* is_ordered */ true, + codegen_); } // void sun.misc.Unsafe.putLongVolatile(Object o, long offset, long x) @@ -1223,7 +1255,11 @@ void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke } void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_); + GenUnsafePut(invoke->GetLocations(), + Primitive::kPrimLong, + /* is_volatile */ true, + /* is_ordered */ false, + codegen_); } static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, HInvoke* invoke) { @@ -1565,7 +1601,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOf(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); + GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); } // int java.lang.String.indexOf(int ch, int fromIndex) @@ -1584,7 +1620,8 @@ void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); + GenerateStringIndexOf( + invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } // java.lang.String.String(byte[] bytes) diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 371588fc47..5b67cdefa3 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -138,31 +138,31 @@ static void MoveIntToFP(LocationSummary* locations, bool is64bit, X86Assembler* } void IntrinsicLocationsBuilderX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - CreateFPToIntLocations(arena_, invoke, true); + CreateFPToIntLocations(arena_, invoke, /* is64bit */ true); } void IntrinsicLocationsBuilderX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - CreateIntToFPLocations(arena_, invoke, true); + CreateIntToFPLocations(arena_, invoke, /* is64bit */ true); } void IntrinsicCodeGeneratorX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicCodeGeneratorX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - CreateFPToIntLocations(arena_, invoke, false); + CreateFPToIntLocations(arena_, invoke, /* is64bit */ false); } void IntrinsicLocationsBuilderX86::VisitFloatIntBitsToFloat(HInvoke* invoke) { - CreateIntToFPLocations(arena_, invoke, false); + CreateIntToFPLocations(arena_, invoke, /* is64bit */ false); } void IntrinsicCodeGeneratorX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } void IntrinsicCodeGeneratorX86::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -298,7 +298,7 @@ void IntrinsicLocationsBuilderX86::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), true, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) { @@ -306,7 +306,7 @@ void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), false, GetAssembler()); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) { @@ -490,7 +490,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) { @@ -498,7 +498,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { @@ -506,7 +506,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, true, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) { @@ -514,7 +514,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, false, GetAssembler()); + GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler()); } static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long, @@ -597,7 +597,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMinIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) { @@ -605,7 +605,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) { @@ -613,7 +613,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) { @@ -621,7 +621,7 @@ void IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler()); } static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -1265,19 +1265,20 @@ static void GenerateStringIndexOf(HInvoke* invoke, } void IntrinsicLocationsBuilderX86::VisitStringIndexOf(HInvoke* invoke) { - CreateStringIndexOfLocations(invoke, arena_, true); + CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ true); } void IntrinsicCodeGeneratorX86::VisitStringIndexOf(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); + GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); } void IntrinsicLocationsBuilderX86::VisitStringIndexOfAfter(HInvoke* invoke) { - CreateStringIndexOfLocations(invoke, arena_, false); + CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ false); } void IntrinsicCodeGeneratorX86::VisitStringIndexOfAfter(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); + GenerateStringIndexOf( + invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } void IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) { @@ -1660,42 +1661,42 @@ static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke } void IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, false, false); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ false, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, false, true); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ false, /* is_volatile */ true); } void IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, false, false); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ true, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, true, true); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ true, /* is_volatile */ true); } void IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, false, false); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ false, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - CreateIntIntIntToIntLocations(arena_, invoke, false, true); + CreateIntIntIntToIntLocations(arena_, invoke, /* is_long */ false, /* is_volatile */ true); } void IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); } @@ -1722,31 +1723,40 @@ static void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena, } void IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimInt, invoke, true); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimInt, invoke, /* is_volatile */ true); } void IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimNot, invoke, true); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimNot, invoke, /* is_volatile */ true); } void IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, false); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false); } void IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) { - CreateIntIntIntIntToVoidPlusTempsLocations(arena_, Primitive::kPrimLong, invoke, true); + CreateIntIntIntIntToVoidPlusTempsLocations( + arena_, Primitive::kPrimLong, invoke, /* is_volatile */ true); } // We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86 @@ -1798,31 +1808,31 @@ static void GenUnsafePut(LocationSummary* locations, } void IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_); } static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, Primitive::Type type, diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 2d9f01b821..ecd129f31e 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -115,10 +115,10 @@ void IntrinsicLocationsBuilderX86_64::VisitDoubleLongBitsToDouble(HInvoke* invok } void IntrinsicCodeGeneratorX86_64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicCodeGeneratorX86_64::VisitDoubleLongBitsToDouble(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86_64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { @@ -129,10 +129,10 @@ void IntrinsicLocationsBuilderX86_64::VisitFloatIntBitsToFloat(HInvoke* invoke) } void IntrinsicCodeGeneratorX86_64::VisitFloatFloatToRawIntBits(HInvoke* invoke) { - MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); + MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } void IntrinsicCodeGeneratorX86_64::VisitFloatIntBitsToFloat(HInvoke* invoke) { - MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); + MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -230,7 +230,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathAbsDouble(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathAbsDouble(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), true, GetAssembler(), codegen_); + MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler(), codegen_); } void IntrinsicLocationsBuilderX86_64::VisitMathAbsFloat(HInvoke* invoke) { @@ -238,7 +238,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathAbsFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathAbsFloat(HInvoke* invoke) { - MathAbsFP(invoke->GetLocations(), false, GetAssembler(), codegen_); + MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler(), codegen_); } static void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { @@ -277,7 +277,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathAbsInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathAbsInt(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), false, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86_64::VisitMathAbsLong(HInvoke* invoke) { @@ -285,7 +285,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathAbsLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathAbsLong(HInvoke* invoke) { - GenAbsInteger(invoke->GetLocations(), true, GetAssembler()); + GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); } static void GenMinMaxFP(LocationSummary* locations, @@ -388,7 +388,8 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, true, GetAssembler(), codegen_); + GenMinMaxFP( + invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler(), codegen_); } void IntrinsicLocationsBuilderX86_64::VisitMathMinFloatFloat(HInvoke* invoke) { @@ -396,7 +397,8 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMinFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), true, false, GetAssembler(), codegen_); + GenMinMaxFP( + invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler(), codegen_); } void IntrinsicLocationsBuilderX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) { @@ -404,7 +406,8 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) } void IntrinsicCodeGeneratorX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, true, GetAssembler(), codegen_); + GenMinMaxFP( + invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler(), codegen_); } void IntrinsicLocationsBuilderX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) { @@ -412,7 +415,8 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), false, false, GetAssembler(), codegen_); + GenMinMaxFP( + invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler(), codegen_); } static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long, @@ -461,7 +465,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMinIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86_64::VisitMathMinLongLong(HInvoke* invoke) { @@ -469,7 +473,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMinLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), true, true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler()); } void IntrinsicLocationsBuilderX86_64::VisitMathMaxIntInt(HInvoke* invoke) { @@ -477,7 +481,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMaxIntInt(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, false, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler()); } void IntrinsicLocationsBuilderX86_64::VisitMathMaxLongLong(HInvoke* invoke) { @@ -485,7 +489,7 @@ void IntrinsicLocationsBuilderX86_64::VisitMathMaxLongLong(HInvoke* invoke) { } void IntrinsicCodeGeneratorX86_64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), false, true, GetAssembler()); + GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler()); } static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { @@ -690,7 +694,7 @@ void IntrinsicCodeGeneratorX86_64::VisitMathRoundDouble(HInvoke* invoke) { __ j(kUnordered, &nan); // output = double-to-long-truncate(input) - __ cvttsd2si(out, inPlusPointFive, true); + __ cvttsd2si(out, inPlusPointFive, /* is64bit */ true); __ jmp(&done); __ Bind(&nan); @@ -1152,7 +1156,7 @@ void IntrinsicCodeGeneratorX86_64::VisitSystemArrayCopy(HInvoke* invoke) { temp2, dest, CpuRegister(kNoRegister), - false); + /* value_can_be_null */ false); __ Bind(slow_path->GetExitLabel()); } @@ -1180,8 +1184,8 @@ void IntrinsicCodeGeneratorX86_64::VisitStringCompareTo(HInvoke* invoke) { codegen_->AddSlowPath(slow_path); __ j(kEqual, slow_path->GetEntryLabel()); - __ gs()->call(Address::Absolute( - QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pStringCompareTo), true)); + __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pStringCompareTo), + /* no_rip */ true)); __ Bind(slow_path->GetExitLabel()); } @@ -1372,7 +1376,7 @@ static void GenerateStringIndexOf(HInvoke* invoke, // Ensure we have a start index >= 0; __ xorl(counter, counter); __ cmpl(start_index, Immediate(0)); - __ cmov(kGreater, counter, start_index, false); // 32-bit copy is enough. + __ cmov(kGreater, counter, start_index, /* is64bit */ false); // 32-bit copy is enough. // Move to the start of the string: string_obj + value_offset + 2 * start_index. __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset)); @@ -1409,19 +1413,20 @@ static void GenerateStringIndexOf(HInvoke* invoke, } void IntrinsicLocationsBuilderX86_64::VisitStringIndexOf(HInvoke* invoke) { - CreateStringIndexOfLocations(invoke, arena_, true); + CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ true); } void IntrinsicCodeGeneratorX86_64::VisitStringIndexOf(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); + GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); } void IntrinsicLocationsBuilderX86_64::VisitStringIndexOfAfter(HInvoke* invoke) { - CreateStringIndexOfLocations(invoke, arena_, false); + CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ false); } void IntrinsicCodeGeneratorX86_64::VisitStringIndexOfAfter(HInvoke* invoke) { - GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); + GenerateStringIndexOf( + invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); } void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromBytes(HInvoke* invoke) { @@ -1446,8 +1451,8 @@ void IntrinsicCodeGeneratorX86_64::VisitStringNewStringFromBytes(HInvoke* invoke codegen_->AddSlowPath(slow_path); __ j(kEqual, slow_path->GetEntryLabel()); - __ gs()->call(Address::Absolute( - QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromBytes), true)); + __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromBytes), + /* no_rip */ true)); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Bind(slow_path->GetExitLabel()); } @@ -1466,8 +1471,8 @@ void IntrinsicLocationsBuilderX86_64::VisitStringNewStringFromChars(HInvoke* inv void IntrinsicCodeGeneratorX86_64::VisitStringNewStringFromChars(HInvoke* invoke) { X86_64Assembler* assembler = GetAssembler(); - __ gs()->call(Address::Absolute( - QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromChars), true)); + __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromChars), + /* no_rip */ true)); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } @@ -1490,8 +1495,8 @@ void IntrinsicCodeGeneratorX86_64::VisitStringNewStringFromString(HInvoke* invok codegen_->AddSlowPath(slow_path); __ j(kEqual, slow_path->GetEntryLabel()); - __ gs()->call(Address::Absolute( - QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromString), true)); + __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocStringFromString), + /* no_rip */ true)); codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); __ Bind(slow_path->GetExitLabel()); } @@ -1715,7 +1720,8 @@ void IntrinsicLocationsBuilderX86_64::VisitThreadCurrentThread(HInvoke* invoke) void IntrinsicCodeGeneratorX86_64::VisitThreadCurrentThread(HInvoke* invoke) { CpuRegister out = invoke->GetLocations()->Out().AsRegister<CpuRegister>(); - GetAssembler()->gs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86_64WordSize>(), true)); + GetAssembler()->gs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86_64WordSize>(), + /* no_rip */ true)); } static void GenUnsafeGet(HInvoke* invoke, @@ -1786,22 +1792,22 @@ void IntrinsicLocationsBuilderX86_64::VisitUnsafeGetObjectVolatile(HInvoke* invo void IntrinsicCodeGeneratorX86_64::VisitUnsafeGet(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLong(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetLongVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetObject(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { - GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); + GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); } @@ -1885,31 +1891,31 @@ static void GenUnsafePut(LocationSummary* locations, Primitive::Type type, bool } void IntrinsicCodeGeneratorX86_64::VisitUnsafePut(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObject(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutObjectVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLong(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongOrdered(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_); } void IntrinsicCodeGeneratorX86_64::VisitUnsafePutLongVolatile(HInvoke* invoke) { - GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, codegen_); + GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_); } static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, Primitive::Type type, diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc index c38bbe3477..02befc011a 100644 --- a/compiler/optimizing/licm.cc +++ b/compiler/optimizing/licm.cc @@ -121,6 +121,8 @@ void LICM::Run() { // phi in it. if (instruction->NeedsEnvironment()) { UpdateLoopPhisIn(instruction->GetEnvironment(), loop_info); + } else { + DCHECK(!instruction->HasEnvironment()); } instruction->MoveBefore(pre_header->GetLastInstruction()); } else if (instruction->CanThrow()) { diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 5b89cfef5a..680f89f9b9 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -933,8 +933,9 @@ class LSEVisitor : public HGraphVisitor { }; void LoadStoreElimination::Run() { - if (graph_->IsDebuggable()) { + if (graph_->IsDebuggable() || graph_->HasTryCatch()) { // Debugger may set heap values or trigger deoptimization of callers. + // Try/catch support not implemented yet. // Skip this optimization. return; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 19614f11c6..9d3c88c79e 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -371,6 +371,9 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { bool HasTryCatch() const { return has_try_catch_; } void SetHasTryCatch(bool value) { has_try_catch_ = value; } + ArtMethod* GetArtMethod() const { return art_method_; } + void SetArtMethod(ArtMethod* method) { art_method_ = method; } + // Returns an instruction with the opposite boolean value from 'cond'. // The instruction has been inserted into the graph, either as a constant, or // before cursor. @@ -479,6 +482,11 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { HCurrentMethod* cached_current_method_; + // The ArtMethod this graph is for. Note that for AOT, it may be null, + // for example for methods whose declaring class could not be resolved + // (such as when the superclass could not be found). + ArtMethod* art_method_; + friend class SsaBuilder; // For caching constants. friend class SsaLivenessAnalysis; // For the linear order. ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1); @@ -2462,11 +2470,15 @@ class HTryBoundary : public HTemplateInstruction<0> { // Deoptimize to interpreter, upon checking a condition. class HDeoptimize : public HTemplateInstruction<1> { public: - explicit HDeoptimize(HInstruction* cond, uint32_t dex_pc) + HDeoptimize(HInstruction* cond, uint32_t dex_pc) : HTemplateInstruction(SideEffects::None(), dex_pc) { SetRawInputAt(0, cond); } + bool CanBeMoved() const OVERRIDE { return true; } + bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { + return true; + } bool NeedsEnvironment() const OVERRIDE { return true; } bool CanThrow() const OVERRIDE { return true; } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index cae2d3f01b..4643aed9cc 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -427,7 +427,7 @@ static void MaybeRunInliner(HGraph* graph, return; } HInliner* inliner = new (graph->GetArena()) HInliner( - graph, codegen, dex_compilation_unit, dex_compilation_unit, driver, handles, stats); + graph, graph, codegen, dex_compilation_unit, dex_compilation_unit, driver, handles, stats); HOptimization* optimizations[] = { inliner }; RunOptimizations(optimizations, arraysize(optimizations), pass_observer); @@ -531,7 +531,6 @@ static void RunOptimizations(HGraph* graph, graph, stats, "instruction_simplifier_after_bce"); InstructionSimplifier* simplify4 = new (arena) InstructionSimplifier( graph, stats, "instruction_simplifier_before_codegen"); - IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, driver); HOptimization* optimizations1[] = { @@ -543,49 +542,30 @@ static void RunOptimizations(HGraph* graph, dce1, simplify2 }; - RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer); MaybeRunInliner(graph, codegen, driver, stats, dex_compilation_unit, pass_observer, &handles); - // TODO: Update passes incompatible with try/catch so we have the same - // pipeline for all methods. - if (graph->HasTryCatch()) { - HOptimization* optimizations2[] = { - boolean_simplify, - side_effects, - gvn, - dce2, - // The codegen has a few assumptions that only the instruction simplifier - // can satisfy. For example, the code generator does not expect to see a - // HTypeConversion from a type to the same type. - simplify4, - }; - - RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); - } else { - HOptimization* optimizations2[] = { - // BooleanSimplifier depends on the InstructionSimplifier removing - // redundant suspend checks to recognize empty blocks. - boolean_simplify, - fold2, // TODO: if we don't inline we can also skip fold2. - side_effects, - gvn, - licm, - induction, - bce, - fold3, // evaluates code generated by dynamic bce - simplify3, - lse, - dce2, - // The codegen has a few assumptions that only the instruction simplifier - // can satisfy. For example, the code generator does not expect to see a - // HTypeConversion from a type to the same type. - simplify4, - }; - - RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); - } + HOptimization* optimizations2[] = { + // BooleanSimplifier depends on the InstructionSimplifier removing + // redundant suspend checks to recognize empty blocks. + boolean_simplify, + fold2, // TODO: if we don't inline we can also skip fold2. + side_effects, + gvn, + licm, + induction, + bce, + fold3, // evaluates code generated by dynamic bce + simplify3, + lse, + dce2, + // The codegen has a few assumptions that only the instruction simplifier + // can satisfy. For example, the code generator does not expect to see a + // HTypeConversion from a type to the same type. + simplify4, + }; + RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); RunArchOptimizations(driver->GetInstructionSet(), graph, stats, pass_observer); AllocateRegisters(graph, codegen, pass_observer); @@ -763,8 +743,8 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, ArtMethod* art_method = compiler_driver->ResolveMethod( soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type); // We may not get a method, for example if its class is erroneous. - // TODO: Clean this up, the compiler driver should just pass the ArtMethod to compile. if (art_method != nullptr) { + graph->SetArtMethod(art_method); interpreter_metadata = art_method->GetQuickenedInfo(); } } @@ -948,6 +928,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, if (stack_map_data == nullptr) { return false; } + MaybeRecordStat(MethodCompilationStat::kCompiled); codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size)); const void* code = code_cache->CommitCode( self, diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index e5ea0f576b..6296eedfb0 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -49,6 +49,10 @@ enum MethodCompilationStat { kNotCompiledUnsupportedIsa, kNotCompiledVerificationError, kNotCompiledVerifyAtRuntime, + kInlinedMonomorphicCall, + kMonomorphicCall, + kPolymorphicCall, + kMegamorphicCall, kLastStat }; @@ -111,6 +115,10 @@ class OptimizingCompilerStats { case kNotCompiledUnsupportedIsa : name = "NotCompiledUnsupportedIsa"; break; case kNotCompiledVerificationError : name = "NotCompiledVerificationError"; break; case kNotCompiledVerifyAtRuntime : name = "NotCompiledVerifyAtRuntime"; break; + case kInlinedMonomorphicCall: name = "InlinedMonomorphicCall"; break; + case kMonomorphicCall: name = "MonomorphicCall"; break; + case kPolymorphicCall: name = "PolymorphicCall"; break; + case kMegamorphicCall: name = "kMegamorphicCall"; break; case kLastStat: LOG(FATAL) << "invalid stat " diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 4a6e6d7c3f..98a1a8f9a1 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -22,6 +22,7 @@ #include "base/bit_utils.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/value_object.h" #include "constants_arm.h" #include "utils/arm/managed_register_arm.h" @@ -697,10 +698,9 @@ class ArmAssembler : public Assembler { // Most of these are pure virtual as they need to be implemented per instruction set. // Create a new literal with a given value. - // NOTE: Force the template parameter to be explicitly specified. In the absence of - // std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>. + // NOTE: Force the template parameter to be explicitly specified. template <typename T> - Literal* NewLiteral(typename std::decay<T>::type value) { + Literal* NewLiteral(typename Identity<T>::type value) { static_assert(std::is_integral<T>::value, "T must be an integral type."); return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value)); } diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index fc7ac7061a..42f21e603d 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -302,6 +302,46 @@ void MipsAssembler::Nor(Register rd, Register rs, Register rt) { EmitR(0, rs, rt, rd, 0, 0x27); } +void MipsAssembler::Movz(Register rd, Register rs, Register rt) { + CHECK(!IsR6()); + EmitR(0, rs, rt, rd, 0, 0x0A); +} + +void MipsAssembler::Movn(Register rd, Register rs, Register rt) { + CHECK(!IsR6()); + EmitR(0, rs, rt, rd, 0, 0x0B); +} + +void MipsAssembler::Seleqz(Register rd, Register rs, Register rt) { + CHECK(IsR6()); + EmitR(0, rs, rt, rd, 0, 0x35); +} + +void MipsAssembler::Selnez(Register rd, Register rs, Register rt) { + CHECK(IsR6()); + EmitR(0, rs, rt, rd, 0, 0x37); +} + +void MipsAssembler::ClzR6(Register rd, Register rs) { + CHECK(IsR6()); + EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x10); +} + +void MipsAssembler::ClzR2(Register rd, Register rs) { + CHECK(!IsR6()); + EmitR(0x1C, rs, rd, rd, 0, 0x20); +} + +void MipsAssembler::CloR6(Register rd, Register rs) { + CHECK(IsR6()); + EmitR(0, rs, static_cast<Register>(0), rd, 0x01, 0x11); +} + +void MipsAssembler::CloR2(Register rd, Register rs) { + CHECK(!IsR6()); + EmitR(0x1C, rs, rd, rd, 0, 0x21); +} + void MipsAssembler::Seb(Register rd, Register rt) { EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x10, 0x20); } @@ -314,6 +354,11 @@ void MipsAssembler::Wsbh(Register rd, Register rt) { EmitR(0x1f, static_cast<Register>(0), rt, rd, 2, 0x20); } +void MipsAssembler::Bitswap(Register rd, Register rt) { + CHECK(IsR6()); + EmitR(0x1f, static_cast<Register>(0), rt, rd, 0x0, 0x20); +} + void MipsAssembler::Sll(Register rd, Register rt, int shamt) { CHECK(IsUint<5>(shamt)) << shamt; EmitR(0, static_cast<Register>(0), rt, rd, shamt, 0x00); @@ -342,6 +387,10 @@ void MipsAssembler::Srlv(Register rd, Register rt, Register rs) { EmitR(0, rs, rt, rd, 0, 0x06); } +void MipsAssembler::Rotrv(Register rd, Register rt, Register rs) { + EmitR(0, rs, rt, rd, 1, 0x06); +} + void MipsAssembler::Srav(Register rd, Register rt, Register rs) { EmitR(0, rs, rt, rd, 0, 0x07); } diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 1ef0992dac..d50b4f698e 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -133,9 +133,19 @@ class MipsAssembler FINAL : public Assembler { void Xori(Register rt, Register rs, uint16_t imm16); void Nor(Register rd, Register rs, Register rt); + void Movz(Register rd, Register rs, Register rt); // R2 + void Movn(Register rd, Register rs, Register rt); // R2 + void Seleqz(Register rd, Register rs, Register rt); // R6 + void Selnez(Register rd, Register rs, Register rt); // R6 + void ClzR6(Register rd, Register rs); + void ClzR2(Register rd, Register rs); + void CloR6(Register rd, Register rs); + void CloR2(Register rd, Register rs); + void Seb(Register rd, Register rt); // R2+ void Seh(Register rd, Register rt); // R2+ void Wsbh(Register rd, Register rt); // R2+ + void Bitswap(Register rd, Register rt); // R6 void Sll(Register rd, Register rt, int shamt); void Srl(Register rd, Register rt, int shamt); @@ -143,6 +153,7 @@ class MipsAssembler FINAL : public Assembler { void Sra(Register rd, Register rt, int shamt); void Sllv(Register rd, Register rt, Register rs); void Srlv(Register rd, Register rt, Register rs); + void Rotrv(Register rd, Register rt, Register rs); // R2+ void Srav(Register rd, Register rt, Register rs); void Lb(Register rt, Register rs, uint16_t imm16); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 77211ce059..a1485e4dd3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -74,7 +74,6 @@ #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "utils.h" -#include "vector_output_stream.h" #include "well_known_classes.h" #include "zip_archive.h" diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc index c2f23aa523..2d15f6f41e 100644 --- a/disassembler/disassembler_mips.cc +++ b/disassembler/disassembler_mips.cc @@ -139,6 +139,7 @@ static const MipsInstruction gMipsInstructions[] = { // SPECIAL2 { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" }, { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" }, + { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 33, "clo", "DS" }, { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" }, { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" }, { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" }, @@ -148,13 +149,34 @@ static const MipsInstruction gMipsInstructions[] = { // SPECIAL3 { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 3, "dext", "TSAZ", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | (16 << 6) | 32, "seb", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | (24 << 6) | 32, "seh", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | 32, "bitswap", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | 36, "dbitswap", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | (2 << 6) | 36, "dsbh", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | (5 << 6) | 36, "dshd", "DT", }, - { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, (31 << kOpcodeShift) | (2 << 6) | 32, "wsbh", "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | (16 << 6) | 32, + "seb", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | (24 << 6) | 32, + "seh", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | 32, + "bitswap", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | 36, + "dbitswap", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | (2 << 6) | 36, + "dsbh", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | (5 << 6) | 36, + "dshd", + "DT", }, + { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f, + (31 << kOpcodeShift) | (2 << 6) | 32, + "wsbh", + "DT", }, { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x26, "sc", "Tl", }, { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x27, "scd", "Tl", }, { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x36, "ll", "Tl", }, diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index d20f7d53de..58331296bf 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -42,6 +42,8 @@ #include "gc/space/space-inl.h" #include "image.h" #include "indenter.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "mapping_table.h" #include "mirror/array-inl.h" #include "mirror/class-inl.h" @@ -52,7 +54,6 @@ #include "oat_file-inl.h" #include "oat_file_manager.h" #include "os.h" -#include "output_stream.h" #include "safe_map.h" #include "scoped_thread_state_change.h" #include "stack_map.h" @@ -1663,6 +1664,8 @@ class ImageDumper { ImageHeader::kSectionDexCacheArrays); const auto& intern_section = image_header_.GetImageSection( ImageHeader::kSectionInternedStrings); + const auto& class_table_section = image_header_.GetImageSection( + ImageHeader::kSectionClassTable); stats_.header_bytes = header_bytes; stats_.alignment_bytes += RoundUp(header_bytes, kObjectAlignment) - header_bytes; // Add padding between the field and method section. @@ -1679,6 +1682,7 @@ class ImageDumper { stats_.art_method_bytes += method_section.Size(); stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size(); stats_.interned_strings_bytes += intern_section.Size(); + stats_.class_table_bytes += class_table_section.Size(); stats_.Dump(os, indent_os); os << "\n"; @@ -2069,6 +2073,7 @@ class ImageDumper { size_t art_method_bytes; size_t dex_cache_arrays_bytes; size_t interned_strings_bytes; + size_t class_table_bytes; size_t bitmap_bytes; size_t alignment_bytes; @@ -2100,6 +2105,7 @@ class ImageDumper { art_method_bytes(0), dex_cache_arrays_bytes(0), interned_strings_bytes(0), + class_table_bytes(0), bitmap_bytes(0), alignment_bytes(0), managed_code_bytes(0), @@ -2262,6 +2268,7 @@ class ImageDumper { "art_method_bytes = %8zd (%2.0f%% of art file bytes)\n" "dex_cache_arrays_bytes = %8zd (%2.0f%% of art file bytes)\n" "interned_string_bytes = %8zd (%2.0f%% of art file bytes)\n" + "class_table_bytes = %8zd (%2.0f%% of art file bytes)\n" "bitmap_bytes = %8zd (%2.0f%% of art file bytes)\n" "alignment_bytes = %8zd (%2.0f%% of art file bytes)\n\n", header_bytes, PercentOfFileBytes(header_bytes), @@ -2272,11 +2279,14 @@ class ImageDumper { PercentOfFileBytes(dex_cache_arrays_bytes), interned_strings_bytes, PercentOfFileBytes(interned_strings_bytes), + class_table_bytes, PercentOfFileBytes(class_table_bytes), bitmap_bytes, PercentOfFileBytes(bitmap_bytes), alignment_bytes, PercentOfFileBytes(alignment_bytes)) << std::flush; - CHECK_EQ(file_bytes, header_bytes + object_bytes + art_field_bytes + art_method_bytes + - dex_cache_arrays_bytes + interned_strings_bytes + bitmap_bytes + alignment_bytes); + CHECK_EQ(file_bytes, + header_bytes + object_bytes + art_field_bytes + art_method_bytes + + dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes + + bitmap_bytes + alignment_bytes); } os << "object_bytes breakdown:\n"; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 3d9f7dc2d5..723bb1762d 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -526,6 +526,20 @@ void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); } +void PatchOat::PatchClassTable(const ImageHeader* image_header) { + const auto& section = image_header->GetImageSection(ImageHeader::kSectionClassTable); + // Note that we require that ReadFromMemory does not make an internal copy of the elements. + // This also relies on visit roots not doing any verification which could fail after we update + // the roots to be the image addresses. + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + ClassTable temp_table; + temp_table.ReadFromMemory(image_->Begin() + section.Offset()); + FixupRootVisitor visitor(this); + BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&visitor, RootInfo(kRootUnknown)); + temp_table.VisitRoots(buffered_visitor); +} + + class RelocatedPointerVisitor { public: explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} @@ -606,6 +620,7 @@ bool PatchOat::PatchImage() { PatchArtFields(image_header); PatchArtMethods(image_header); PatchInternedStrings(image_header); + PatchClassTable(image_header); // Patch dex file int/long arrays which point to ArtFields. PatchDexFileArrays(img_roots); diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 09150144ec..38bd865b22 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -116,6 +116,8 @@ class PatchOat { void PatchArtMethods(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); void PatchInternedStrings(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); + void PatchClassTable(const ImageHeader* image_header) + SHARED_REQUIRES(Locks::mutator_lock_); void PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 47f2569b82..238d9f3fe2 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -298,7 +298,9 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* ShadowFrame* shadow_frame = self->PopStackedShadowFrame(StackedShadowFrameType::kDeoptimizationShadowFrame); mirror::Throwable* pending_exception = nullptr; - self->PopDeoptimizationContext(result, &pending_exception); + bool from_code = false; + self->PopDeoptimizationContext(result, &pending_exception, &from_code); + CHECK(!from_code); self->SetTopOfStack(nullptr); self->SetTopOfShadowStack(shadow_frame); @@ -307,7 +309,7 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* if (pending_exception != nullptr) { self->SetException(pending_exception); } - interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result); + interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, from_code, result); } if (kLogInvocationStartAndReturn) { LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(), diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h index d6a44f7293..8430d68d0e 100644 --- a/runtime/base/bit_utils.h +++ b/runtime/base/bit_utils.h @@ -23,6 +23,7 @@ #include "base/logging.h" #include "base/iteration_range.h" +#include "base/stl_util.h" namespace art { @@ -108,12 +109,12 @@ static inline int WhichPowerOf2(T x) { } // For rounding integers. -// NOTE: In the absence of std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>. +// Note: Omit the `n` from T type deduction, deduce only from the `x` argument. template<typename T> -static constexpr T RoundDown(T x, typename std::decay<T>::type n) WARN_UNUSED; +static constexpr T RoundDown(T x, typename Identity<T>::type n) WARN_UNUSED; template<typename T> -static constexpr T RoundDown(T x, typename std::decay<T>::type n) { +static constexpr T RoundDown(T x, typename Identity<T>::type n) { return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0)) (x & -n); diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h index 95baa822b1..fc1a52f807 100644 --- a/runtime/base/hash_set.h +++ b/runtime/base/hash_set.h @@ -236,7 +236,7 @@ class HashSet { // Returns how large the table is after being written. If target is null, then no writing happens // but the size is still returned. Target must be 8 byte aligned. - size_t WriteToMemory(uint8_t* ptr) { + size_t WriteToMemory(uint8_t* ptr) const { size_t offset = 0; offset = WriteToBytes(ptr, offset, static_cast<uint64_t>(num_elements_)); offset = WriteToBytes(ptr, offset, static_cast<uint64_t>(num_buckets_)); @@ -457,7 +457,7 @@ class HashSet { } // Make sure that everything reinserts in the right spot. Returns the number of errors. - size_t Verify() { + size_t Verify() NO_THREAD_SAFETY_ANALYSIS { size_t errors = 0; for (size_t i = 0; i < num_buckets_; ++i) { T& element = data_[i]; diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h index 324ab218d2..ad03c319d9 100644 --- a/runtime/base/stl_util.h +++ b/runtime/base/stl_util.h @@ -156,6 +156,23 @@ struct CStringLess { } }; +// Use to suppress type deduction for a function argument. +// See std::identity<> for more background: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.2.2 - move/forward helpers +// +// e.g. "template <typename X> void bar(identity<X>::type foo); +// bar(5); // compilation error +// bar<int>(5); // ok +// or "template <typename T> void foo(T* x, typename Identity<T*>::type y); +// Base b; +// Derived d; +// foo(&b, &d); // Use implicit Derived* -> Base* conversion. +// If T was deduced from both &b and &d, there would be a mismatch, i.e. deduction failure. +template <typename T> +struct Identity { + using type = T; +}; + } // namespace art #endif // ART_RUNTIME_BASE_STL_UTIL_H_ diff --git a/runtime/base/variant_map.h b/runtime/base/variant_map.h index 82e5d2e21b..531cb37355 100644 --- a/runtime/base/variant_map.h +++ b/runtime/base/variant_map.h @@ -19,8 +19,11 @@ #include <memory.h> #include <map> +#include <type_traits> #include <utility> +#include "base/stl_util.h" + namespace art { // @@ -268,8 +271,9 @@ struct VariantMap { } // Set a value for a given key, overwriting the previous value if any. + // Note: Omit the `value` from TValue type deduction, deduce only from the `key` argument. template <typename TValue> - void Set(const TKey<TValue>& key, const TValue& value) { + void Set(const TKey<TValue>& key, const typename Identity<TValue>::type& value) { // Clone the value first, to protect against &value == GetValuePtr(key). auto* new_value = new TValue(value); @@ -279,8 +283,9 @@ struct VariantMap { // Set a value for a given key, only if there was no previous value before. // Returns true if the value was set, false if a previous value existed. + // Note: Omit the `value` from TValue type deduction, deduce only from the `key` argument. template <typename TValue> - bool SetIfMissing(const TKey<TValue>& key, const TValue& value) { + bool SetIfMissing(const TKey<TValue>& key, const typename Identity<TValue>::type& value) { TValue* ptr = Get(key); if (ptr == nullptr) { Set(key, value); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 3f31fcd153..0a37f26135 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1017,6 +1017,15 @@ bool ClassLinker::InitFromImage(std::string* error_msg) { mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); + const ImageHeader& header = space->GetImageHeader(); + const ImageSection& section = header.GetImageSection(ImageHeader::kSectionClassTable); + if (section.Size() > 0u) { + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); + ClassTable* const class_table = InsertClassTableForClassLoader(nullptr); + class_table->ReadFromMemory(space->Begin() + section.Offset()); + dex_cache_boot_image_class_lookup_required_ = false; + } + FinishInit(self); VLOG(startup) << "ClassLinker::InitFromImage exiting"; @@ -2786,9 +2795,11 @@ void ClassLinker::AddImageClassesToClassTable(gc::space::ImageSpace* image_space Thread* self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); ScopedAssertNoThreadSuspension ants(self, "Moving image classes to class table"); + + ClassTable* const class_table = InsertClassTableForClassLoader(class_loader); + mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches(image_space); std::string temp; - ClassTable* const class_table = InsertClassTableForClassLoader(class_loader); for (int32_t i = 0; i < dex_caches->GetLength(); i++) { mirror::DexCache* dex_cache = dex_caches->Get(i); GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes(); diff --git a/runtime/class_table.cc b/runtime/class_table.cc index 3ed1c9540d..df2dbf416c 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -115,7 +115,7 @@ bool ClassTable::Remove(const char* descriptor) { return false; } -std::size_t ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root) +uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root) const { std::string temp; return ComputeModifiedUtf8Hash(root.Read()->GetDescriptor(&temp)); @@ -133,7 +133,7 @@ bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Clas return a.Read()->DescriptorEquals(descriptor); } -std::size_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descriptor) const { +uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descriptor) const { return ComputeModifiedUtf8Hash(descriptor); } @@ -148,4 +148,29 @@ bool ClassTable::InsertDexFile(mirror::Object* dex_file) { return true; } +size_t ClassTable::WriteToMemory(uint8_t* ptr) const { + ClassSet combined; + // Combine all the class sets in case there are multiple, also adjusts load factor back to + // default in case classes were pruned. + for (const ClassSet& class_set : classes_) { + for (const GcRoot<mirror::Class>& root : class_set) { + combined.Insert(root); + } + } + const size_t ret = combined.WriteToMemory(ptr); + // Sanity check. + if (kIsDebugBuild && ptr != nullptr) { + size_t read_count; + ClassSet class_set(ptr, /*make copy*/false, &read_count); + class_set.Verify(); + } + return ret; +} + +size_t ClassTable::ReadFromMemory(uint8_t* ptr) { + size_t read_count = 0; + classes_.insert(classes_.begin(), ClassSet(ptr, /*make copy*/false, &read_count)); + return read_count; +} + } // namespace art diff --git a/runtime/class_table.h b/runtime/class_table.h index 002bb564ab..c911365698 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -104,17 +104,27 @@ class ClassTable { REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + // Combines all of the tables into one class set. + size_t WriteToMemory(uint8_t* ptr) const + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + size_t ReadFromMemory(uint8_t* ptr) + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + private: class ClassDescriptorHashEquals { public: + // uint32_t for cross compilation. + uint32_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS; // Same class loader and descriptor. - std::size_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS; bool operator()(const GcRoot<mirror::Class>& a, const GcRoot<mirror::Class>& b) const NO_THREAD_SAFETY_ANALYSIS;; // Same descriptor. bool operator()(const GcRoot<mirror::Class>& a, const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS; - std::size_t operator()(const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS; + // uint32_t for cross compilation. + uint32_t operator()(const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS; }; class GcRootEmptyFn { public: diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc index 438b6b8109..3f621249c5 100644 --- a/runtime/dex_instruction.cc +++ b/runtime/dex_instruction.cc @@ -189,8 +189,17 @@ std::string Instruction::DumpString(const DexFile* file) const { case CONST_STRING: if (file != nullptr) { uint32_t string_idx = VRegB_21c(); - os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(), - PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx); + if (string_idx < file->NumStringIds()) { + os << StringPrintf("const-string v%d, %s // string@%d", + VRegA_21c(), + PrintableString(file->StringDataByIdx(string_idx)).c_str(), + string_idx); + } else { + os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d", + VRegA_21c(), + string_idx, + string_idx); + } break; } FALLTHROUGH_INTENDED; @@ -348,9 +357,19 @@ std::string Instruction::DumpString(const DexFile* file) const { if (Opcode() == CONST_STRING_JUMBO) { uint32_t string_idx = VRegB_31c(); if (file != nullptr) { - os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(), - PrintableString(file->StringDataByIdx(string_idx)).c_str(), - string_idx); + if (string_idx < file->NumStringIds()) { + os << StringPrintf("%s v%d, %s // string@%d", + opcode, + VRegA_31c(), + PrintableString(file->StringDataByIdx(string_idx)).c_str(), + string_idx); + } else { + os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d", + opcode, + VRegA_31c(), + string_idx, + string_idx); + } } else { os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); } diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index dfd9fcddb8..c019cae722 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -52,7 +52,7 @@ extern "C" NO_RETURN void artDeoptimizeFromCompiledCode(Thread* self) // Before deoptimizing to interpreter, we must push the deoptimization context. JValue return_value; return_value.SetJ(0); // we never deoptimize from compiled code with an invoke result. - self->PushDeoptimizationContext(return_value, false, self->GetException()); + self->PushDeoptimizationContext(return_value, false, /* from_code */ true, self->GetException()); QuickExceptionHandler exception_handler(self, true); exception_handler.DeoptimizeSingleFrame(); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 6361144db1..08c9b49729 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -685,7 +685,9 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, } mirror::Throwable* pending_exception = nullptr; - self->PopDeoptimizationContext(&result, &pending_exception); + bool from_code = false; + self->PopDeoptimizationContext(&result, &pending_exception, /* out */ &from_code); + CHECK(from_code); // Push a transition back into managed code onto the linked list in thread. self->PushManagedStackFragment(&fragment); @@ -712,7 +714,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, if (pending_exception != nullptr) { self->SetException(pending_exception); } - interpreter::EnterInterpreterFromDeoptimize(self, deopt_frame, &result); + interpreter::EnterInterpreterFromDeoptimize(self, deopt_frame, from_code, &result); } else { const char* old_cause = self->StartAssertNoThreadSuspension( "Building interpreter shadow frame"); @@ -754,7 +756,8 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, if (UNLIKELY(Dbg::IsForcedInterpreterNeededForUpcall(self, caller))) { // Push the context of the deoptimization stack so we can restore the return value and the // exception before executing the deoptimized frames. - self->PushDeoptimizationContext(result, shorty[0] == 'L', self->GetException()); + self->PushDeoptimizationContext( + result, shorty[0] == 'L', /* from_code */ false, self->GetException()); // Set special exception to cause deoptimization. self->SetException(Thread::GetDeoptimizationException()); diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc index 9c8e4df1e0..7d00094c9f 100644 --- a/runtime/gc/allocator/rosalloc.cc +++ b/runtime/gc/allocator/rosalloc.cc @@ -1526,10 +1526,9 @@ void RosAlloc::SetFootprintLimit(size_t new_capacity) { } } +// Below may be called by mutator itself just before thread termination. size_t RosAlloc::RevokeThreadLocalRuns(Thread* thread) { Thread* self = Thread::Current(); - // Avoid race conditions on the bulk free bit maps with BulkFree() (GC). - ReaderMutexLock wmu(self, bulk_free_lock_); size_t free_bytes = 0U; for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; idx++) { MutexLock mu(self, *size_bracket_locks_[idx]); @@ -1544,10 +1543,17 @@ size_t RosAlloc::RevokeThreadLocalRuns(Thread* thread) { // Count the number of free slots left. size_t num_free_slots = thread_local_run->NumberOfFreeSlots(); free_bytes += num_free_slots * bracketSizes[idx]; + // The above bracket index lock guards thread local free list to avoid race condition + // with unioning bulk free list to thread local free list by GC thread in BulkFree. + // If thread local run is true, GC thread will help update thread local free list + // in BulkFree. And the latest thread local free list will be merged to free list + // either when this thread local run is full or when revoking this run here. In this + // case the free list wll be updated. If thread local run is false, GC thread will help + // merge bulk free list in next BulkFree. + // Thus no need to merge bulk free list to free list again here. bool dont_care; thread_local_run->MergeThreadLocalFreeListToFreeList(&dont_care); thread_local_run->SetIsThreadLocal(false); - thread_local_run->MergeBulkFreeListToFreeList(); DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end()); DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end()); RevokeRun(self, idx, thread_local_run); diff --git a/runtime/image.cc b/runtime/image.cc index 1bc19ff656..2eac3fb873 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -24,7 +24,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '2', '\0' }; +const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '3', '\0' }; ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/image.h b/runtime/image.h index 555cf5ddb7..a16f3c98fb 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -170,6 +170,7 @@ class PACKED(4) ImageHeader { kSectionArtMethods, kSectionDexCacheArrays, kSectionInternedStrings, + kSectionClassTable, kSectionImageBitmap, kSectionCount, // Number of elements in enum. }; diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index bc2c197d33..264cd2c785 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -1062,7 +1062,9 @@ TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self, uintpt PrettyMethod(method).c_str(), return_value.GetJ()) << *self; } - self->PushDeoptimizationContext(return_value, return_shorty == 'L', + self->PushDeoptimizationContext(return_value, + return_shorty == 'L', + false /* from_code */, nullptr /* no pending exception */); return GetTwoWordSuccessValue(*return_pc, reinterpret_cast<uintptr_t>(GetQuickDeoptimizationEntryPoint())); diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index d686f749f3..871fad7b80 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -397,7 +397,10 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive self->PopShadowFrame(); } -void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JValue* ret_val) +void EnterInterpreterFromDeoptimize(Thread* self, + ShadowFrame* shadow_frame, + bool from_code, + JValue* ret_val) SHARED_REQUIRES(Locks::mutator_lock_) { JValue value; // Set value to last known result in case the shadow frame chain is empty. @@ -408,7 +411,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JVa self->SetTopOfShadowStack(shadow_frame); const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem(); const uint32_t dex_pc = shadow_frame->GetDexPC(); - uint32_t new_dex_pc; + uint32_t new_dex_pc = dex_pc; if (UNLIKELY(self->IsExceptionPending())) { // If we deoptimize from the QuickExceptionHandler, we already reported the exception to // the instrumentation. To prevent from reporting it a second time, we simply pass a @@ -419,11 +422,16 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JVa instrumentation); new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler // or DexFile::kDexNoIndex if there is none. - } else { - const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); - // For an invoke, use the dex pc of the next instruction. + } else if (!from_code) { + // For the debugger and full deoptimization stack, we must go past the invoke + // instruction, as it already executed. // TODO: should be tested more once b/17586779 is fixed. - new_dex_pc = dex_pc + (instr->IsInvoke() ? instr->SizeInCodeUnits() : 0); + const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); + DCHECK(instr->IsInvoke()); + new_dex_pc = dex_pc + instr->SizeInCodeUnits(); + } else { + // Nothing to do, the dex_pc is the one at which the code requested + // the deoptimization. } if (new_dex_pc != DexFile::kDexNoIndex) { shadow_frame->SetDexPC(new_dex_pc); @@ -432,6 +440,8 @@ void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JVa ShadowFrame* old_frame = shadow_frame; shadow_frame = shadow_frame->GetLink(); ShadowFrame::DeleteDeoptimizedFrame(old_frame); + // Following deoptimizations of shadow frames must pass the invoke instruction. + from_code = false; first = false; } ret_val->SetJ(value.GetJ()); diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index b21ea84d8e..8e7f3da1ba 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -37,7 +37,8 @@ extern void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, mirror::Object* receiver, uint32_t* args, JValue* result) SHARED_REQUIRES(Locks::mutator_lock_); -extern void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, +// 'from_code' denotes whether the deoptimization was explicitly triggered by compiled code. +extern void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, bool from_code, JValue* ret_val) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 27a0e2d1af..92aa86ee53 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -142,11 +142,24 @@ bool Jit::LoadCompiler(std::string* error_msg) { bool Jit::CompileMethod(ArtMethod* method, Thread* self) { DCHECK(!method->IsRuntimeMethod()); + // Don't compile the method if it has breakpoints. if (Dbg::IsDebuggerActive() && Dbg::MethodHasAnyBreakpoints(method)) { VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to breakpoint"; return false; } - return jit_compile_method_(jit_compiler_handle_, method, self); + + // Don't compile the method if we are supposed to be deoptimized. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (instrumentation->AreAllMethodsDeoptimized() || instrumentation->IsDeoptimized(method)) { + return false; + } + + if (!code_cache_->NotifyCompilationOf(method, self)) { + return false; + } + bool success = jit_compile_method_(jit_compiler_handle_, method, self); + code_cache_->DoneCompiling(method, self); + return success; } void Jit::CreateThreadPool() { diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 804d69fbf8..3342e92a79 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -536,7 +536,9 @@ void JitCodeCache::GarbageCollectCache(Thread* self) { instrumentation->UpdateMethodsCode(it.second, GetQuickToInterpreterBridge()); } for (ProfilingInfo* info : profiling_infos_) { - info->GetMethod()->SetProfilingInfo(nullptr); + if (!info->IsMethodBeingCompiled()) { + info->GetMethod()->SetProfilingInfo(nullptr); + } } } @@ -577,12 +579,17 @@ void JitCodeCache::GarbageCollectCache(Thread* self) { } } - // Free all profiling info. - for (ProfilingInfo* info : profiling_infos_) { - DCHECK(info->GetMethod()->GetProfilingInfo(sizeof(void*)) == nullptr); - mspace_free(data_mspace_, reinterpret_cast<uint8_t*>(info)); - } - profiling_infos_.clear(); + void* data_mspace = data_mspace_; + // Free all profiling infos of methods that were not being compiled. + auto profiling_kept_end = std::remove_if(profiling_infos_.begin(), profiling_infos_.end(), + [data_mspace] (ProfilingInfo* info) { + if (info->GetMethod()->GetProfilingInfo(sizeof(void*)) == nullptr) { + mspace_free(data_mspace, reinterpret_cast<uint8_t*>(info)); + return true; + } + return false; + }); + profiling_infos_.erase(profiling_kept_end, profiling_infos_.end()); live_bitmap_.reset(nullptr); has_done_one_collection_ = true; @@ -643,7 +650,7 @@ ProfilingInfo* JitCodeCache::AddProfilingInfoInternal(Thread* self, ArtMethod* method, const std::vector<uint32_t>& entries) { size_t profile_info_size = RoundUp( - sizeof(ProfilingInfo) + sizeof(ProfilingInfo::InlineCache) * entries.size(), + sizeof(ProfilingInfo) + sizeof(InlineCache) * entries.size(), sizeof(void*)); ScopedThreadSuspension sts(self, kSuspended); MutexLock mu(self, lock_); @@ -694,5 +701,25 @@ uint64_t JitCodeCache::GetLastUpdateTimeNs() { MutexLock mu(Thread::Current(), lock_); return last_update_time_ns_; } + +bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self) { + if (ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { + return false; + } + MutexLock mu(self, lock_); + ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*)); + if (info == nullptr || info->IsMethodBeingCompiled()) { + return false; + } + info->SetIsMethodBeingCompiled(true); + return true; +} + +void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self ATTRIBUTE_UNUSED) { + ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*)); + DCHECK(info->IsMethodBeingCompiled()); + info->SetIsMethodBeingCompiled(false); +} + } // namespace jit } // namespace art diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index acd7c62940..4032c7b832 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -66,6 +66,14 @@ class JitCodeCache { // of methods that got JIT compiled, as we might have collected some. size_t NumberOfCompiledCode() REQUIRES(!lock_); + bool NotifyCompilationOf(ArtMethod* method, Thread* self) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!lock_); + + void DoneCompiling(ArtMethod* method, Thread* self) + SHARED_REQUIRES(Locks::mutator_lock_) + REQUIRES(!lock_); + // Allocate and write code and its metadata to the code cache. uint8_t* CommitCode(Thread* self, ArtMethod* method, diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 2e52b1b4dc..dcb346cd3a 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -54,28 +54,29 @@ bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocatio code_ptr += instruction.SizeInCodeUnits(); } - // If there is no instruction we are interested in, no need to create a `ProfilingInfo` - // object, it will never be filled. - if (entries.empty()) { - return true; - } + // We always create a `ProfilingInfo` object, even if there is no instruction we are + // interested in. The JIT code cache internally uses it. // Allocate the `ProfilingInfo` object int the JIT's data space. jit::JitCodeCache* code_cache = Runtime::Current()->GetJit()->GetCodeCache(); return code_cache->AddProfilingInfo(self, method, entries, retry_allocation) != nullptr; } -void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) { +InlineCache* ProfilingInfo::GetInlineCache(uint32_t dex_pc) { InlineCache* cache = nullptr; // TODO: binary search if array is too long. for (size_t i = 0; i < number_of_inline_caches_; ++i) { - if (cache_[i].dex_pc == dex_pc) { + if (cache_[i].dex_pc_ == dex_pc) { cache = &cache_[i]; break; } } DCHECK(cache != nullptr); + return cache; +} +void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) { + InlineCache* cache = GetInlineCache(dex_pc); for (size_t i = 0; i < InlineCache::kIndividualCacheSize; ++i) { mirror::Class* existing = cache->classes_[i].Read(); if (existing == cls) { diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index b13a315d64..ddaf02fdf5 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -25,6 +25,7 @@ namespace art { class ArtMethod; +class ProfilingInfo; namespace jit { class JitCodeCache; @@ -34,6 +35,49 @@ namespace mirror { class Class; } +// Structure to store the classes seen at runtime for a specific instruction. +// Once the classes_ array is full, we consider the INVOKE to be megamorphic. +class InlineCache { + public: + bool IsMonomorphic() const { + DCHECK_GE(kIndividualCacheSize, 2); + return !classes_[0].IsNull() && classes_[1].IsNull(); + } + + bool IsMegamorphic() const { + for (size_t i = 0; i < kIndividualCacheSize; ++i) { + if (classes_[i].IsNull()) { + return false; + } + } + return true; + } + + mirror::Class* GetMonomorphicType() const SHARED_REQUIRES(Locks::mutator_lock_) { + // Note that we cannot ensure the inline cache is actually monomorphic + // at this point, as other threads may have updated it. + return classes_[0].Read(); + } + + bool IsUnitialized() const { + return classes_[0].IsNull(); + } + + bool IsPolymorphic() const { + DCHECK_GE(kIndividualCacheSize, 3); + return !classes_[1].IsNull() && classes_[kIndividualCacheSize - 1].IsNull(); + } + + private: + static constexpr uint16_t kIndividualCacheSize = 5; + uint32_t dex_pc_; + GcRoot<mirror::Class> classes_[kIndividualCacheSize]; + + friend class ProfilingInfo; + + DISALLOW_COPY_AND_ASSIGN(InlineCache); +}; + /** * Profiling info for a method, created and filled by the interpreter once the * method is warm, and used by the compiler to drive optimizations. @@ -67,44 +111,24 @@ class ProfilingInfo { return method_; } - private: - // Structure to store the classes seen at runtime for a specific instruction. - // Once the classes_ array is full, we consider the INVOKE to be megamorphic. - struct InlineCache { - bool IsMonomorphic() const { - DCHECK_GE(kIndividualCacheSize, 2); - return !classes_[0].IsNull() && classes_[1].IsNull(); - } - - bool IsMegamorphic() const { - for (size_t i = 0; i < kIndividualCacheSize; ++i) { - if (classes_[i].IsNull()) { - return false; - } - } - return true; - } + InlineCache* GetInlineCache(uint32_t dex_pc); - bool IsUnitialized() const { - return classes_[0].IsNull(); - } - - bool IsPolymorphic() const { - DCHECK_GE(kIndividualCacheSize, 3); - return !classes_[1].IsNull() && classes_[kIndividualCacheSize - 1].IsNull(); - } + bool IsMethodBeingCompiled() const { + return is_method_being_compiled_; + } - static constexpr uint16_t kIndividualCacheSize = 5; - uint32_t dex_pc; - GcRoot<mirror::Class> classes_[kIndividualCacheSize]; - }; + void SetIsMethodBeingCompiled(bool value) { + is_method_being_compiled_ = value; + } + private: ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries) : number_of_inline_caches_(entries.size()), - method_(method) { + method_(method), + is_method_being_compiled_(false) { memset(&cache_, 0, number_of_inline_caches_ * sizeof(InlineCache)); for (size_t i = 0; i < number_of_inline_caches_; ++i) { - cache_[i].dex_pc = entries[i]; + cache_[i].dex_pc_ = entries[i]; } } @@ -114,6 +138,11 @@ class ProfilingInfo { // Method this profiling info is for. ArtMethod* const method_; + // Whether the ArtMethod is currently being compiled. This flag + // is implicitly guarded by the JIT code cache lock. + // TODO: Make the JIT code cache lock global. + bool is_method_being_compiled_; + // Dynamically allocated array of size `number_of_inline_caches_`. InlineCache cache_[0]; diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc index 649df5f62b..d1687d7874 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -2210,4 +2210,55 @@ TEST_F(JniInternalTest, MonitorExitNotAllUnlocked) { check_jni_abort_catcher.Check("Still holding a locked object on JNI end"); } +static bool IsLocked(JNIEnv* env, jobject jobj) { + ScopedObjectAccess soa(env); + LockWord lock_word = soa.Decode<mirror::Object*>(jobj)->GetLockWord(true); + switch (lock_word.GetState()) { + case LockWord::kHashCode: + case LockWord::kUnlocked: + return false; + case LockWord::kThinLocked: + return true; + case LockWord::kFatLocked: + return lock_word.FatLockMonitor()->IsLocked(); + default: { + LOG(FATAL) << "Invalid monitor state " << lock_word.GetState(); + UNREACHABLE(); + } + } +} + +TEST_F(JniInternalTest, DetachThreadUnlockJNIMonitors) { + // We need to lock an object, detach, reattach, and check the locks. + // + // As re-attaching will create a different thread, we need to use a global + // ref to keep the object around. + + // Create an object to torture. + jobject global_ref; + { + jclass object_class = env_->FindClass("java/lang/Object"); + ASSERT_NE(object_class, nullptr); + jobject object = env_->AllocObject(object_class); + ASSERT_NE(object, nullptr); + global_ref = env_->NewGlobalRef(object); + } + + // Lock it. + env_->MonitorEnter(global_ref); + ASSERT_TRUE(IsLocked(env_, global_ref)); + + // Detach and re-attach. + jint detach_result = vm_->DetachCurrentThread(); + ASSERT_EQ(detach_result, JNI_OK); + jint attach_result = vm_->AttachCurrentThread(&env_, nullptr); + ASSERT_EQ(attach_result, JNI_OK); + + // Look at the global ref, check whether it's still locked. + ASSERT_FALSE(IsLocked(env_, global_ref)); + + // Delete the global ref. + env_->DeleteGlobalRef(global_ref); +} + } // namespace art diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 7f4519c8f2..5b1061087d 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -41,15 +41,13 @@ ParsedOptions::ParsedOptions() // Runtime::Abort } -ParsedOptions* ParsedOptions::Create(const RuntimeOptions& options, bool ignore_unrecognized, - RuntimeArgumentMap* runtime_options) { +bool ParsedOptions::Parse(const RuntimeOptions& options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options) { CHECK(runtime_options != nullptr); - std::unique_ptr<ParsedOptions> parsed(new ParsedOptions()); - if (parsed->Parse(options, ignore_unrecognized, runtime_options)) { - return parsed.release(); - } - return nullptr; + ParsedOptions parser; + return parser.DoParse(options, ignore_unrecognized, runtime_options); } using RuntimeParser = CmdlineParser<RuntimeArgumentMap, RuntimeArgumentMap::Key>; @@ -407,8 +405,9 @@ static void MaybeOverrideVerbosity() { // gLogVerbosity.verifier = true; // TODO: don't check this in! } -bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized, - RuntimeArgumentMap* runtime_options) { +bool ParsedOptions::DoParse(const RuntimeOptions& options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options) { for (size_t i = 0; i < options.size(); ++i) { if (true && options[0].first == "-Xzygote") { LOG(INFO) << "option[" << i << "]=" << options[i].first; diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h index 529dd5ce1c..5974fb6a6e 100644 --- a/runtime/parsed_options.h +++ b/runtime/parsed_options.h @@ -50,8 +50,9 @@ class ParsedOptions { static std::unique_ptr<RuntimeParser> MakeParser(bool ignore_unrecognized); // returns true if parsing succeeds, and stores the resulting options into runtime_options - static ParsedOptions* Create(const RuntimeOptions& options, bool ignore_unrecognized, - RuntimeArgumentMap* runtime_options); + static bool Parse(const RuntimeOptions& options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options); bool (*hook_is_sensitive_thread_)(); jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap); @@ -72,8 +73,9 @@ class ParsedOptions { void Exit(int status); void Abort(); - bool Parse(const RuntimeOptions& options, bool ignore_unrecognized, - RuntimeArgumentMap* runtime_options); + bool DoParse(const RuntimeOptions& options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options); }; } // namespace art diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc index a8575de425..fad00c73d8 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -60,8 +60,8 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { options.push_back(std::make_pair("exit", test_exit)); RuntimeArgumentMap map; - std::unique_ptr<ParsedOptions> parsed(ParsedOptions::Create(options, false, &map)); - ASSERT_TRUE(parsed.get() != nullptr); + bool parsed = ParsedOptions::Parse(options, false, &map); + ASSERT_TRUE(parsed); ASSERT_NE(0u, map.Size()); using Opt = RuntimeArgumentMap; @@ -102,8 +102,8 @@ TEST_F(ParsedOptionsTest, ParsedOptionsGc) { options.push_back(std::make_pair("-Xgc:MC", nullptr)); RuntimeArgumentMap map; - std::unique_ptr<ParsedOptions> parsed(ParsedOptions::Create(options, false, &map)); - ASSERT_TRUE(parsed.get() != nullptr); + bool parsed = ParsedOptions::Parse(options, false, &map); + ASSERT_TRUE(parsed); ASSERT_NE(0u, map.Size()); using Opt = RuntimeArgumentMap; diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 1552318c1e..9cb37eed58 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -283,7 +283,12 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { prev_shadow_frame_(nullptr), stacked_shadow_frame_pushed_(false), single_frame_deopt_(single_frame), - single_frame_done_(false) { + single_frame_done_(false), + single_frame_deopt_method_(nullptr) { + } + + ArtMethod* GetSingleFrameDeoptMethod() const { + return single_frame_deopt_method_; } bool VisitFrame() OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { @@ -356,6 +361,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { // Single-frame deopt ends at the first non-inlined frame and needs to store that method. exception_handler_->SetHandlerQuickArg0(reinterpret_cast<uintptr_t>(method)); single_frame_done_ = true; + single_frame_deopt_method_ = method; } return true; } @@ -586,6 +592,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { bool stacked_shadow_frame_pushed_; const bool single_frame_deopt_; bool single_frame_done_; + ArtMethod* single_frame_deopt_method_; DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor); }; @@ -614,6 +621,14 @@ void QuickExceptionHandler::DeoptimizeSingleFrame() { DeoptimizeStackVisitor visitor(self_, context_, this, true); visitor.WalkStack(true); + // Compiled code made an explicit deoptimization. Transfer the code + // to interpreter and clear the counter to JIT the method again. + ArtMethod* deopt_method = visitor.GetSingleFrameDeoptMethod(); + DCHECK(deopt_method != nullptr); + deopt_method->ClearCounter(); + Runtime::Current()->GetInstrumentation()->UpdateMethodsCode( + deopt_method, GetQuickToInterpreterBridge()); + // PC needs to be of the quick-to-interpreter bridge. int32_t offset; #ifdef __LP64__ diff --git a/runtime/runtime.cc b/runtime/runtime.cc index fe8eb0d78d..dedc110b00 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -434,14 +434,25 @@ void Runtime::SweepSystemWeaks(IsMarkedVisitor* visitor) { GetLambdaBoxTable()->SweepWeakBoxedLambdas(visitor); } -bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) { +bool Runtime::ParseOptions(const RuntimeOptions& raw_options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options) { + InitLogging(/* argv */ nullptr); // Calls Locks::Init() as a side effect. + bool parsed = ParsedOptions::Parse(raw_options, ignore_unrecognized, runtime_options); + if (!parsed) { + LOG(ERROR) << "Failed to parse options"; + return false; + } + return true; +} + +bool Runtime::Create(RuntimeArgumentMap&& runtime_options) { // TODO: acquire a static mutex on Runtime to avoid racing. if (Runtime::instance_ != nullptr) { return false; } - InitLogging(nullptr); // Calls Locks::Init() as a side effect. instance_ = new Runtime; - if (!instance_->Init(options, ignore_unrecognized)) { + if (!instance_->Init(std::move(runtime_options))) { // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will // leak memory, instead. Fix the destructor. b/19100793. // delete instance_; @@ -451,6 +462,12 @@ bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) { return true; } +bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) { + RuntimeArgumentMap runtime_options; + return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) && + Create(std::move(runtime_options)); +} + static jobject CreateSystemClassLoader(Runtime* runtime) { if (runtime->IsAotCompiler() && !runtime->GetCompilerCallbacks()->IsBootImage()) { return nullptr; @@ -829,21 +846,14 @@ void Runtime::SetSentinel(mirror::Object* sentinel) { sentinel_ = GcRoot<mirror::Object>(sentinel); } -bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) { +bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { + RuntimeArgumentMap runtime_options(std::move(runtime_options_in)); ATRACE_BEGIN("Runtime::Init"); CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize); MemMap::Init(); using Opt = RuntimeArgumentMap; - RuntimeArgumentMap runtime_options; - std::unique_ptr<ParsedOptions> parsed_options( - ParsedOptions::Create(raw_options, ignore_unrecognized, &runtime_options)); - if (parsed_options.get() == nullptr) { - LOG(ERROR) << "Failed to parse options"; - ATRACE_END(); - return false; - } VLOG(startup) << "Runtime::Init -verbose:startup enabled"; QuasiAtomic::Startup(); diff --git a/runtime/runtime.h b/runtime/runtime.h index bd3641405d..93d8fcfa46 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -84,6 +84,7 @@ class MonitorList; class MonitorPool; class NullPointerHandler; class OatFileManager; +struct RuntimeArgumentMap; class SignalCatcher; class StackOverflowHandler; class SuspensionHandler; @@ -112,8 +113,17 @@ enum VisitRootFlags : uint8_t { class Runtime { public: + // Parse raw runtime options. + static bool ParseOptions(const RuntimeOptions& raw_options, + bool ignore_unrecognized, + RuntimeArgumentMap* runtime_options); + + // Creates and initializes a new runtime. + static bool Create(RuntimeArgumentMap&& runtime_options) + SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_); + // Creates and initializes a new runtime. - static bool Create(const RuntimeOptions& options, bool ignore_unrecognized) + static bool Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_); // IsAotCompiler for compilers that don't have a running runtime. Only dex2oat currently. @@ -599,7 +609,7 @@ class Runtime { void BlockSignals(); - bool Init(const RuntimeOptions& options, bool ignore_unrecognized) + bool Init(RuntimeArgumentMap&& runtime_options) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_); void InitNativeMethods() REQUIRES(!Locks::mutator_lock_); void InitThreadGroups(Thread* self); diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h index 88ac00a672..4610f6f4a1 100644 --- a/runtime/runtime_options.h +++ b/runtime/runtime_options.h @@ -17,14 +17,13 @@ #ifndef ART_RUNTIME_RUNTIME_OPTIONS_H_ #define ART_RUNTIME_RUNTIME_OPTIONS_H_ -#include "runtime/base/variant_map.h" -#include "cmdline/cmdline_types.h" // TODO: don't need to include this file here +#include "base/variant_map.h" +#include "cmdline_types.h" // TODO: don't need to include this file here // Map keys #include <vector> #include <string> -#include "runtime/base/logging.h" -#include "cmdline/unit.h" +#include "base/logging.h" #include "jdwp/jdwp.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" diff --git a/runtime/thread.cc b/runtime/thread.cc index 63e6326f2f..90539b479f 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -164,14 +164,20 @@ void Thread::ResetQuickAllocEntryPointsForThread() { class DeoptimizationContextRecord { public: - DeoptimizationContextRecord(const JValue& ret_val, bool is_reference, + DeoptimizationContextRecord(const JValue& ret_val, + bool is_reference, + bool from_code, mirror::Throwable* pending_exception, DeoptimizationContextRecord* link) - : ret_val_(ret_val), is_reference_(is_reference), pending_exception_(pending_exception), + : ret_val_(ret_val), + is_reference_(is_reference), + from_code_(from_code), + pending_exception_(pending_exception), link_(link) {} JValue GetReturnValue() const { return ret_val_; } bool IsReference() const { return is_reference_; } + bool GetFromCode() const { return from_code_; } mirror::Throwable* GetPendingException() const { return pending_exception_; } DeoptimizationContextRecord* GetLink() const { return link_; } mirror::Object** GetReturnValueAsGCRoot() { @@ -189,6 +195,9 @@ class DeoptimizationContextRecord { // Indicates whether the returned value is a reference. If so, the GC will visit it. const bool is_reference_; + // Whether the context was created from an explicit deoptimization in the code. + const bool from_code_; + // The exception that was pending before deoptimization (or null if there was no pending // exception). mirror::Throwable* pending_exception_; @@ -220,22 +229,28 @@ class StackedShadowFrameRecord { DISALLOW_COPY_AND_ASSIGN(StackedShadowFrameRecord); }; -void Thread::PushDeoptimizationContext(const JValue& return_value, bool is_reference, +void Thread::PushDeoptimizationContext(const JValue& return_value, + bool is_reference, + bool from_code, mirror::Throwable* exception) { DeoptimizationContextRecord* record = new DeoptimizationContextRecord( return_value, is_reference, + from_code, exception, tlsPtr_.deoptimization_context_stack); tlsPtr_.deoptimization_context_stack = record; } -void Thread::PopDeoptimizationContext(JValue* result, mirror::Throwable** exception) { +void Thread::PopDeoptimizationContext(JValue* result, + mirror::Throwable** exception, + bool* from_code) { AssertHasDeoptimizationContext(); DeoptimizationContextRecord* record = tlsPtr_.deoptimization_context_stack; tlsPtr_.deoptimization_context_stack = record->GetLink(); result->SetJ(record->GetReturnValue().GetJ()); *exception = record->GetPendingException(); + *from_code = record->GetFromCode(); delete record; } @@ -2546,7 +2561,8 @@ void Thread::QuickDeliverException() { if (is_deoptimization) { // Save the exception into the deoptimization context so it can be restored // before entering the interpreter. - PushDeoptimizationContext(JValue(), false, exception); + PushDeoptimizationContext( + JValue(), /*is_reference */ false, /* from_code */ false, exception); } } // Don't leave exception visible while we try to find the handler, which may cause class diff --git a/runtime/thread.h b/runtime/thread.h index 4624f27564..c556c3614d 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -849,10 +849,14 @@ class Thread { // and execute Java code, so there might be nested deoptimizations happening. // We need to save the ongoing deoptimization shadow frames and return // values on stacks. - void PushDeoptimizationContext(const JValue& return_value, bool is_reference, + // 'from_code' denotes whether the deoptimization was explicitly made from + // compiled code. + void PushDeoptimizationContext(const JValue& return_value, + bool is_reference, + bool from_code, mirror::Throwable* exception) SHARED_REQUIRES(Locks::mutator_lock_); - void PopDeoptimizationContext(JValue* result, mirror::Throwable** exception) + void PopDeoptimizationContext(JValue* result, mirror::Throwable** exception, bool* from_code) SHARED_REQUIRES(Locks::mutator_lock_); void AssertHasDeoptimizationContext() SHARED_REQUIRES(Locks::mutator_lock_); @@ -1224,7 +1228,7 @@ class Thread { RuntimeStats stats; } tls64_; - struct PACKED(4) tls_ptr_sized_values { + struct PACKED(sizeof(void*)) tls_ptr_sized_values { tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr), managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr), self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0), diff --git a/runtime/utf.cc b/runtime/utf.cc index 5a116980c9..a2d6363c6e 100644 --- a/runtime/utf.cc +++ b/runtime/utf.cc @@ -178,8 +178,8 @@ int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count) { return static_cast<int32_t>(hash); } -size_t ComputeModifiedUtf8Hash(const char* chars) { - size_t hash = 0; +uint32_t ComputeModifiedUtf8Hash(const char* chars) { + uint32_t hash = 0; while (*chars != '\0') { hash = hash * 31 + *chars++; } diff --git a/runtime/utf.h b/runtime/utf.h index 03158c492d..4abd605f5a 100644 --- a/runtime/utf.h +++ b/runtime/utf.h @@ -85,8 +85,8 @@ int32_t ComputeUtf16Hash(mirror::CharArray* chars, int32_t offset, size_t char_c int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count); // Compute a hash code of a modified UTF-8 string. Not the standard java hash since it returns a -// size_t and hashes individual chars instead of codepoint words. -size_t ComputeModifiedUtf8Hash(const char* chars); +// uint32_t and hashes individual chars instead of codepoint words. +uint32_t ComputeModifiedUtf8Hash(const char* chars); /* * Retrieve the next UTF-16 character or surrogate pair from a UTF-8 string. diff --git a/test/005-annotations/expected.txt b/test/005-annotations/expected.txt index 180adf8687..3d9fd8bcfc 100644 --- a/test/005-annotations/expected.txt +++ b/test/005-annotations/expected.txt @@ -89,7 +89,7 @@ annotations on TYPE class android.test.anno.FullyNoted(1): annotations on FIELD int android.test.anno.FullyNoted.mBar: @android.test.anno.AnnoFancyField(nombre=fubar) interface android.test.anno.AnnoFancyField - aff: @android.test.anno.AnnoFancyField(nombre=fubar) / class $Proxy13 + aff: @android.test.anno.AnnoFancyField(nombre=fubar) / true --> nombre is 'fubar' SimplyNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType() diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java index 2f0a8d31c3..bc89f1682c 100644 --- a/test/005-annotations/src/android/test/anno/TestAnnotations.java +++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java @@ -20,6 +20,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.TreeMap; public class TestAnnotations { @@ -81,7 +82,7 @@ public class TestAnnotations { AnnoFancyField aff; aff = (AnnoFancyField) f.getAnnotation(AnnoFancyField.class); if (aff != null) { - System.out.println(" aff: " + aff + " / " + aff.getClass()); + System.out.println(" aff: " + aff + " / " + Proxy.isProxyClass(aff.getClass())); System.out.println(" --> nombre is '" + aff.nombre() + "'"); } } diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt index 052c8faf1b..be7023e49d 100644 --- a/test/044-proxy/expected.txt +++ b/test/044-proxy/expected.txt @@ -42,7 +42,7 @@ Invoke public abstract java.lang.String Shapes.blob() (no args) --- blob Success: method blob res=mix -$Proxy1.getTrace null:-1 +$PROXY_CLASS_NAME0$.getTrace null:-1 Invoke public abstract void Shapes.upChuck() (no args) Got expected ioobe @@ -51,7 +51,7 @@ Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedExcepti Got expected ie Proxy interfaces: [interface Quads, interface Colors, interface Trace] -Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()] +Proxy methods: [public final java.lang.String $PROXY_CLASS_NAME0$.blob(), public final double $PROXY_CLASS_NAME0$.blue(int), public final R0a $PROXY_CLASS_NAME0$.checkMe(), public final R0aa $PROXY_CLASS_NAME0$.checkMe(), public final R0base $PROXY_CLASS_NAME0$.checkMe(), public final void $PROXY_CLASS_NAME0$.circle(int), public final boolean $PROXY_CLASS_NAME0$.equals(java.lang.Object), public final void $PROXY_CLASS_NAME0$.getTrace(), public final int $PROXY_CLASS_NAME0$.green(double), public final int $PROXY_CLASS_NAME0$.hashCode(), public final int $PROXY_CLASS_NAME0$.mauve(java.lang.String), public final int $PROXY_CLASS_NAME0$.rectangle(int,int), public final int $PROXY_CLASS_NAME0$.red(float), public final int $PROXY_CLASS_NAME0$.square(int,int), public final java.lang.String $PROXY_CLASS_NAME0$.toString(), public final int $PROXY_CLASS_NAME0$.trapezoid(int,double,int), public final void $PROXY_CLASS_NAME0$.upCheck() throws java.lang.InterruptedException, public final void $PROXY_CLASS_NAME0$.upChuck()] Decl annos: [] Param annos (0) : [] Modifiers: 17 @@ -84,7 +84,7 @@ Got expected exception Invoke public abstract void InterfaceW1.bothThrowBase() throws BaseException,SubException,SubSubException (no args) Got expected exception -Proxy methods: [public final boolean $Proxy3.equals(java.lang.Object), public final java.lang.Object $Proxy3.foo(), public final java.lang.String $Proxy3.foo(), public final int $Proxy3.hashCode(), public final java.lang.String $Proxy3.toString()] +Proxy methods: [public final boolean $PROXY_CLASS_NAME1$.equals(java.lang.Object), public final java.lang.Object $PROXY_CLASS_NAME1$.foo(), public final java.lang.String $PROXY_CLASS_NAME1$.foo(), public final int $PROXY_CLASS_NAME1$.hashCode(), public final java.lang.String $PROXY_CLASS_NAME1$.toString()] Invocation of public abstract java.lang.String NarrowingTest$I2.foo() Invoking foo using I2 type: hello Invocation of public abstract java.lang.Object NarrowingTest$I1.foo() diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java index 15732978aa..445a6cc467 100644 --- a/test/044-proxy/src/BasicTest.java +++ b/test/044-proxy/src/BasicTest.java @@ -84,7 +84,8 @@ public class BasicTest { }); System.out.println("Proxy interfaces: " + Arrays.deepToString(proxy.getClass().getInterfaces())); - System.out.println("Proxy methods: " + Arrays.deepToString(methods)); + System.out.println("Proxy methods: " + + Main.replaceProxyClassNamesForOutput(Arrays.deepToString(methods))); Method meth = methods[methods.length -1]; System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations())); Annotation[][] paramAnnos = meth.getParameterAnnotations(); @@ -100,6 +101,7 @@ public class BasicTest { /* create the proxy class */ Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(), new Class[] { Quads.class, Colors.class, Trace.class }); + Main.registerProxyClassName(proxyClass.getCanonicalName()); /* create a proxy object, passing the handler object in */ Object proxy = null; @@ -262,7 +264,8 @@ class MyInvocationHandler implements InvocationHandler { for (int i = 0; i < stackTrace.length; i++) { StackTraceElement ste = stackTrace[i]; if (ste.getMethodName().equals("getTrace")) { - System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " + + String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); + System.out.println(outputClassName + "." + ste.getMethodName() + " " + ste.getFileName() + ":" + ste.getLineNumber()); } } @@ -276,7 +279,8 @@ class MyInvocationHandler implements InvocationHandler { for (int i = 0; i < stackTrace.length; i++) { StackTraceElement ste = stackTrace[i]; if (ste.getMethodName().equals("getTrace")) { - System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " + + String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); + System.out.println(outputClassName + "." + ste.getMethodName() + " " + ste.getFileName() + ":" + ste.getLineNumber()); } } diff --git a/test/044-proxy/src/Main.java b/test/044-proxy/src/Main.java index 05e8e5b512..1f23b95cf0 100644 --- a/test/044-proxy/src/Main.java +++ b/test/044-proxy/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import java.util.HashMap; + /** * Test java.lang.reflect.Proxy */ @@ -30,4 +32,24 @@ public class Main { FloatSelect.main(null); NativeProxy.main(args); } + + // The following code maps from the actual proxy class names (eg $Proxy2) to their test output + // names (eg $PROXY_CLASS_NAME1$). This is to avoid the flaky test failures due to potentially + // undeterministic proxy class naming. + + public static void registerProxyClassName(String proxyClassName) { + proxyClassNameMap.put(proxyClassName, + "$PROXY_CLASS_NAME" + (uniqueTestProxyClassNum++) + "$"); + } + + public static String replaceProxyClassNamesForOutput(String str) { + for (String key : proxyClassNameMap.keySet()) { + str = str.replace(key, proxyClassNameMap.get(key)); + } + return str; + } + + private static final HashMap<String, String> proxyClassNameMap = new HashMap<String, String>(); + + private static int uniqueTestProxyClassNum = 0; } diff --git a/test/044-proxy/src/NarrowingTest.java b/test/044-proxy/src/NarrowingTest.java index 3b94b76279..5b80d7284f 100644 --- a/test/044-proxy/src/NarrowingTest.java +++ b/test/044-proxy/src/NarrowingTest.java @@ -45,9 +45,11 @@ class NarrowingTest { } } }); + Main.registerProxyClassName(proxy.getClass().getCanonicalName()); Method[] methods = proxy.getClass().getDeclaredMethods(); - System.out.println("Proxy methods: " + Arrays.deepToString(methods)); + System.out.println("Proxy methods: " + + Main.replaceProxyClassNamesForOutput(Arrays.deepToString(methods))); System.out.println("Invoking foo using I2 type: " + proxy.foo()); diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index c932761c3b..0b87a4f311 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -31,9 +31,9 @@ z (class java.lang.Character) 30 (class java.lang.Integer) 62 (class java.lang.Long) 14 (class java.lang.Short) -[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final int java.lang.String.count, private int java.lang.String.hashCode, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] -[public native char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), native void java.lang.String.getCharsNoCheck(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), native void java.lang.String.setCharAt(int,char), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public native [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private native java.lang.String java.lang.String.fastSubstring(int,int), private char java.lang.String.foldCase(char), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] +[java.lang.String(int,int,char[]), public java.lang.String(), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder)] +[private final int java.lang.String.count, private int java.lang.String.hashCode, private static final char java.lang.String.REPLACEMENT_CHAR, private static final char[] java.lang.String.ASCII, private static final long java.lang.String.serialVersionUID, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER] +[native void java.lang.String.getCharsNoCheck(int,int,char[],int), native void java.lang.String.setCharAt(int,char), private char java.lang.String.foldCase(char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), private native int java.lang.String.fastIndexOf(int,int), private native java.lang.String java.lang.String.fastSubstring(int,int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public native [C java.lang.String.toCharArray(), public native char java.lang.String.charAt(int), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] 0 diff --git a/test/100-reflect2/src/Main.java b/test/100-reflect2/src/Main.java index bf3a574c99..124585225f 100644 --- a/test/100-reflect2/src/Main.java +++ b/test/100-reflect2/src/Main.java @@ -157,10 +157,28 @@ class Main { System.out.println(o + " (" + (o != null ? o.getClass() : "null") + ")"); } + /** + * Sorts the input array using the comparator and returns the sorted array. + */ + private static Object[] sort(Object[] objects, Comparator<Object> comp) { + Arrays.sort(objects, comp); + return objects; + } + public static void testMethodReflection() throws Exception { - System.out.println(Arrays.toString(String.class.getDeclaredConstructors())); - System.out.println(Arrays.toString(String.class.getDeclaredFields())); - System.out.println(Arrays.toString(String.class.getDeclaredMethods())); + Comparator<Object> comp = new Comparator<Object>() { + public int compare(Object a, Object b) { + return a.toString().compareTo(b.toString()); + } + public boolean equals(Object b) { + return this == b; + } + }; + + // Sort the return values by their string values since the order is undefined by the spec. + System.out.println(Arrays.toString(sort(String.class.getDeclaredConstructors(), comp))); + System.out.println(Arrays.toString(sort(String.class.getDeclaredFields(), comp))); + System.out.println(Arrays.toString(sort(String.class.getDeclaredMethods(), comp))); System.out.println(Arrays.toString(Main.class.getInterfaces())); System.out.println(Arrays.toString(String.class.getInterfaces())); diff --git a/test/530-checker-loops/src/Main.java b/test/530-checker-loops/src/Main.java index 34d2f64bf4..3f6e48bbae 100644 --- a/test/530-checker-loops/src/Main.java +++ b/test/530-checker-loops/src/Main.java @@ -415,6 +415,135 @@ public class Main { return result; } + /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: Deoptimize + private static void linearTriangularOnTwoArrayLengths(int n) { + int[] a = new int[n]; + for (int i = 0; i < a.length; i++) { + int[] b = new int[i]; + for (int j = 0; j < b.length; j++) { + // Need to know j < b.length < a.length for static bce. + a[j] += 1; + // Need to know just j < b.length for static bce. + b[j] += 1; + } + verifyTriangular(a, b, i, n); + } + } + + /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: Deoptimize + private static void linearTriangularOnOneArrayLength(int n) { + int[] a = new int[n]; + for (int i = 0; i < a.length; i++) { + int[] b = new int[i]; + for (int j = 0; j < i; j++) { + // Need to know j < i < a.length for static bce. + a[j] += 1; + // Need to know just j < i for static bce. + b[j] += 1; + } + verifyTriangular(a, b, i, n); + } + } + + /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: Deoptimize + private static void linearTriangularOnParameter(int n) { + int[] a = new int[n]; + for (int i = 0; i < n; i++) { + int[] b = new int[i]; + for (int j = 0; j < i; j++) { + // Need to know j < i < n for static bce. + a[j] += 1; + // Need to know just j < i for static bce. + b[j] += 1; + } + verifyTriangular(a, b, i, n); + } + } + + // Verifier for triangular methods. + private static void verifyTriangular(int[] a, int[] b, int m, int n) { + expectEquals(n, a.length); + for (int i = 0, k = m; i < n; i++) { + expectEquals(a[i], k); + if (k > 0) k--; + } + expectEquals(m, b.length); + for (int i = 0; i < m; i++) { + expectEquals(b[i], 1); + } + } + + /// CHECK-START: void Main.bubble(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: If + /// CHECK-DAG: ArraySet + /// CHECK-DAG: ArraySet + /// CHECK-START: void Main.bubble(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-NOT: BoundsCheck + /// CHECK-DAG: ArrayGet + /// CHECK-DAG: If + /// CHECK-DAG: ArraySet + /// CHECK-DAG: ArraySet + /// CHECK-NOT: Deoptimize + private static void bubble(int[] a) { + for (int i = a.length; --i >= 0;) { + for (int j = 0; j < i; j++) { + if (a[j] > a[j+1]) { + int tmp = a[j]; + a[j] = a[j+1]; + a[j+1] = tmp; + } + } + } + } + /// CHECK-START: int Main.periodicIdiom(int) BCE (before) /// CHECK-DAG: BoundsCheck /// CHECK-START: int Main.periodicIdiom(int) BCE (after) @@ -1012,6 +1141,16 @@ public class Main { expectEquals(55, linearDoWhileDown()); expectEquals(55, linearShort()); expectEquals(55, invariantFromPreLoop(x, 1)); + linearTriangularOnTwoArrayLengths(10); + linearTriangularOnOneArrayLength(10); + linearTriangularOnParameter(10); + + // Sorting. + int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 }; + bubble(sort); + for (int i = 0; i < 10; i++) { + expectEquals(sort[i], x[i]); + } // Periodic adds (1, 3), one at the time. expectEquals(0, periodicIdiom(-1)); diff --git a/test/555-UnsafeGetLong-regression/expected.txt b/test/555-UnsafeGetLong-regression/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/555-UnsafeGetLong-regression/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/555-UnsafeGetLong-regression/info.txt b/test/555-UnsafeGetLong-regression/info.txt new file mode 100644 index 0000000000..0e16ed7726 --- /dev/null +++ b/test/555-UnsafeGetLong-regression/info.txt @@ -0,0 +1,2 @@ +Regression test for sun.misc.Unsafe.getLong's intrinsic's locations +not handled properly. diff --git a/test/555-UnsafeGetLong-regression/src/Main.java b/test/555-UnsafeGetLong-regression/src/Main.java new file mode 100644 index 0000000000..1adafae9a7 --- /dev/null +++ b/test/555-UnsafeGetLong-regression/src/Main.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class Main { + private static void assertLongEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static Unsafe getUnsafe() throws Exception { + Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (Unsafe) f.get(null); + } + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + Unsafe unsafe = getUnsafe(); + + testUnsafeGetLong(unsafe); + } + + public static void testUnsafeGetLong(Unsafe unsafe) throws Exception { + TestClass test = new TestClass(); + Field longField = TestClass.class.getDeclaredField("longVar"); + long lvar = unsafe.objectFieldOffset(longField); + lvar = unsafe.getLong(test, lvar); + assertLongEquals(1122334455667788L, lvar); + } + + private static class TestClass { + public long longVar = 1122334455667788L; + } +} diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt index 362ae2536f..adc4d03a7a 100644 --- a/tools/ahat/README.txt +++ b/tools/ahat/README.txt @@ -19,7 +19,6 @@ TODO: * Show site context and heap and class filter in "Objects" view? * Have a menu at the top of an object view with links to the sections? * Include ahat version and hprof file in the menu at the top of the page? - * Show root types. * Heaped Table - Make sortable by clicking on headers. * For HeapTable with single heap shown, the heap name isn't centered? @@ -77,6 +76,7 @@ Things to move to perflib: * Extracting bitmap data from bitmap instances. * Adding up allocations by stack frame. * Computing, for each instance, the other instances it dominates. + * Instance.isRoot and Instance.getRootTypes. Release History: 0.2 Oct 20, 2015 diff --git a/tools/ahat/src/AhatSnapshot.java b/tools/ahat/src/AhatSnapshot.java index 0bf064eb24..fc7911b71b 100644 --- a/tools/ahat/src/AhatSnapshot.java +++ b/tools/ahat/src/AhatSnapshot.java @@ -19,6 +19,8 @@ package com.android.ahat; import com.android.tools.perflib.heap.ClassObj; import com.android.tools.perflib.heap.Heap; import com.android.tools.perflib.heap.Instance; +import com.android.tools.perflib.heap.RootObj; +import com.android.tools.perflib.heap.RootType; import com.android.tools.perflib.heap.Snapshot; import com.android.tools.perflib.heap.StackFrame; import com.android.tools.perflib.heap.StackTrace; @@ -29,8 +31,10 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; @@ -48,6 +52,11 @@ class AhatSnapshot { // Collection of objects whose immediate dominator is the SENTINEL_ROOT. private List<Instance> mRooted; + // Map from roots to their types. + // Instances are only included if they are roots, and the collection of root + // types is guaranteed to be non-empty. + private Map<Instance, Collection<RootType>> mRoots; + private Site mRootSite; private Map<Heap, Long> mHeapSizes; @@ -113,6 +122,18 @@ class AhatSnapshot { } mHeapSizes.put(heap, total); } + + // Record the roots and their types. + mRoots = new HashMap<Instance, Collection<RootType>>(); + for (RootObj root : snapshot.getGCRoots()) { + Instance inst = root.getReferredInstance(); + Collection<RootType> types = mRoots.get(inst); + if (types == null) { + types = new HashSet<RootType>(); + mRoots.put(inst, types); + } + types.add(root.getRootType()); + } } // Note: This method is exposed for testing purposes. @@ -140,6 +161,21 @@ class AhatSnapshot { return mRooted; } + /** + * Returns true if the given instance is a root. + */ + public boolean isRoot(Instance inst) { + return mRoots.containsKey(inst); + } + + /** + * Returns the list of root types for the given instance, or null if the + * instance is not a root. + */ + public Collection<RootType> getRootTypes(Instance inst) { + return mRoots.get(inst); + } + public List<Heap> getHeaps() { return mHeaps; } diff --git a/tools/ahat/src/DominatedList.java b/tools/ahat/src/DominatedList.java index 34a5665b3e..7a673f556e 100644 --- a/tools/ahat/src/DominatedList.java +++ b/tools/ahat/src/DominatedList.java @@ -71,7 +71,7 @@ class DominatedList { } public DocString render(Instance element) { - return Value.render(element); + return Value.render(mSnapshot, element); } }; return Collections.singletonList(value); diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java index 1305070b0f..06023dab7f 100644 --- a/tools/ahat/src/ObjectHandler.java +++ b/tools/ahat/src/ObjectHandler.java @@ -23,9 +23,11 @@ import com.android.tools.perflib.heap.Field; import com.android.tools.perflib.heap.Heap; import com.android.tools.perflib.heap.Instance; import com.android.tools.perflib.heap.RootObj; +import com.android.tools.perflib.heap.RootType; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -57,7 +59,7 @@ class ObjectHandler implements AhatHandler { } doc.title("Object %08x", inst.getUniqueId()); - doc.big(Value.render(inst)); + doc.big(Value.render(mSnapshot, inst)); printAllocationSite(doc, query, inst); printDominatorPath(doc, query, inst); @@ -65,27 +67,41 @@ class ObjectHandler implements AhatHandler { doc.section("Object Info"); ClassObj cls = inst.getClassObj(); doc.descriptions(); - doc.description(DocString.text("Class"), Value.render(cls)); + doc.description(DocString.text("Class"), Value.render(mSnapshot, cls)); doc.description(DocString.text("Size"), DocString.format("%d", inst.getSize())); doc.description( DocString.text("Retained Size"), DocString.format("%d", inst.getTotalRetainedSize())); doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName())); + + Collection<RootType> rootTypes = mSnapshot.getRootTypes(inst); + if (rootTypes != null) { + DocString types = new DocString(); + String comma = ""; + for (RootType type : rootTypes) { + types.append(comma); + types.append(type.getName()); + comma = ", "; + } + doc.description(DocString.text("Root Types"), types); + } + doc.end(); printBitmap(doc, inst); if (inst instanceof ClassInstance) { - printClassInstanceFields(doc, query, (ClassInstance)inst); + printClassInstanceFields(doc, query, mSnapshot, (ClassInstance)inst); } else if (inst instanceof ArrayInstance) { - printArrayElements(doc, query, (ArrayInstance)inst); + printArrayElements(doc, query, mSnapshot, (ArrayInstance)inst); } else if (inst instanceof ClassObj) { - printClassInfo(doc, query, (ClassObj)inst); + printClassInfo(doc, query, mSnapshot, (ClassObj)inst); } - printReferences(doc, query, inst); + printReferences(doc, query, mSnapshot, inst); printDominatedObjects(doc, query, inst); } - private static void printClassInstanceFields(Doc doc, Query query, ClassInstance inst) { + private static void printClassInstanceFields( + Doc doc, Query query, AhatSnapshot snapshot, ClassInstance inst) { doc.section("Fields"); doc.table(new Column("Type"), new Column("Name"), new Column("Value")); SubsetSelector<ClassInstance.FieldValue> selector @@ -94,31 +110,35 @@ class ObjectHandler implements AhatHandler { doc.row( DocString.text(field.getField().getType().toString()), DocString.text(field.getField().getName()), - Value.render(field.getValue())); + Value.render(snapshot, field.getValue())); } doc.end(); selector.render(doc); } - private static void printArrayElements(Doc doc, Query query, ArrayInstance array) { + private static void printArrayElements( + Doc doc, Query query, AhatSnapshot snapshot, ArrayInstance array) { doc.section("Array Elements"); doc.table(new Column("Index", Column.Align.RIGHT), new Column("Value")); List<Object> elements = Arrays.asList(array.getValues()); SubsetSelector<Object> selector = new SubsetSelector(query, ARRAY_ELEMENTS_ID, elements); int i = 0; for (Object elem : selector.selected()) { - doc.row(DocString.format("%d", i), Value.render(elem)); + doc.row(DocString.format("%d", i), Value.render(snapshot, elem)); i++; } doc.end(); selector.render(doc); } - private static void printClassInfo(Doc doc, Query query, ClassObj clsobj) { + private static void printClassInfo( + Doc doc, Query query, AhatSnapshot snapshot, ClassObj clsobj) { doc.section("Class Info"); doc.descriptions(); - doc.description(DocString.text("Super Class"), Value.render(clsobj.getSuperClassObj())); - doc.description(DocString.text("Class Loader"), Value.render(clsobj.getClassLoader())); + doc.description(DocString.text("Super Class"), + Value.render(snapshot, clsobj.getSuperClassObj())); + doc.description(DocString.text("Class Loader"), + Value.render(snapshot, clsobj.getClassLoader())); doc.end(); doc.section("Static Fields"); @@ -131,13 +151,14 @@ class ObjectHandler implements AhatHandler { doc.row( DocString.text(field.getKey().getType().toString()), DocString.text(field.getKey().getName()), - Value.render(field.getValue())); + Value.render(snapshot, field.getValue())); } doc.end(); selector.render(doc); } - private static void printReferences(Doc doc, Query query, Instance inst) { + private static void printReferences( + Doc doc, Query query, AhatSnapshot snapshot, Instance inst) { doc.section("Objects with References to this Object"); if (inst.getHardReferences().isEmpty()) { doc.println(DocString.text("(none)")); @@ -146,7 +167,7 @@ class ObjectHandler implements AhatHandler { List<Instance> references = inst.getHardReferences(); SubsetSelector<Instance> selector = new SubsetSelector(query, HARD_REFS_ID, references); for (Instance ref : selector.selected()) { - doc.row(Value.render(ref)); + doc.row(Value.render(snapshot, ref)); } doc.end(); selector.render(doc); @@ -158,7 +179,7 @@ class ObjectHandler implements AhatHandler { List<Instance> references = inst.getSoftReferences(); SubsetSelector<Instance> selector = new SubsetSelector(query, SOFT_REFS_ID, references); for (Instance ref : selector.selected()) { - doc.row(Value.render(ref)); + doc.row(Value.render(snapshot, ref)); } doc.end(); selector.render(doc); @@ -217,7 +238,7 @@ class ObjectHandler implements AhatHandler { if (element == null) { return DocString.link(DocString.uri("rooted"), DocString.text("ROOT")); } else { - return DocString.text("→ ").append(Value.render(element)); + return DocString.text("→ ").append(Value.render(mSnapshot, element)); } } }; diff --git a/tools/ahat/src/ObjectsHandler.java b/tools/ahat/src/ObjectsHandler.java index 8ad3f481da..4cfb0a55cf 100644 --- a/tools/ahat/src/ObjectsHandler.java +++ b/tools/ahat/src/ObjectsHandler.java @@ -60,7 +60,7 @@ class ObjectsHandler implements AhatHandler { doc.row( DocString.format("%,d", inst.getSize()), DocString.text(inst.getHeap().getName()), - Value.render(inst)); + Value.render(mSnapshot, inst)); } doc.end(); selector.render(doc); diff --git a/tools/ahat/src/SiteHandler.java b/tools/ahat/src/SiteHandler.java index 0425a5a825..839e220ca4 100644 --- a/tools/ahat/src/SiteHandler.java +++ b/tools/ahat/src/SiteHandler.java @@ -101,7 +101,7 @@ class SiteHandler implements AhatHandler { site.getStackId(), site.getStackDepth(), info.heap.getName(), className), DocString.format("%,14d", info.numInstances)), DocString.text(info.heap.getName()), - Value.render(info.classObj)); + Value.render(mSnapshot, info.classObj)); } doc.end(); selector.render(doc); diff --git a/tools/ahat/src/Value.java b/tools/ahat/src/Value.java index 7c969b3645..847692bd10 100644 --- a/tools/ahat/src/Value.java +++ b/tools/ahat/src/Value.java @@ -32,21 +32,29 @@ class Value { /** * Create a DocString representing a summary of the given instance. */ - private static DocString renderInstance(Instance inst) { - DocString link = new DocString(); + private static DocString renderInstance(AhatSnapshot snapshot, Instance inst) { + DocString formatted = new DocString(); if (inst == null) { - link.append("(null)"); - return link; + formatted.append("(null)"); + return formatted; + } + + // Annotate roots as roots. + if (snapshot.isRoot(inst)) { + formatted.append("(root) "); } + // Annotate classes as classes. + DocString link = new DocString(); if (inst instanceof ClassObj) { link.append("class "); } link.append(inst.toString()); + URI objTarget = DocString.formattedUri("object?id=%d", inst.getId()); - DocString formatted = DocString.link(objTarget, link); + formatted.appendLink(objTarget, link); // Annotate Strings with their values. String stringValue = InstanceUtils.asString(inst, kMaxChars); @@ -63,7 +71,7 @@ class Value { // It should not be possible for a referent to refer back to the // reference object, even indirectly, so there shouldn't be any issues // with infinite recursion here. - formatted.append(renderInstance(referent)); + formatted.append(renderInstance(snapshot, referent)); } // Annotate DexCache with its location. @@ -89,9 +97,9 @@ class Value { /** * Create a DocString summarizing the given value. */ - public static DocString render(Object val) { + public static DocString render(AhatSnapshot snapshot, Object val) { if (val instanceof Instance) { - return renderInstance((Instance)val); + return renderInstance(snapshot, (Instance)val); } else { return DocString.format("%s", val); } |