diff options
55 files changed, 1306 insertions, 279 deletions
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 7a93613481..58876200ca 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -283,11 +283,13 @@ class LinkerPatch { static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators"); }; union { - uint32_t cmp2_; // Used for relational operators. + // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`. + // This allows a hashing function to treat an array of linker patches as raw memory. + size_t cmp2_; // Used for relational operators. // Literal offset of the insn loading PC (same as literal_offset if it's the same insn, // may be different if the PC-relative addressing needs multiple insns). uint32_t pc_insn_offset_; - static_assert(sizeof(pc_insn_offset_) == sizeof(cmp2_), "needed by relational operators"); + static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators"); }; friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 6bc2a13299..f078bf6507 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2306,9 +2306,9 @@ class SetVerifiedClassVisitor : public CompilationVisitor { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self()); // Mark methods as pre-verified. If we don't do this, the interpreter will run with // access checks. - klass->SetPreverifiedFlagOnAllMethods( + klass->SetSkipAccessChecksFlagOnAllMethods( GetInstructionSetPointerSize(manager_->GetCompiler()->GetInstructionSet())); - klass->SetPreverified(); + klass->SetVerificationAttempted(); } // Record the final class status if necessary. ClassReference ref(manager_->GetDexFile(), class_def_index); diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 3d24d19919..b673eeb3b6 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -110,18 +110,27 @@ class ElfBuilder FINAL { CHECK(sections.empty() || sections.back()->finished_); // The first ELF section index is 1. Index 0 is reserved for NULL. section_index_ = sections.size() + 1; - // Push this section on the list of written sections. - sections.push_back(this); + // Page-align if we switch between allocated and non-allocated sections, + // or if we change the type of allocation (e.g. executable vs non-executable). + if (!sections.empty()) { + if (header_.sh_flags != sections.back()->header_.sh_flags) { + header_.sh_addralign = kPageSize; + } + } // Align file position. if (header_.sh_type != SHT_NOBITS) { - header_.sh_offset = RoundUp(owner_->stream_.Seek(0, kSeekCurrent), header_.sh_addralign); - owner_->stream_.Seek(header_.sh_offset, kSeekSet); + header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign); + } else { + header_.sh_offset = 0; } // Align virtual memory address. if ((header_.sh_flags & SHF_ALLOC) != 0) { - header_.sh_addr = RoundUp(owner_->virtual_address_, header_.sh_addralign); - owner_->virtual_address_ = header_.sh_addr; + header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign); + } else { + header_.sh_addr = 0; } + // Push this section on the list of written sections. + sections.push_back(this); } // Finish writing of this section. @@ -170,8 +179,8 @@ class ElfBuilder FINAL { // and it will be zero-initialized when the ELF file is loaded in the running program. void WriteNoBitsSection(Elf_Word size) { DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u); - Start(); header_.sh_type = SHT_NOBITS; + Start(); header_.sh_size = size; End(); } @@ -293,12 +302,13 @@ class ElfBuilder FINAL { 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), + strtab_(this, ".strtab", 0, 1), 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), + started_(false), virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; @@ -351,22 +361,25 @@ class ElfBuilder FINAL { other_sections_.push_back(std::move(s)); } - // Set where the next section will be allocated in the virtual address space. - void SetVirtualAddress(Elf_Addr address) { - DCHECK_GE(address, virtual_address_); - virtual_address_ = address; - } - - void Start() { - // Reserve space for ELF header and program headers. - // 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; + // Reserve space for ELF header and program headers. + // We do not know the number of headers until later, so + // it is easiest to just reserve a fixed amount of space. + // Program headers are required for loading by the linker. + // It is possible to omit them for ELF files used for debugging. + void Start(bool write_program_headers = true) { + int size = sizeof(Elf_Ehdr); + if (write_program_headers) { + size += sizeof(Elf_Phdr) * kMaxProgramHeaders; + } stream_.Seek(size, kSeekSet); + started_ = true; virtual_address_ += size; + write_program_headers_ = write_program_headers; } void End() { + DCHECK(started_); + // Write section names and finish the section headers. shstrtab_.Start(); shstrtab_.Write(""); @@ -386,8 +399,7 @@ class ElfBuilder FINAL { shdrs.push_back(section->header_); } Elf_Off section_headers_offset; - section_headers_offset = RoundUp(stream_.Seek(0, kSeekCurrent), sizeof(Elf_Off)); - stream_.Seek(section_headers_offset, kSeekSet); + section_headers_offset = AlignFileOffset(sizeof(Elf_Off)); stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0])); // Flush everything else before writing the program headers. This should prevent @@ -395,14 +407,21 @@ class ElfBuilder FINAL { // and partially written data if we suddenly lose power, for example. stream_.Flush(); - // Write the initial file headers. - std::vector<Elf_Phdr> phdrs = MakeProgramHeaders(); + // The main ELF header. Elf_Ehdr elf_header = MakeElfHeader(isa_); - elf_header.e_phoff = sizeof(Elf_Ehdr); elf_header.e_shoff = section_headers_offset; - elf_header.e_phnum = phdrs.size(); elf_header.e_shnum = shdrs.size(); elf_header.e_shstrndx = shstrtab_.GetSectionIndex(); + + // Program headers (i.e. mmap instructions). + std::vector<Elf_Phdr> phdrs; + if (write_program_headers_) { + phdrs = MakeProgramHeaders(); + CHECK_LE(phdrs.size(), kMaxProgramHeaders); + elf_header.e_phoff = sizeof(Elf_Ehdr); + elf_header.e_phnum = phdrs.size(); + } + stream_.Seek(0, kSeekSet); stream_.WriteFully(&elf_header, sizeof(elf_header)); stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0])); @@ -492,6 +511,14 @@ class ElfBuilder FINAL { return &stream_; } + off_t AlignFileOffset(size_t alignment) { + return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet); + } + + Elf_Addr AlignVirtualAddress(size_t alignment) { + return virtual_address_ = RoundUp(virtual_address_, alignment); + } + private: static Elf_Ehdr MakeElfHeader(InstructionSet isa) { Elf_Ehdr elf_header = Elf_Ehdr(); @@ -666,9 +693,13 @@ class ElfBuilder FINAL { // List of used section in the order in which they were written. std::vector<Section*> sections_; + bool started_; + // Used for allocation of virtual address space. Elf_Addr virtual_address_; + size_t write_program_headers_; + DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index c5a0fd50bd..5dbf7360f8 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -52,6 +52,9 @@ class ElfWriter { virtual ~ElfWriter() {} virtual void Start() = 0; + virtual void PrepareDebugInfo(size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0; virtual OutputStream* StartRoData() = 0; virtual void EndRoData(OutputStream* rodata) = 0; virtual OutputStream* StartText() = 0; diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index d1f50073a0..e2481b061c 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -1148,13 +1148,19 @@ class DebugInfoWriter { writer.Write(types); } - void End() { + void End(bool write_oat_patches) { builder_->GetDebugInfo()->End(); - builder_->WritePatches(".debug_info.oat_patches", - ArrayRef<const uintptr_t>(debug_info_patches_)); + if (write_oat_patches) { + builder_->WritePatches(".debug_info.oat_patches", + ArrayRef<const uintptr_t>(debug_info_patches_)); + } builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_); - builder_->WriteSection(".debug_loc", &debug_loc_); - builder_->WriteSection(".debug_ranges", &debug_ranges_); + if (!debug_loc_.empty()) { + builder_->WriteSection(".debug_loc", &debug_loc_); + } + if (!debug_ranges_.empty()) { + builder_->WriteSection(".debug_ranges", &debug_ranges_); + } } private: @@ -1357,10 +1363,12 @@ class DebugLineWriter { return buffer.size(); } - void End() { + void End(bool write_oat_patches) { builder_->GetDebugLine()->End(); - builder_->WritePatches(".debug_line.oat_patches", - ArrayRef<const uintptr_t>(debug_line_patches)); + if (write_oat_patches) { + builder_->WritePatches(".debug_line.oat_patches", + ArrayRef<const uintptr_t>(debug_line_patches)); + } } private: @@ -1370,7 +1378,8 @@ class DebugLineWriter { template<typename ElfTypes> static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos) { + const ArrayRef<const MethodDebugInfo>& method_infos, + bool write_oat_patches) { // Group the methods into compilation units based on source file. std::vector<CompilationUnit> compilation_units; const char* last_source_file = nullptr; @@ -1394,7 +1403,7 @@ static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, for (auto& compilation_unit : compilation_units) { line_writer.WriteCompilationUnit(compilation_unit); } - line_writer.End(); + line_writer.End(write_oat_patches); } // Write .debug_info section. @@ -1404,7 +1413,7 @@ static void WriteDebugSections(ElfBuilder<ElfTypes>* builder, for (const auto& compilation_unit : compilation_units) { info_writer.WriteCompilationUnit(compilation_unit); } - info_writer.End(); + info_writer.End(write_oat_patches); } } @@ -1484,13 +1493,14 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, template <typename ElfTypes> void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format) { + CFIFormat cfi_format, + bool write_oat_patches) { // Add methods to .symtab. WriteDebugSymbols(builder, method_infos, true /* with_signature */); // Generate CFI (stack unwinding information). - WriteCFISection(builder, method_infos, cfi_format, true /* write_oat_patches */); + WriteCFISection(builder, method_infos, cfi_format, write_oat_patches); // Write DWARF .debug_* sections. - WriteDebugSections(builder, method_infos); + WriteDebugSections(builder, method_infos, write_oat_patches); } static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) { @@ -1539,20 +1549,20 @@ static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* ds } template <typename ElfTypes> -void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder, - const ArrayRef<const MethodDebugInfo>& method_infos) { - const InstructionSet isa = parent_builder->GetIsa(); +std::vector<uint8_t> MakeMiniDebugInfoInternal( + InstructionSet isa, + size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const MethodDebugInfo>& method_infos) { std::vector<uint8_t> buffer; buffer.reserve(KB); VectorOutputStream out("Mini-debug-info ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); builder->Start(); - // Write .rodata and .text as NOBITS sections. - // This allows tools to detect virtual address relocation of the parent ELF file. - builder->SetVirtualAddress(parent_builder->GetRoData()->GetAddress()); - builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize()); - builder->SetVirtualAddress(parent_builder->GetText()->GetAddress()); - builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize()); + // Mirror .rodata and .text as NOBITS sections. + // It is needed to detected relocations after compression. + builder->GetRoData()->WriteNoBitsSection(rodata_section_size); + builder->GetText()->WriteNoBitsSection(text_section_size); WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */); WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT, false /* write_oat_paches */); builder->End(); @@ -1560,7 +1570,19 @@ void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder, std::vector<uint8_t> compressed_buffer; compressed_buffer.reserve(buffer.size() / 4); XzCompress(&buffer, &compressed_buffer); - parent_builder->WriteSection(".gnu_debugdata", &compressed_buffer); + return compressed_buffer; +} + +std::vector<uint8_t> MakeMiniDebugInfo( + InstructionSet isa, + size_t rodata_size, + size_t text_size, + const ArrayRef<const MethodDebugInfo>& method_infos) { + if (Is64BitInstructionSet(isa)) { + return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos); + } else { + return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos); + } } template <typename ElfTypes> @@ -1571,10 +1593,12 @@ static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal( buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); - builder->Start(); + // No program headers since the ELF file is not linked and has no allocated sections. + builder->Start(false /* write_program_headers */); WriteDebugInfo(builder.get(), ArrayRef<const MethodDebugInfo>(&method_info, 1), - DW_DEBUG_FRAME_FORMAT); + DW_DEBUG_FRAME_FORMAT, + false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); // Make a copy of the buffer. We want to shrink it anyway. @@ -1601,12 +1625,12 @@ static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal( buffer.reserve(KB); VectorOutputStream out("Debug ELF file", &buffer); std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out)); - builder->Start(); - + // No program headers since the ELF file is not linked and has no allocated sections. + builder->Start(false /* write_program_headers */); DebugInfoWriter<ElfTypes> info_writer(builder.get()); info_writer.Start(); info_writer.WriteTypes(types); - info_writer.End(); + info_writer.End(false /* write_oat_patches */); builder->End(); CHECK(builder->Good()); @@ -1630,17 +1654,13 @@ ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa, template void WriteDebugInfo<ElfTypes32>( ElfBuilder<ElfTypes32>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); + CFIFormat cfi_format, + bool write_oat_patches); template void WriteDebugInfo<ElfTypes64>( ElfBuilder<ElfTypes64>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); -template void WriteMiniDebugInfo<ElfTypes32>( - ElfBuilder<ElfTypes32>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos); -template void WriteMiniDebugInfo<ElfTypes64>( - ElfBuilder<ElfTypes64>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos); + CFIFormat cfi_format, + bool write_oat_patches); } // namespace dwarf } // namespace art diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h index e19da088da..e289197971 100644 --- a/compiler/elf_writer_debug.h +++ b/compiler/elf_writer_debug.h @@ -33,11 +33,13 @@ struct MethodDebugInfo; template <typename ElfTypes> void WriteDebugInfo(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos, - CFIFormat cfi_format); + CFIFormat cfi_format, + bool write_oat_patches); -template <typename ElfTypes> -void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder, - const ArrayRef<const MethodDebugInfo>& method_infos); +std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa, + size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const MethodDebugInfo>& method_infos); ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info); diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 6bf080a083..759a6d633a 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -33,6 +33,8 @@ #include "leb128.h" #include "linker/buffered_output_stream.h" #include "linker/file_output_stream.h" +#include "thread-inl.h" +#include "thread_pool.h" #include "utils.h" namespace art { @@ -46,6 +48,37 @@ namespace art { // Let's use .debug_frame because it is easier to strip or compress. constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT; +class DebugInfoTask : public Task { + public: + DebugInfoTask(InstructionSet isa, + size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) + : isa_(isa), + rodata_section_size_(rodata_section_size), + text_section_size_(text_section_size), + method_infos_(method_infos) { + } + + void Run(Thread*) { + result_ = dwarf::MakeMiniDebugInfo(isa_, + rodata_section_size_, + text_section_size_, + method_infos_); + } + + std::vector<uint8_t>* GetResult() { + return &result_; + } + + private: + InstructionSet isa_; + size_t rodata_section_size_; + size_t text_section_size_; + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos_; + std::vector<uint8_t> result_; +}; + template <typename ElfTypes> class ElfWriterQuick FINAL : public ElfWriter { public: @@ -55,6 +88,9 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfWriterQuick(); void Start() OVERRIDE; + void PrepareDebugInfo(size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE; OutputStream* StartRoData() OVERRIDE; void EndRoData(OutputStream* rodata) OVERRIDE; OutputStream* StartText() OVERRIDE; @@ -75,6 +111,8 @@ class ElfWriterQuick FINAL : public ElfWriter { File* const elf_file_; std::unique_ptr<BufferedOutputStream> output_stream_; std::unique_ptr<ElfBuilder<ElfTypes>> builder_; + std::unique_ptr<DebugInfoTask> debug_info_task_; + std::unique_ptr<ThreadPool> debug_info_thread_pool_; DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); }; @@ -147,15 +185,38 @@ void ElfWriterQuick<ElfTypes>::WriteDynamicSection() { } template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::PrepareDebugInfo( + size_t rodata_section_size, + size_t text_section_size, + const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { + if (compiler_options_->GetGenerateMiniDebugInfo()) { + // Prepare the mini-debug-info in background while we do other I/O. + Thread* self = Thread::Current(); + debug_info_task_ = std::unique_ptr<DebugInfoTask>( + new DebugInfoTask(builder_->GetIsa(), + rodata_section_size, + text_section_size, + method_infos)); + debug_info_thread_pool_ = std::unique_ptr<ThreadPool>( + new ThreadPool("Mini-debug-info writer", 1)); + debug_info_thread_pool_->AddTask(self, debug_info_task_.get()); + debug_info_thread_pool_->StartWorkers(self); + } +} + +template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::WriteDebugInfo( const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) { if (compiler_options_->GetGenerateDebugInfo()) { // Generate all the debug information we can. - dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat); + dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */); } if (compiler_options_->GetGenerateMiniDebugInfo()) { - // Generate only some information and compress it. - dwarf::WriteMiniDebugInfo(builder_.get(), method_infos); + // Wait for the mini-debug-info generation to finish and write it to disk. + Thread* self = Thread::Current(); + DCHECK(debug_info_thread_pool_ != nullptr); + debug_info_thread_pool_->Wait(self, true, false); + builder_->WriteSection(".gnu_debugdata", debug_info_task_->GetResult()); } } diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index eee6116098..c307522f2b 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -1227,27 +1227,28 @@ class BCEVisitor : public HGraphVisitor { InductionVarRange::Value v1; InductionVarRange::Value v2; bool needs_finite_test = false; - induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test); - 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; + if (induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test)) { + 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)); + } 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 ae15fcf381..9566c29adf 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -93,7 +93,7 @@ InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis) DCHECK(induction_analysis != nullptr); } -void InductionVarRange::GetInductionRange(HInstruction* context, +bool InductionVarRange::GetInductionRange(HInstruction* context, HInstruction* instruction, /*out*/Value* min_val, /*out*/Value* max_val, @@ -111,12 +111,9 @@ void InductionVarRange::GetInductionRange(HInstruction* context, *min_val = GetVal(info, trip, in_body, /* is_min */ true); *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false)); *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip); - } else { - // No loop to analyze. - *min_val = Value(); - *max_val = Value(); - *needs_finite_test = false; + return true; } + return false; // Nothing known } bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const { diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h index 974b8fba06..3cb7b4bfd5 100644 --- a/compiler/optimizing/induction_var_range.h +++ b/compiler/optimizing/induction_var_range.h @@ -60,13 +60,13 @@ class InductionVarRange { * Given a context denoted by the first instruction, returns a possibly conservative * lower and upper bound on the instruction's value in the output parameters min_val * and max_val, respectively. The need_finite_test flag denotes if an additional finite-test - * is needed to protect the range evaluation inside its loop. + * is needed to protect the range evaluation inside its loop. Returns false on failure. */ - void GetInductionRange(HInstruction* context, + bool GetInductionRange(HInstruction* context, HInstruction* instruction, - /*out*/Value* min_val, - /*out*/Value* max_val, - /*out*/bool* needs_finite_test); + /*out*/ Value* min_val, + /*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) const; @@ -79,8 +79,8 @@ class InductionVarRange { */ bool CanGenerateCode(HInstruction* context, HInstruction* instruction, - /*out*/bool* needs_finite_test, - /*out*/bool* needs_taken_test); + /*out*/ bool* needs_finite_test, + /*out*/ bool* needs_taken_test); /** * Generates the actual code in the HIR for the lower and upper bound expressions on the @@ -101,8 +101,8 @@ class InductionVarRange { HInstruction* instruction, HGraph* graph, HBasicBlock* block, - /*out*/HInstruction** lower, - /*out*/HInstruction** upper); + /*out*/ HInstruction** lower, + /*out*/ HInstruction** upper); /** * Generates explicit taken-test for the loop in the given context. Code is generated in @@ -113,7 +113,7 @@ class InductionVarRange { void GenerateTakenTest(HInstruction* context, HGraph* graph, HBasicBlock* block, - /*out*/HInstruction** taken_test); + /*out*/ HInstruction** taken_test); private: bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const; @@ -168,17 +168,17 @@ class InductionVarRange { HInstruction* instruction, HGraph* graph, HBasicBlock* block, - /*out*/HInstruction** lower, - /*out*/HInstruction** upper, - /*out*/HInstruction** taken_test, - /*out*/bool* needs_finite_test, - /*out*/bool* needs_taken_test) const; + /*out*/ HInstruction** lower, + /*out*/ HInstruction** upper, + /*out*/ HInstruction** taken_test, + /*out*/ bool* needs_finite_test, + /*out*/ bool* needs_taken_test) const; bool GenerateCode(HInductionVarAnalysis::InductionInfo* info, HInductionVarAnalysis::InductionInfo* trip, HGraph* graph, HBasicBlock* block, - /*out*/HInstruction** result, + /*out*/ HInstruction** result, bool in_body, bool is_min) const; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index c057eca434..3dda8501d2 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -858,7 +858,6 @@ void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env, // At the end of the loop pre-header, the corresponding value for instruction // is the first input of the phi. HInstruction* initial = instruction->AsPhi()->InputAt(0); - DCHECK(initial->GetBlock()->Dominates(loop_header)); SetRawEnvAt(i, initial); initial->AddEnvUseAt(this, i); } else { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index b3e3ba68a0..b1f71cee3d 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -126,6 +126,11 @@ static std::string StrippedCommandLine() { continue; } + // The image format is dropped. + if (StartsWith(original_argv[i], "--image-format=")) { + continue; + } + // This should leave any dex-file and oat-file options, describing what we compiled. // However, we prefer to drop this when we saw --zip-fd. @@ -1682,6 +1687,12 @@ class Dex2Oat FINAL { std::vector<const DexFile*>& dex_files = dex_files_per_oat_file_[i]; oat_writer->PrepareLayout(driver_.get(), image_writer_.get(), dex_files); + // We need to mirror the layout of the ELF file in the compressed debug-info. + // Therefore we need to propagate the sizes of at least those sections. + size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset(); + size_t text_size = oat_writer->GetSize() - rodata_size; + elf_writer->PrepareDebugInfo(rodata_size, text_size, oat_writer->GetMethodDebugInfo()); + OutputStream*& rodata = rodata_[i]; DCHECK(rodata != nullptr); if (!oat_writer->WriteRodata(rodata)) { diff --git a/runtime/art_method.h b/runtime/art_method.h index ce23c2a52b..078a978505 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -174,13 +174,13 @@ class ArtMethod FINAL { bool IsProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_); - bool IsPreverified() { - return (GetAccessFlags() & kAccPreverified) != 0; + bool SkipAccessChecks() { + return (GetAccessFlags() & kAccSkipAccessChecks) != 0; } - void SetPreverified() { - DCHECK(!IsPreverified()); - SetAccessFlags(GetAccessFlags() | kAccPreverified); + void SetSkipAccessChecks() { + DCHECK(!SkipAccessChecks()); + SetAccessFlags(GetAccessFlags() | kAccSkipAccessChecks); } // Returns true if this method could be overridden by a default method. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c80f91a7b8..88d49b2c25 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1669,6 +1669,22 @@ bool ClassLinker::AddImageSpace( forward_dex_cache_arrays); class_table->Visit(visitor); } + // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss. + // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and + // mark as PROT_NONE to catch any invalid accesses. + if (forward_dex_cache_arrays) { + const ImageSection& dex_cache_section = header.GetImageSection( + ImageHeader::kSectionDexCacheArrays); + uint8_t* section_begin = AlignUp(space->Begin() + dex_cache_section.Offset(), kPageSize); + uint8_t* section_end = AlignDown(space->Begin() + dex_cache_section.End(), kPageSize); + if (section_begin < section_end) { + madvise(section_begin, section_end - section_begin, MADV_DONTNEED); + mprotect(section_begin, section_end - section_begin, PROT_NONE); + VLOG(image) << "Released and protected dex cache array image section from " + << reinterpret_cast<const void*>(section_begin) << "-" + << reinterpret_cast<const void*>(section_end); + } + } } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; @@ -3625,7 +3641,7 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { // Don't attempt to re-verify if already sufficiently verified. if (klass->IsVerified()) { - EnsurePreverifiedMethods(klass); + EnsureSkipAccessChecksMethods(klass); return; } if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { @@ -3648,22 +3664,10 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self); } - // Skip verification if we are forcing a soft fail. - // This has to be before the normal verification enabled check, - // since technically verification is disabled in this mode. - if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) { - // Force verification to be a 'soft failure'. - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - // As this is a fake verified status, make sure the methods are _not_ marked preverified - // later. - klass->SetPreverified(); - return; - } - // Skip verification if disabled. if (!Runtime::Current()->IsVerificationEnabled()) { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - EnsurePreverifiedMethods(klass); + EnsureSkipAccessChecksMethods(klass); return; } @@ -3766,9 +3770,9 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self); } else { mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - // As this is a fake verified status, make sure the methods are _not_ marked preverified - // later. - klass->SetPreverified(); + // As this is a fake verified status, make sure the methods are _not_ marked + // kAccSkipAccessChecks later. + klass->SetVerificationAttempted(); } } } else { @@ -3781,19 +3785,26 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { } if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) { // Class is verified so we don't need to do any access check on its methods. - // Let the interpreter know it by setting the kAccPreverified flag onto each + // Let the interpreter know it by setting the kAccSkipAccessChecks flag onto each // method. // Note: we're going here during compilation and at runtime. When we set the - // kAccPreverified flag when compiling image classes, the flag is recorded + // kAccSkipAccessChecks flag when compiling image classes, the flag is recorded // in the image and is set when loading the image. - EnsurePreverifiedMethods(klass); + + if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) { + // Never skip access checks if the verification soft fail is forced. + // Mark the class as having a verification attempt to avoid re-running the verifier. + klass->SetVerificationAttempted(); + } else { + EnsureSkipAccessChecksMethods(klass); + } } } -void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) { - if (!klass->IsPreverified()) { - klass->SetPreverifiedFlagOnAllMethods(image_pointer_size_); - klass->SetPreverified(); +void ClassLinker::EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass) { + if (!klass->WasVerificationAttempted()) { + klass->SetSkipAccessChecksFlagOnAllMethods(image_pointer_size_); + klass->SetVerificationAttempted(); } } @@ -3824,7 +3835,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, } // We may be running with a preopted oat file but without image. In this case, - // we don't skip verification of preverified classes to ensure we initialize + // we don't skip verification of skip_access_checks classes to ensure we initialize // dex caches with all types resolved during verification. // We need to trust image classes, as these might be coming out of a pre-opted, quickened boot // image (that we just failed loading), and the verifier can't be run on quickened opcodes when @@ -3932,8 +3943,9 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& } DCHECK(klass->GetClass() != nullptr); klass->SetObjectSize(sizeof(mirror::Proxy)); - // Set the class access flags incl. preverified, so we do not try to set the flag on the methods. - klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified); + // Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on + // the methods. + klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted); klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader)); DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetName(soa.Decode<mirror::String*>(name)); @@ -4104,9 +4116,10 @@ ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) { // Create constructor for Proxy that must initialize the method. - CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 19u); + CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 18u); ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked( 2, image_pointer_size_); + DCHECK_EQ(std::string(proxy_constructor->GetName()), "<init>"); // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden // constructor method. GetClassRoot(kJavaLangReflectProxy)->GetDexCache()->SetResolvedMethod( @@ -4741,7 +4754,7 @@ bool ClassLinker::EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool bool can_init_parents) { DCHECK(c.Get() != nullptr); if (c->IsInitialized()) { - EnsurePreverifiedMethods(c); + EnsureSkipAccessChecksMethods(c); return true; } const bool success = InitializeClass(self, c, can_init_fields, can_init_parents); @@ -6436,11 +6449,11 @@ bool ClassLinker::LinkInterfaceMethods( for (ArtMethod* def_method : default_methods) { ArtMethod& new_method = *out; new_method.CopyFrom(def_method, image_pointer_size_); - // Clear the preverified flag if it is present. Since this class hasn't been verified yet it - // shouldn't have methods that are preverified. + // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been verified + // yet it shouldn't have methods that are skipping access checks. // TODO This is rather arbitrary. We should maybe support classes where only some of its - // methods are preverified. - new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccPreverified); + // methods are skip_access_checks. + new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccSkipAccessChecks); move_table.emplace(def_method, &new_method); ++out; } @@ -6448,11 +6461,11 @@ bool ClassLinker::LinkInterfaceMethods( ArtMethod& new_method = *out; new_method.CopyFrom(conf_method, image_pointer_size_); // This is a type of default method (there are default method impls, just a conflict) so mark - // this as a default, non-abstract method, since thats what it is. Also clear the preverified - // bit since this class hasn't been verified yet it shouldn't have methods that are - // preverified. + // this as a default, non-abstract method, since thats what it is. Also clear the + // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have + // methods that are skipping access checks. constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict; - constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccPreverified); + constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks); new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); DCHECK(new_method.IsDefaultConflicting()); // The actual method might or might not be marked abstract since we just copied it from a diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 9217c32fe7..71fcf296bd 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -964,9 +964,10 @@ class ClassLinker { void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out) SHARED_REQUIRES(Locks::mutator_lock_); - // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the - // class access flags to determine whether this has been done before. - void EnsurePreverifiedMethods(Handle<mirror::Class> c) + // Ensures that methods have the kAccSkipAccessChecks bit set. We use the + // kAccVerificationAttempted bit on the class access flags to determine whether this has been done + // before. + void EnsureSkipAccessChecksMethods(Handle<mirror::Class> c) SHARED_REQUIRES(Locks::mutator_lock_); mirror::Class* LookupClassFromBootImage(const char* descriptor) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 40dfda9316..3a0f3e5065 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -210,11 +210,10 @@ class ClassLinkerTest : public CommonRuntimeTest { klass->GetDescriptor(&temp2))); if (klass->IsInterface()) { EXPECT_TRUE(klass->IsAbstract()); - if (klass->NumDirectMethods() == 1) { - EXPECT_TRUE(klass->GetDirectMethod(0, sizeof(void*))->IsClassInitializer()); - EXPECT_TRUE(klass->GetDirectMethod(0, sizeof(void*))->IsDirect()); - } else { - EXPECT_EQ(0U, klass->NumDirectMethods()); + // Check that all direct methods are static (either <clinit> or a regular static method). + for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) { + EXPECT_TRUE(m.IsStatic()); + EXPECT_TRUE(m.IsDirect()); } } else { if (!klass->IsSynthetic()) { @@ -1126,14 +1125,14 @@ TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) { static void CheckMethod(ArtMethod* method, bool verified) SHARED_REQUIRES(Locks::mutator_lock_) { if (!method->IsNative() && !method->IsAbstract()) { - EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified) + EXPECT_EQ((method->GetAccessFlags() & kAccSkipAccessChecks) != 0U, verified) << PrettyMethod(method, true); } } -static void CheckPreverified(mirror::Class* c, bool preverified) +static void CheckVerificationAttempted(mirror::Class* c, bool preverified) SHARED_REQUIRES(Locks::mutator_lock_) { - EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified) + EXPECT_EQ((c->GetAccessFlags() & kAccVerificationAttempted) != 0U, preverified) << "Class " << PrettyClass(c) << " not as expected"; for (auto& m : c->GetMethods(sizeof(void*))) { CheckMethod(&m, preverified); @@ -1147,7 +1146,7 @@ TEST_F(ClassLinkerTest, Preverified_InitializedBoot) { ASSERT_TRUE(JavaLangObject != nullptr); EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the " "core"; - CheckPreverified(JavaLangObject, true); + CheckVerificationAttempted(JavaLangObject, true); } TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) { @@ -1160,10 +1159,10 @@ TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) { EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the " "core"; - CheckPreverified(security_manager.Get(), false); + CheckVerificationAttempted(security_manager.Get(), false); class_linker_->EnsureInitialized(soa.Self(), security_manager, true, true); - CheckPreverified(security_manager.Get(), true); + CheckVerificationAttempted(security_manager.Get(), true); } TEST_F(ClassLinkerTest, Preverified_App) { @@ -1175,10 +1174,10 @@ TEST_F(ClassLinkerTest, Preverified_App) { Handle<mirror::Class> statics( hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader))); - CheckPreverified(statics.Get(), false); + CheckVerificationAttempted(statics.Get(), false); class_linker_->EnsureInitialized(soa.Self(), statics, true, true); - CheckPreverified(statics.Get(), true); + CheckVerificationAttempted(statics.Get(), true); } TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) { diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 0663b7ef78..51611753c8 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -316,7 +316,31 @@ inline ArtField* FindFieldFromCode(uint32_t field_idx, ArtMethod* referrer, default: is_primitive = true; is_set = true; is_static = true; break; } ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static); + + ArtField* resolved_field; + if (access_check) { + // Slow path: According to JLS 13.4.8, a linkage error may occur if a compile-time + // qualifying type of a field and the resolved run-time qualifying type of a field differed + // in their static-ness. + // + // In particular, don't assume the dex instruction already correctly knows if the + // real field is static or not. The resolution must not be aware of this. + ArtMethod* method = referrer->GetInterfaceMethodIfProxy(sizeof(void*)); + + StackHandleScope<2> hs(self); + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(method->GetDexCache())); + Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(method->GetClassLoader())); + + resolved_field = class_linker->ResolveFieldJLS(*method->GetDexFile(), + field_idx, + h_dex_cache, + h_class_loader); + } else { + // Fast path: Verifier already would've called ResolveFieldJLS and we wouldn't + // be executing here if there was a static/non-static mismatch. + resolved_field = class_linker->ResolveField(field_idx, referrer, is_static); + } + if (UNLIKELY(resolved_field == nullptr)) { DCHECK(self->IsExceptionPending()); // Throw exception and unwind. return nullptr; // Failure. diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h index c8e913c0d4..ae412262fc 100644 --- a/runtime/gc/collector_type.h +++ b/runtime/gc/collector_type.h @@ -42,6 +42,8 @@ enum CollectorType { kCollectorTypeCC, // Instrumentation critical section fake collector. kCollectorTypeInstrumentation, + // Fake collector for adding or removing application image spaces. + kCollectorTypeAddRemoveAppImageSpace, // A homogeneous space compaction collector used in background transition // when both foreground and background collector are CMS. kCollectorTypeHomogeneousSpaceCompact, diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc index 84243dfe1e..679432ba89 100644 --- a/runtime/gc/gc_cause.cc +++ b/runtime/gc/gc_cause.cc @@ -34,6 +34,7 @@ const char* PrettyCause(GcCause cause) { case kGcCauseHomogeneousSpaceCompact: return "HomogeneousSpaceCompact"; case kGcCauseTrim: return "HeapTrim"; case kGcCauseInstrumentation: return "Instrumentation"; + case kGcCauseAddRemoveAppImageSpace: return "AddRemoveAppImageSpace"; default: LOG(FATAL) << "Unreachable"; UNREACHABLE(); diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h index 34c776622a..c6b505c481 100644 --- a/runtime/gc/gc_cause.h +++ b/runtime/gc/gc_cause.h @@ -41,6 +41,8 @@ enum GcCause { kGcCauseTrim, // Not a real GC cause, used to implement exclusion between GC and instrumentation. kGcCauseInstrumentation, + // Not a real GC cause, used to add or remove app image spaces. + kGcCauseAddRemoveAppImageSpace, // GC triggered for background transition when both foreground and background collector are CMS. kGcCauseHomogeneousSpaceCompact, }; diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 136b793ba1..8269f7662f 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -271,7 +271,7 @@ Heap::Heap(size_t initial_size, // The loaded spaces. Secondary images may fail to load, in which case we need to remove // already added spaces. std::vector<space::Space*> added_image_spaces; - + uint8_t* const original_requested_alloc_space_begin = requested_alloc_space_begin; for (size_t index = 0; index < image_file_names.size(); ++index) { std::string& image_name = image_file_names[index]; ATRACE_BEGIN("ImageSpace::Create"); @@ -320,7 +320,7 @@ Heap::Heap(size_t initial_size, delete loaded_space; } boot_image_spaces_.clear(); - requested_alloc_space_begin = nullptr; + requested_alloc_space_begin = original_requested_alloc_space_begin; break; } } diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index d185e6331a..92693395f1 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -925,7 +925,7 @@ class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor { if (fixup_heap_objects_) { method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this)); } - method->UpdateEntrypoints(ForwardCodeAdapter(this)); + method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this)); } private: diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 3eff7fc69d..0b2471b4c0 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -311,7 +311,7 @@ static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item, shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self); bool transaction_active = Runtime::Current()->IsActiveTransaction(); - if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) { + if (LIKELY(shadow_frame.GetMethod()->SkipAccessChecks())) { // Enter the "without access check" interpreter. if (kInterpreterImplKind == kMterpImplKind) { if (transaction_active) { diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 6c9cc7017b..09d860140f 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -637,17 +637,25 @@ static inline bool DoCallCommon(ArtMethod* called_method, self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction); self->EndAssertNoThreadSuspension(old_cause); + // ArtMethod here is needed to check type information of the call site against the callee. + // Type information is retrieved from a DexFile/DexCache for that respective declared method. + // + // As a special case for proxy methods, which are not dex-backed, + // we have to retrieve type information from the proxy's method + // interface method instead (which is dex backed since proxies are never interfaces). + ArtMethod* method = new_shadow_frame->GetMethod()->GetInterfaceMethodIfProxy(sizeof(void*)); + // We need to do runtime check on reference assignment. We need to load the shorty // to get the exact type of each reference argument. - const DexFile::TypeList* params = new_shadow_frame->GetMethod()->GetParameterTypeList(); + const DexFile::TypeList* params = method->GetParameterTypeList(); uint32_t shorty_len = 0; - const char* shorty = new_shadow_frame->GetMethod()->GetShorty(&shorty_len); + const char* shorty = method->GetShorty(&shorty_len); // Handle receiver apart since it's not part of the shorty. size_t dest_reg = first_dest_reg; size_t arg_offset = 0; - if (!new_shadow_frame->GetMethod()->IsStatic()) { + if (!method->IsStatic()) { size_t receiver_reg = is_range ? vregC : arg[0]; new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg)); ++dest_reg; @@ -667,7 +675,7 @@ static inline bool DoCallCommon(ArtMethod* called_method, if (do_assignability_check && o != nullptr) { size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); Class* arg_type = - new_shadow_frame->GetMethod()->GetClassFromTypeIndex( + method->GetClassFromTypeIndex( params->GetTypeItem(shorty_pos).type_idx_, true /* resolve */, pointer_size); if (arg_type == nullptr) { CHECK(self->IsExceptionPending()); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index b97d99424e..cdc6204665 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -800,11 +800,11 @@ ArtField* Class::FindField(Thread* self, Handle<Class> klass, const StringPiece& return nullptr; } -void Class::SetPreverifiedFlagOnAllMethods(size_t pointer_size) { +void Class::SetSkipAccessChecksFlagOnAllMethods(size_t pointer_size) { DCHECK(IsVerified()); for (auto& m : GetMethods(pointer_size)) { if (!m.IsNative() && m.IsInvokable()) { - m.SetPreverified(); + m.SetSkipAccessChecks(); } } } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 8fa4975532..388a231cdc 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -287,14 +287,18 @@ class MANAGED Class FINAL : public Object { return (GetAccessFlags() & kAccSynthetic) != 0; } - // Returns true if the class can avoid access checks. - bool IsPreverified() SHARED_REQUIRES(Locks::mutator_lock_) { - return (GetAccessFlags() & kAccPreverified) != 0; + // Return whether the class had run the verifier at least once. + // This does not necessarily mean that access checks are avoidable, + // since the class methods might still need to be run with access checks. + bool WasVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccSkipAccessChecks) != 0; } - void SetPreverified() SHARED_REQUIRES(Locks::mutator_lock_) { + // Mark the class as having gone through a verification attempt. + // Mutually exclusive from whether or not each method is allowed to skip access checks. + void SetVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) { uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); - SetAccessFlags(flags | kAccPreverified); + SetAccessFlags(flags | kAccVerificationAttempted); } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -562,7 +566,7 @@ class MANAGED Class FINAL : public Object { // The size of java.lang.Class.class. static uint32_t ClassClassSize(size_t pointer_size) { // The number of vtable entries in java.lang.Class. - uint32_t vtable_entries = Object::kVTableLength + 69; + uint32_t vtable_entries = Object::kVTableLength + 72; return ComputeClassSize(true, vtable_entries, 0, 0, 4, 1, 0, pointer_size); } @@ -1136,8 +1140,8 @@ class MANAGED Class FINAL : public Object { void VisitNativeRoots(Visitor& visitor, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - // When class is verified, set the kAccPreverified flag on each method. - void SetPreverifiedFlagOnAllMethods(size_t pointer_size) + // When class is verified, set the kAccSkipAccessChecks flag on each method. + void SetSkipAccessChecksFlagOnAllMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); // Get the descriptor of the class. In a few cases a std::string is required, rather than diff --git a/runtime/modifiers.h b/runtime/modifiers.h index 9946eabc82..ed4c5fc76c 100644 --- a/runtime/modifiers.h +++ b/runtime/modifiers.h @@ -42,14 +42,16 @@ static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5) static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16) -static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init> -static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only) -static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) -static constexpr uint32_t kAccPreverified = 0x00080000; // class (runtime), - // method (dex only) -static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only) -static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only) -static constexpr uint32_t kAccDefault = 0x00400000; // method (runtime) +static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init> +static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only) +static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) +// Used by a method to denote that its execution does not need to go through slow path interpreter. +static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (dex only) +// Used by a class to denote that the verifier has attempted to check it at least once. +static constexpr uint32_t kAccVerificationAttempted = 0x00080000; // class (runtime) +static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only) +static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only) +static constexpr uint32_t kAccDefault = 0x00400000; // method (runtime) // This is set by the class linker during LinkInterfaceMethods. Prior to that point we do not know // if any particular method needs to be a default conflict. Used to figure out at runtime if // invoking this method will throw an exception. diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 0ddd4a280c..a80585abca 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -469,14 +469,21 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT return soa.AddLocalReference<jobjectArray>(ret.Get()); } -static jobject Class_getDeclaredAnnotation(JNIEnv* env, jobject javaThis, jclass annotationType) { +static jobject Class_getDeclaredAnnotation(JNIEnv* env, jobject javaThis, jclass annotationClass) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<2> hs(soa.Self()); Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis))); + + // Handle public contract to throw NPE if the "annotationClass" argument was null. + if (UNLIKELY(annotationClass == nullptr)) { + ThrowNullPointerException("annotationClass"); + return nullptr; + } + if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) { return nullptr; } - Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType))); + Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass))); return soa.AddLocalReference<jobject>( klass->GetDexFile().GetAnnotationForClass(klass, annotation_class)); } diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index de90f0aa04..e76e443cf7 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -24,6 +24,7 @@ #include "base/stl_util.h" #include "class_linker.h" #include "dex_file-inl.h" +#include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" #include "handle_scope-inl.h" #include "mirror/class_loader.h" @@ -379,6 +380,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // spaces array. { ScopedThreadSuspension sts(self, kSuspended); + gc::ScopedGCCriticalSection gcs(self, + gc::kGcCauseAddRemoveAppImageSpace, + gc::kCollectorTypeAddRemoveAppImageSpace); ScopedSuspendAll ssa("Add image space"); runtime->GetHeap()->AddSpace(image_space.get()); } @@ -393,6 +397,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( dex_files.clear(); { ScopedThreadSuspension sts(self, kSuspended); + gc::ScopedGCCriticalSection gcs(self, + gc::kGcCauseAddRemoveAppImageSpace, + gc::kCollectorTypeAddRemoveAppImageSpace); ScopedSuspendAll ssa("Remove image space"); runtime->GetHeap()->RemoveSpace(image_space.get()); } diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index aa64ee3702..2ea4b1453d 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -277,6 +277,8 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .WithType<ExperimentalFlags>() .AppendValues() .IntoKey(M::Experimental) + .Define("-Xforce-nb-testing") + .IntoKey(M::ForceNativeBridge) .Ignore({ "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa", "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_", diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 0c06ca672c..b1b7473acb 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -602,9 +602,12 @@ bool Runtime::Start() { if (is_native_bridge_loaded_) { PreInitializeNativeBridge("."); } + NativeBridgeAction action = force_native_bridge_ + ? NativeBridgeAction::kInitialize + : NativeBridgeAction::kUnload; InitNonZygoteOrPostFork(self->GetJniEnv(), /* is_system_server */ false, - NativeBridgeAction::kInitialize, + action, GetInstructionSetString(kRuntimeISA)); } @@ -939,6 +942,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback); no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain); + force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge); Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_); @@ -1914,7 +1918,8 @@ void Runtime::SetImtUnimplementedMethod(ArtMethod* method) { } bool Runtime::IsVerificationEnabled() const { - return verify_ == verifier::VerifyMode::kEnable; + return verify_ == verifier::VerifyMode::kEnable || + verify_ == verifier::VerifyMode::kSoftFail; } bool Runtime::IsVerificationSoftFail() const { diff --git a/runtime/runtime.h b/runtime/runtime.h index c8c2ee530d..bec26f8eaa 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -774,6 +774,9 @@ class Runtime { // building a statically link version of dex2oat. bool no_sig_chain_; + // Force the use of native bridge even if the app ISA matches the runtime ISA. + bool force_native_bridge_; + // Whether or not a native bridge has been loaded. // // The native bridge allows running native code compiled for a foreign ISA. The way it works is, diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index 308f3bafc2..097bccb372 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -92,6 +92,7 @@ RUNTIME_OPTIONS_KEY (BackgroundGcOption, BackgroundGc) RUNTIME_OPTIONS_KEY (Unit, DisableExplicitGC) RUNTIME_OPTIONS_KEY (Unit, NoSigChain) +RUNTIME_OPTIONS_KEY (Unit, ForceNativeBridge) RUNTIME_OPTIONS_KEY (LogVerbosity, Verbose) RUNTIME_OPTIONS_KEY (unsigned int, LockProfThreshold) RUNTIME_OPTIONS_KEY (std::string, StackTraceFile) diff --git a/test/048-reflect-v8/expected.txt b/test/048-reflect-v8/expected.txt index 2d0b4ccb6b..3109eccda6 100644 --- a/test/048-reflect-v8/expected.txt +++ b/test/048-reflect-v8/expected.txt @@ -1,4 +1,95 @@ -Main$DefaultInterface is default = yes -Main$RegularInterface is default = no -Main$ImplementsWithDefault is default = yes -Main$ImplementsWithRegular is default = no +============================== +Are These Methods Default: +============================== +IsDefaultTest$DefaultInterface is default = yes +IsDefaultTest$RegularInterface is default = no +IsDefaultTest$ImplementsWithDefault is default = yes +IsDefaultTest$ImplementsWithRegular is default = no +============================== +Class annotations by type: +============================== +Annotations by type, defined by class SingleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Annotations by type, defined by class SingleUser with annotation Calendars: <empty> +Annotations by type, defined by class User with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23) +Annotations by type, defined by class User with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Annotations by type, defined by class User2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6) +Annotations by type, defined by class User2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)]) +Annotations by type, defined by class UserComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23) +Annotations by type, defined by class UserComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +Annotations by type, defined by class UserSub with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23) +Annotations by type, defined by class UserSub with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Annotations by type, defined by class UserSub2 with annotation Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6) +Annotations by type, defined by class UserSub2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +----------------------------- +----------------------------- +============================== +Class declared annotation: +============================== +Declared annotations by class class SingleUser, annotation interface Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Declared annotations by class class SingleUser, annotation interface Calendars: <null> +Declared annotations by class class User, annotation interface Calendar: <null> +Declared annotations by class class User, annotation interface Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Declared annotations by class class UserComplex, annotation interface Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6) +Declared annotations by class class UserComplex, annotation interface Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +Declared annotations by class class UserSub, annotation interface Calendar: <null> +Declared annotations by class class UserSub, annotation interface Calendars: <null> +Declared annotations by class class UserSub2, annotation interface Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6) +Declared annotations by class class UserSub2, annotation interface Calendars: <null> +----------------------------- +----------------------------- +============================== +Declared class annotations by type: +============================== +Declared annnotations by type, defined by class SingleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Declared annnotations by type, defined by class SingleUser with annotation Calendars: <empty> +Declared annnotations by type, defined by class User with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23) +Declared annnotations by type, defined by class User with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Declared annnotations by type, defined by class User2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6) +Declared annnotations by type, defined by class User2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)]) +Declared annnotations by type, defined by class UserComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23) +Declared annnotations by type, defined by class UserComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +Declared annnotations by type, defined by class UserSub with annotation Calendar: <empty> +Declared annnotations by type, defined by class UserSub with annotation Calendars: <empty> +Declared annnotations by type, defined by class UserSub2 with annotation Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6) +Declared annnotations by type, defined by class UserSub2 with annotation Calendars: <empty> +----------------------------- +----------------------------- +============================== +Method annotations by type: +============================== +Annotations by type, defined by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Annotations by type, defined by method singleUser with annotation Calendars: <empty> +Annotations by type, defined by method user with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23) +Annotations by type, defined by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Annotations by type, defined by method user2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6) +Annotations by type, defined by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)]) +Annotations by type, defined by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23) +Annotations by type, defined by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +----------------------------- +----------------------------- +============================== +Declared method annotations: +============================== +Annotations declared by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Annotations declared by method singleUser with annotation Calendars: <null> +Annotations declared by method user with annotation Calendar: <null> +Annotations declared by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Annotations declared by method user2 with annotation Calendar: <null> +Annotations declared by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)]) +Annotations declared by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6) +Annotations declared by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +----------------------------- +----------------------------- +============================== +Declared method annotations by type: +============================== +Annotations by type, defined by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23) +Annotations by type, defined by method singleUser with annotation Calendars: <empty> +Annotations by type, defined by method user with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23) +Annotations by type, defined by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)]) +Annotations by type, defined by method user2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6) +Annotations by type, defined by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)]) +Annotations by type, defined by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23) +Annotations by type, defined by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)]) +----------------------------- +----------------------------- diff --git a/test/048-reflect-v8/src/AnnotationTest.java b/test/048-reflect-v8/src/AnnotationTest.java new file mode 100644 index 0000000000..75e684557c --- /dev/null +++ b/test/048-reflect-v8/src/AnnotationTest.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2016 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.annotation.Annotation; +import java.lang.reflect.Method; + +public class AnnotationTest extends AnnotationTestHelpers { + public static void testAnnotationsByType() { + System.out.println("=============================="); + System.out.println("Class annotations by type:"); + System.out.println("=============================="); + + // Print associated annotations: + // * A is directly present or repeatably present on an element E; + // * No annotation of A is directly/repeatably present on an element + // AND E is a class AND A's type is inheritable, AND A is associated with its superclass. + // (Looks through subtypes recursively only if there's 0 result at each level, + // and the annotation is @Inheritable). + printAnnotationsByType(Calendar.class, SingleUser.class); + printAnnotationsByType(Calendars.class, SingleUser.class); + + printAnnotationsByType(Calendar.class, User.class); + printAnnotationsByType(Calendars.class, User.class); + + printAnnotationsByType(Calendar.class, User2.class); // Enforce ordering 'z,x,y' + printAnnotationsByType(Calendars.class, User2.class); + + // NOTE: + // Order of outer-most annotations Calendars[C,C],S vs C,Calendars[C,C] is unspecified. + // In particular it's the order of #getDeclaredAnnotations which is completely unmentioned. + // The only requirement for #getAnnotationsByType is to have same ordering as + // #getDeclaredAnnotations. + // (Calendars[] itself has to maintain value() order). + printAnnotationsByType(Calendar.class, UserComplex.class); // Cs(C,C),C collapses into C,C,C. + printAnnotationsByType(Calendars.class, UserComplex.class); + + printAnnotationsByType(Calendar.class, UserSub.class); + printAnnotationsByType(Calendars.class, UserSub.class); + + printAnnotationsByType(Calendar.class, UserSub2.class); + // The directly present "Calendar" annotation masks all the repeatably present + // "Calendar" annotations coming from User. + printAnnotationsByType(Calendars.class, UserSub2.class); + // Edge case: UserSub2 doesn't directly have a Calendars annotation, + // so it doesn't mask the "User" Calendars annotation. + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + + } + + public static void testDeclaredAnnotation() { + System.out.println("=============================="); + System.out.println("Class declared annotation:"); + System.out.println("=============================="); + + // Print directly present annotations: + // + // The element E has an annotation_item for it (accessible through an + // annotations_directory_item) corresponding to an annotation A, + // and A's type_idx must match that on the encoded_annotation (from the annotation_item). + // (Does not look through the subtypes recursively) + printDeclaredAnnotation(SingleUser.class, Calendar.class); + printDeclaredAnnotation(SingleUser.class, Calendars.class); + + printDeclaredAnnotation(User.class, Calendar.class); + printDeclaredAnnotation(User.class, Calendars.class); + + printDeclaredAnnotation(UserComplex.class, Calendar.class); + printDeclaredAnnotation(UserComplex.class, Calendars.class); + + printDeclaredAnnotation(UserSub.class, Calendar.class); + printDeclaredAnnotation(UserSub.class, Calendars.class); + + printDeclaredAnnotation(UserSub2.class, Calendar.class); + printDeclaredAnnotation(UserSub2.class, Calendars.class); + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + } + + public static void testDeclaredAnnotationsByType() { + System.out.println("=============================="); + System.out.println("Declared class annotations by type:"); + System.out.println("=============================="); + + // A is directly present or repeatably present on an element E; + // -- (does not do any recursion for classes regardless of @Inherited) + printDeclaredAnnotationsByType(Calendar.class, SingleUser.class); + printDeclaredAnnotationsByType(Calendars.class, SingleUser.class); + + printDeclaredAnnotationsByType(Calendar.class, User.class); + printDeclaredAnnotationsByType(Calendars.class, User.class); + + printDeclaredAnnotationsByType(Calendar.class, User2.class); // Enforce ordering 'z,x,y' + printDeclaredAnnotationsByType(Calendars.class, User2.class); + + printDeclaredAnnotationsByType(Calendar.class, UserComplex.class); + printDeclaredAnnotationsByType(Calendars.class, UserComplex.class); + + printDeclaredAnnotationsByType(Calendar.class, UserSub.class); + printDeclaredAnnotationsByType(Calendars.class, UserSub.class); + + printDeclaredAnnotationsByType(Calendar.class, UserSub2.class); + // The directly present "Calendar" annotation masks all the repeatably present "Calendar" + // annotations coming from User. + printDeclaredAnnotationsByType(Calendars.class, UserSub2.class); + // Edge case: UserSub2 doesn't directly have a Calendars annotation, + // so it doesn't mask the "User" Calendars annotation. + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + } + + // Print the annotation "annotationClass" that is associated with an element denoted by + // "annotationUseClass." + private static <A extends Annotation> void printAnnotationsByType(Class<A> annotationClass, + Class<?> annotationUseClass) { + A[] annotationsByType = annotationUseClass.getAnnotationsByType(annotationClass); + + String msg = "Annotations by type, defined by class " + + annotationUseClass.getName() + " with annotation " + annotationClass.getName() + ": " + + asString(annotationsByType); + + + System.out.println(msg); + } + + private static <A extends Annotation> void printDeclaredAnnotation(Class<?> annotationUseClass, + Class<A> annotationDefClass) { + A anno = annotationUseClass.getDeclaredAnnotation(annotationDefClass); + + String msg = asString(anno); + + System.out.println("Declared annotations by class " + annotationUseClass + + ", annotation " + annotationDefClass + ": " + msg); + } + + // Print the annotation "annotationClass" that is directly/indirectly present with an element + // denoted by "annotationUseClass." + private static <A extends Annotation> void printDeclaredAnnotationsByType( + Class<A> annotationClass, Class<?> annotationUseClass) { + A[] annotationsByType = annotationUseClass.getDeclaredAnnotationsByType(annotationClass); + + String msg = "Declared annnotations by type, defined by class " + annotationUseClass.getName() + + " with annotation " + annotationClass.getName() + ": " + + asString(annotationsByType); + + System.out.println(msg); + } + + public static void testMethodAnnotationsByType() { + System.out.println("=============================="); + System.out.println("Method annotations by type:"); + System.out.println("=============================="); + + // Print associated annotations: + // * A is directly present or repeatably present on an element E; + // * No annotation of A is directly/repeatably present on an element AND E is a class + // AND A's type is inheritable, AND A is associated with its superclass. + // (Looks through subtypes recursively only if there's 0 result at each level, + // and the annotation is @Inheritable). + printMethodAnnotationsByType(Calendar.class, "singleUser", AnnotationTestFixture.class); + printMethodAnnotationsByType(Calendars.class, "singleUser", AnnotationTestFixture.class); + + printMethodAnnotationsByType(Calendar.class, "user", AnnotationTestFixture.class); + printMethodAnnotationsByType(Calendars.class, "user", AnnotationTestFixture.class); + + printMethodAnnotationsByType(Calendar.class, "user2", AnnotationTestFixture.class); + printMethodAnnotationsByType(Calendars.class, "user2", AnnotationTestFixture.class); + + printMethodAnnotationsByType(Calendar.class, "userComplex", AnnotationTestFixture.class); + printMethodAnnotationsByType(Calendars.class, "userComplex", AnnotationTestFixture.class); + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + } + + // Print the annotation "annotationClass" that is associated with an element denoted by + // "annotationUseClass" method methodName. + private static <A extends Annotation> void printMethodAnnotationsByType(Class<A> annotationClass, + String methodName, Class<?> annotationUseClass) { + Method m = null; + try { + m = annotationUseClass.getDeclaredMethod(methodName); + } catch (Throwable t) { + throw new AssertionError(t); + } + A[] annotationsByType = m.getAnnotationsByType(annotationClass); + + String msg = "Annotations by type, defined by method " + m.getName() + " with annotation " + + annotationClass.getName() + ": " + + asString(annotationsByType); + + System.out.println(msg); + } + + public static void testMethodDeclaredAnnotations() { + System.out.println("=============================="); + System.out.println("Declared method annotations:"); + System.out.println("=============================="); + + printMethodDeclaredAnnotation(Calendar.class, "singleUser", AnnotationTestFixture.class); + printMethodDeclaredAnnotation(Calendars.class, "singleUser", AnnotationTestFixture.class); + + printMethodDeclaredAnnotation(Calendar.class, "user", AnnotationTestFixture.class); + printMethodDeclaredAnnotation(Calendars.class, "user", AnnotationTestFixture.class); + + printMethodDeclaredAnnotation(Calendar.class, "user2", AnnotationTestFixture.class); + printMethodDeclaredAnnotation(Calendars.class, "user2", AnnotationTestFixture.class); + + printMethodDeclaredAnnotation(Calendar.class, "userComplex", AnnotationTestFixture.class); + printMethodDeclaredAnnotation(Calendars.class, "userComplex", AnnotationTestFixture.class); + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + } + + // Print the annotation "annotationClass" that is associated with an element denoted by + // methodName in annotationUseClass. + private static <A extends Annotation> void printMethodDeclaredAnnotation(Class<A> annotationClass, + String methodName, Class<?> annotationUseClass) { + Method m = null; + try { + m = annotationUseClass.getDeclaredMethod(methodName); + } catch (Throwable t) { + throw new AssertionError(t); + } + Annotation annotationsByType = m.getDeclaredAnnotation(annotationClass); + + String msg = "Annotations declared by method " + m.getName() + " with annotation " + + annotationClass.getName() + ": " + + asString(annotationsByType); + + System.out.println(msg); + } + + public static void testMethodDeclaredAnnotationsByType() { + System.out.println("=============================="); + System.out.println("Declared method annotations by type:"); + System.out.println("=============================="); + + printMethodDeclaredAnnotationByType(Calendar.class, "singleUser", AnnotationTestFixture.class); + printMethodDeclaredAnnotationByType(Calendars.class, "singleUser", AnnotationTestFixture.class); + + printMethodDeclaredAnnotationByType(Calendar.class, "user", AnnotationTestFixture.class); + printMethodDeclaredAnnotationByType(Calendars.class, "user", AnnotationTestFixture.class); + + printMethodDeclaredAnnotationByType(Calendar.class, "user2", AnnotationTestFixture.class); + printMethodDeclaredAnnotationByType(Calendars.class, "user2", AnnotationTestFixture.class); + + printMethodDeclaredAnnotationByType(Calendar.class, "userComplex", AnnotationTestFixture.class); + printMethodDeclaredAnnotationByType(Calendars.class, "userComplex", + AnnotationTestFixture.class); + + System.out.println("-----------------------------"); + System.out.println("-----------------------------"); + } + + // Print the annotation "annotationClass" that is associated with an element denoted by + // methodName in annotationUseClass. + private static <A extends Annotation> void printMethodDeclaredAnnotationByType( + Class<A> annotationClass, String methodName, Class<?> annotationUseClass) { + Method m = null; + try { + m = annotationUseClass.getDeclaredMethod(methodName); + } catch (Throwable t) { + throw new AssertionError(t); + } + A[] annotationsByType = m.getDeclaredAnnotationsByType(annotationClass); + + String msg = "Annotations by type, defined by method " + m.getName() + " with annotation " + + annotationClass.getName() + ": " + + asString(annotationsByType); + + System.out.println(msg); + } +} diff --git a/test/048-reflect-v8/src/AnnotationTestFixture.java b/test/048-reflect-v8/src/AnnotationTestFixture.java new file mode 100644 index 0000000000..248dfacf3b --- /dev/null +++ b/test/048-reflect-v8/src/AnnotationTestFixture.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 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. + */ + +public class AnnotationTestFixture { + + @Calendar(dayOfWeek="single", hour=23) + public static void singleUser() { + + } + @Calendars ({ + @Calendar(dayOfMonth="last"), + @Calendar(dayOfWeek="Fri", hour=23) + }) + public static void user() { + + } + + @Calendars ({ + @Calendar(dayOfMonth="z"), + @Calendar(dayOfMonth="x"), + @Calendar(dayOfMonth="y") + }) + public static void user2() { + + } + + @Calendar(dayOfMonth="afirst") + @Calendars ({ + @Calendar(dayOfMonth="zsecond"), + @Calendar(dayOfMonth="athird", hour=23) + }) + public static void userComplex() { + + } +} diff --git a/test/048-reflect-v8/src/AnnotationTestHelpers.java b/test/048-reflect-v8/src/AnnotationTestHelpers.java new file mode 100644 index 0000000000..6b5bea266e --- /dev/null +++ b/test/048-reflect-v8/src/AnnotationTestHelpers.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 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.annotation.Annotation; + +public class AnnotationTestHelpers { + // Provide custom print function that print a deterministic output. + // Note that Annotation#toString has unspecified order: it prints out the + // fields, which is why we can't rely on it. + + public static String asString(Annotation anno) { + if (anno instanceof Calendar) { + return asString((Calendar)anno); + } else if (anno instanceof Calendars) { + return asString((Calendars)anno); + } else { + if (anno == null) { + return "<null>"; + } + // Fall-back, usually would only go here in a test failure. + return anno.toString(); + } + } + + public static String asString(Annotation[] annos) { + String msg = ""; + + if (annos == null) { + msg += "<null>"; + } else if (annos.length == 0) { + msg += "<empty>"; + } else { + for (int i = 0; i < annos.length; ++i) { + msg += asString(annos[i]); + + if (i != annos.length - 1) { + msg += ", "; + } + } + } + + return msg; + } + + public static String asString(Calendar calendar) { + if (calendar == null) { + return "<null>"; + } + + return "@Calendar(dayOfMonth=" + calendar.dayOfMonth() + ", dayOfWeek=" + + calendar.dayOfWeek() + ", hour=" + calendar.hour() + ")"; + } + + public static String asString(Calendars calendars) { + if (calendars == null) { + return "<null>"; + } + + String s = "@Calendars(value=["; + + Calendar[] allValues = calendars.value(); + for (int i = 0; i < allValues.length; ++i) { + s += asString(allValues[i]); + if (i != allValues.length - 1) { + s += ", "; + } + } + + s += "])"; + + return s; + } +} diff --git a/test/048-reflect-v8/src/Calendar.java b/test/048-reflect-v8/src/Calendar.java new file mode 100644 index 0000000000..4a16573bca --- /dev/null +++ b/test/048-reflect-v8/src/Calendar.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 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.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +// This is a plain old non-1.8 annotation. At runtime we can see that it has a +// "Repeatable" annotation if we query with getDeclaredAnnotation(Repeatable.class) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(Calendars.class) +@Inherited // note: container must also be @Inherited by JLS. +public @interface Calendar { + String dayOfMonth() default "unspecified_month"; + String dayOfWeek() default "unspecified_week"; + int hour() default 6; +} + diff --git a/test/048-reflect-v8/src/Calendars.java b/test/048-reflect-v8/src/Calendars.java new file mode 100644 index 0000000000..caeda52ea6 --- /dev/null +++ b/test/048-reflect-v8/src/Calendars.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +// Plain old annotation, there's nothing 1.8 specific about it. +@Retention(RetentionPolicy.RUNTIME) +@Inherited // note: elements must also be @Inherited by JLS. +public @interface Calendars { + Calendar[] value(); +} diff --git a/test/048-reflect-v8/src/IFaceA.java b/test/048-reflect-v8/src/IFaceA.java new file mode 100644 index 0000000000..9b1f610f84 --- /dev/null +++ b/test/048-reflect-v8/src/IFaceA.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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. + */ + +// Stored as a complex annotation Calendars(Calendar,Calendar) +// in the binary. +@Calendars ({ + @Calendar(dayOfMonth="if_a_first"), + @Calendar(dayOfMonth="if_b_last") +}) +public interface IFaceA { +} diff --git a/test/048-reflect-v8/src/IFaceSimple.java b/test/048-reflect-v8/src/IFaceSimple.java new file mode 100644 index 0000000000..93cf61057e --- /dev/null +++ b/test/048-reflect-v8/src/IFaceSimple.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 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. + */ + +// Simple annotation, no container. +@Calendar(dayOfMonth="if_simple_first") +public interface IFaceSimple { + +} diff --git a/test/048-reflect-v8/src/IsDefaultTest.java b/test/048-reflect-v8/src/IsDefaultTest.java new file mode 100644 index 0000000000..177dcf1ab9 --- /dev/null +++ b/test/048-reflect-v8/src/IsDefaultTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 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.Method; + +public class IsDefaultTest { + interface DefaultInterface { + default void sayHi() { + System.out.println("hi default"); + } + } + + interface RegularInterface { + void sayHi(); + } + + class ImplementsWithDefault implements DefaultInterface {} + class ImplementsWithRegular implements RegularInterface { + public void sayHi() { + System.out.println("hello specific"); + } + } + + private static void printIsDefault(Class<?> klass) { + Method m; + try { + m = klass.getMethod("sayHi"); + } catch (Throwable t) { + System.out.println(t); + return; + } + + boolean isDefault = m.isDefault(); + System.out.println(klass.getName() + " is default = " + (isDefault ? "yes" : "no")); + } + + public static void test() { + System.out.println("=============================="); + System.out.println("Are These Methods Default:"); + System.out.println("=============================="); + + printIsDefault(DefaultInterface.class); + printIsDefault(RegularInterface.class); + printIsDefault(ImplementsWithDefault.class); + printIsDefault(ImplementsWithRegular.class); + } +} diff --git a/test/048-reflect-v8/src/Main.java b/test/048-reflect-v8/src/Main.java index 7fa2a923d7..f2b8287d18 100644 --- a/test/048-reflect-v8/src/Main.java +++ b/test/048-reflect-v8/src/Main.java @@ -14,43 +14,14 @@ * limitations under the License. */ -import java.lang.reflect.Method; - public class Main { - interface DefaultInterface { - default void sayHi() { - System.out.println("hi default"); - } - } - - interface RegularInterface { - void sayHi(); - } - - class ImplementsWithDefault implements DefaultInterface {} - class ImplementsWithRegular implements RegularInterface { - public void sayHi() { - System.out.println("hello specific"); - } - } - - private static void printIsDefault(Class<?> klass) { - Method m; - try { - m = klass.getMethod("sayHi"); - } catch (Throwable t) { - System.out.println(t); - return; - } - - boolean isDefault = m.isDefault(); - System.out.println(klass.getName() + " is default = " + (isDefault ? "yes" : "no")); - } - public static void main(String[] args) { - printIsDefault(DefaultInterface.class); - printIsDefault(RegularInterface.class); - printIsDefault(ImplementsWithDefault.class); - printIsDefault(ImplementsWithRegular.class); + IsDefaultTest.test(); + AnnotationTest.testAnnotationsByType(); + AnnotationTest.testDeclaredAnnotation(); + AnnotationTest.testDeclaredAnnotationsByType(); + AnnotationTest.testMethodAnnotationsByType(); + AnnotationTest.testMethodDeclaredAnnotations(); + AnnotationTest.testMethodDeclaredAnnotationsByType(); } } diff --git a/test/048-reflect-v8/src/SingleUser.java b/test/048-reflect-v8/src/SingleUser.java new file mode 100644 index 0000000000..0f9c430109 --- /dev/null +++ b/test/048-reflect-v8/src/SingleUser.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 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. + */ + +// Stored as a single "Calendar" annotation in the binary. +@Calendar(dayOfWeek="single", hour=23) +public class SingleUser { + +} diff --git a/test/048-reflect-v8/src/User.java b/test/048-reflect-v8/src/User.java new file mode 100644 index 0000000000..003ceeb093 --- /dev/null +++ b/test/048-reflect-v8/src/User.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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. + */ + +// Stored as a complex annotation Calendars(Calendar,Calendar) +// in the binary. +// +/* FIXME: Use this code instead, when Jack supports repeatable annotations properly. + * + * @Calendar(dayOfMonth="last") + * @Calendar(dayOfWeek="Fri", hour=23) + */ +@Calendars ({ + @Calendar(dayOfMonth="last"), + @Calendar(dayOfWeek="Fri", hour=23) +}) +public class User { + +} diff --git a/test/048-reflect-v8/src/User2.java b/test/048-reflect-v8/src/User2.java new file mode 100644 index 0000000000..1a6049f508 --- /dev/null +++ b/test/048-reflect-v8/src/User2.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +// Stored as a complex annotation Calendars(Calendar,Calendar,Calendar) +// in the binary. +// (Check for order, should be z,x,y) +@Calendars ({ + @Calendar(dayOfMonth="z"), + @Calendar(dayOfMonth="x"), + @Calendar(dayOfMonth="y") +}) +public class User2 { + +} diff --git a/test/048-reflect-v8/src/UserComplex.java b/test/048-reflect-v8/src/UserComplex.java new file mode 100644 index 0000000000..e26234960b --- /dev/null +++ b/test/048-reflect-v8/src/UserComplex.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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. + */ + +// Stored as a complex annotation Calendars(Calendar,Calendar) +// followed by a Calendar in the binary. +// In other words { Calendars([C,C]), C } +// +// Note that trying to do {C,Calendars,C} or similar +// is illegal by the JLS. +@Calendar(dayOfMonth="afirst") +@Calendars ({ + @Calendar(dayOfMonth="zsecond"), + @Calendar(dayOfMonth="athird", hour=23) +}) +// @Calendar(dayOfMonth="zlast") // Leave for future ordering test +public class UserComplex { + +} diff --git a/test/048-reflect-v8/src/UserSub.java b/test/048-reflect-v8/src/UserSub.java new file mode 100644 index 0000000000..d60aa6a3f1 --- /dev/null +++ b/test/048-reflect-v8/src/UserSub.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 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. + */ + +public class UserSub + extends User + implements IFaceA, IFaceSimple { + +} diff --git a/test/048-reflect-v8/src/UserSub2.java b/test/048-reflect-v8/src/UserSub2.java new file mode 100644 index 0000000000..13e2eb07c8 --- /dev/null +++ b/test/048-reflect-v8/src/UserSub2.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 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. + */ + +// This calendar subsumes anything else we would've normally gotten from the subclass. +@Calendar(dayOfMonth="sub2") +public class UserSub2 + extends User + implements IFaceA, IFaceSimple { + +} diff --git a/test/115-native-bridge/run b/test/115-native-bridge/run index ea2045b86c..aeb5721aac 100644 --- a/test/115-native-bridge/run +++ b/test/115-native-bridge/run @@ -28,4 +28,4 @@ ln -s ${LIBPATH}/libarttestd.so libarttestd2.so LEFT=$(echo ${ARGS} | sed -r 's/-Djava.library.path.*//') RIGHT=$(echo ${ARGS} | sed -r 's/.*Djava.library.path[^ ]* //') MODARGS="${LEFT} -Djava.library.path=`pwd` ${RIGHT}" -exec ${RUN} --runtime-option -XX:NativeBridge=libnativebridgetest.so ${MODARGS} NativeBridgeMain +exec ${RUN} --runtime-option -Xforce-nb-testing --runtime-option -XX:NativeBridge=libnativebridgetest.so ${MODARGS} NativeBridgeMain diff --git a/test/562-bce-preheader/src/Main.java b/test/562-bce-preheader/src/Main.java index 8de0533591..8b527b4f63 100644 --- a/test/562-bce-preheader/src/Main.java +++ b/test/562-bce-preheader/src/Main.java @@ -70,6 +70,26 @@ public class Main { return acc; } + /** + * An artificial example with an inconsistent phi structure during + * dynamic bce that is corrected afterwards. Note that only the last + * assignment is really live, but the other statements set up an + * interesting phi structure. + */ + private static int doit(int[] z) { + int a = 0; + for (int i = 0; i < 10; ++i) { + for (int j = i; j < 10; ++j) { + a = z[i]; + for (int k = 0; k < 10; ++k) { + a += z[k]; + a = z[i]; + } + } + } + return a; + } + public static void main(String args[]) { int[][] x = new int[2][2]; int y; @@ -96,6 +116,9 @@ public class Main { expectEquals(26, foo(a, b, 2)); expectEquals(38, foo(a, b, 3)); + int[] z = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + expectEquals(10, doit(z)); + System.out.println("passed"); } diff --git a/test/565-checker-doublenegbitwise/src/Main.java b/test/565-checker-doublenegbitwise/src/Main.java index d681ad7e8e..c51eda8a66 100644 --- a/test/565-checker-doublenegbitwise/src/Main.java +++ b/test/565-checker-doublenegbitwise/src/Main.java @@ -37,7 +37,7 @@ public class Main { // Note: before the instruction_simplifier pass, Xor's are used instead of // Not's (the simplification happens during the same pass). - /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before) + /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<CstM1:i\d+>> IntConstant -1 @@ -46,14 +46,14 @@ public class Main { /// CHECK: <<And:i\d+>> And [<<Not1>>,<<Not2>>] /// CHECK: Return [<<And>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<Or:i\d+>> Or [<<P1>>,<<P2>>] /// CHECK: <<Not:i\d+>> Not [<<Or>>] /// CHECK: Return [<<Not>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not /// CHECK-NOT: And @@ -69,7 +69,7 @@ public class Main { // See note above. // The second Xor has its arguments reversed for no obvious reason. - /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before) + /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before) /// CHECK: <<P1:j\d+>> ParameterValue /// CHECK: <<P2:j\d+>> ParameterValue /// CHECK: <<CstM1:j\d+>> LongConstant -1 @@ -78,14 +78,14 @@ public class Main { /// CHECK: <<Or:j\d+>> Or [<<Not1>>,<<Not2>>] /// CHECK: Return [<<Or>>] - /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) + /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) /// CHECK: <<P1:j\d+>> ParameterValue /// CHECK: <<P2:j\d+>> ParameterValue /// CHECK: <<And:j\d+>> And [<<P1>>,<<P2>>] /// CHECK: <<Not:j\d+>> Not [<<And>>] /// CHECK: Return [<<Not>>] - /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) + /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not /// CHECK-NOT: Or @@ -102,7 +102,7 @@ public class Main { * operation incorrectly. */ - /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before) + /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK-DAG: <<Cst1:i\d+>> IntConstant 1 @@ -114,7 +114,7 @@ public class Main { /// CHECK: <<Or:i\d+>> Or [<<Not1>>,<<Not2>>] /// CHECK: Return [<<Or>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<Cst1:i\d+>> IntConstant 1 @@ -124,7 +124,7 @@ public class Main { /// CHECK: <<Not:i\d+>> Not [<<And>>] /// CHECK: Return [<<Not>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after) /// CHECK: Not /// CHECK-NOT: Not /// CHECK-NOT: Or @@ -143,7 +143,7 @@ public class Main { */ // See first note above. - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before) + /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<CstM1:i\d+>> IntConstant -1 @@ -152,13 +152,13 @@ public class Main { /// CHECK: <<Xor:i\d+>> Xor [<<Not1>>,<<Not2>>] /// CHECK: Return [<<Xor>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<Xor:i\d+>> Xor [<<P1>>,<<P2>>] /// CHECK: Return [<<Xor>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after) /// CHECK-NOT: Not public static int $opt$noinline$notXorToXor(int a, int b) { @@ -170,7 +170,7 @@ public class Main { * Check that no transformation is done when one Not has multiple uses. */ - /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before) + /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<CstM1:i\d+>> IntConstant -1 @@ -182,7 +182,7 @@ public class Main { /// CHECK: <<Add:i\d+>> Add [<<And2>>,<<And1>>] /// CHECK: Return [<<Add>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) /// CHECK: <<P1:i\d+>> ParameterValue /// CHECK: <<P2:i\d+>> ParameterValue /// CHECK: <<One:i\d+>> IntConstant 1 @@ -193,7 +193,7 @@ public class Main { /// CHECK: <<Add:i\d+>> Add [<<And2>>,<<And1>>] /// CHECK: Return [<<Add>>] - /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) + /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after) /// CHECK-NOT: Or public static int $opt$noinline$notMultipleUses(int a, int b) { diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index dfb540edf2..a8938fad40 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -302,18 +302,7 @@ TEST_ART_BROKEN_NO_RELOCATE_TESTS := # Temporarily disable some broken tests when forcing access checks in interpreter b/22414682 TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \ - 004-JniTest \ - 005-annotations \ - 044-proxy \ - 073-mismatched-field \ - 088-monitor-verification \ - 135-MirandaDispatch \ - 137-cfi \ - 412-new-array \ - 471-uninitialized-locals \ - 506-verify-aput \ - 554-jit-profile-file \ - 800-smali + 137-cfi ifneq (,$(filter interp-ac,$(COMPILER_TYPES))) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ @@ -470,10 +459,7 @@ TEST_ART_BROKEN_DEFAULT_RUN_TESTS := # Known broken tests for the mips32 optimizing compiler backend. TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := \ - 441-checker-inliner \ 510-checker-try-catch \ - 536-checker-intrinsic-optimization \ - 557-checker-instruction-simplifier-ror \ ifeq (mips,$(TARGET_ARCH)) ifneq (,$(filter optimizing,$(COMPILER_TYPES))) @@ -488,7 +474,6 @@ TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := # Known broken tests for the mips64 optimizing compiler backend. TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS := \ - 557-checker-instruction-simplifier-ror \ ifeq (mips64,$(TARGET_ARCH)) ifneq (,$(filter optimizing,$(COMPILER_TYPES))) diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index 6d67f8477d..93e71a73fb 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -266,5 +266,10 @@ "libcore.util.NativeAllocationRegistryTest#testNativeAllocationNoAllocatorAndNoSharedRegistry", "libcore.util.NativeAllocationRegistryTest#testNativeAllocationNoAllocatorAndSharedRegistry", "libcore.util.NativeAllocationRegistryTest#testNullArguments"] +}, +{ + description: "Intermittent failure the libcore team is working on", + result: EXEC_FAILED, + names: ["ibcore.util.ZoneInfoTest#testReadSerialized"] } ] diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt index 95d12928f1..d8ef9baa64 100644 --- a/tools/libcore_failures_concurrent_collector.txt +++ b/tools/libcore_failures_concurrent_collector.txt @@ -27,7 +27,8 @@ description: "TimeoutException on host-{x86,x86-64}-concurrent-collector", result: EXEC_FAILED, modes: [host], - names: ["libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushDisabled", + names: ["libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushEnabled", + "libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushDisabled", "libcore.java.util.zip.GZIPOutputStreamTest#testSyncFlushEnabled", "libcore.java.util.zip.OldAndroidGZIPStreamTest#testGZIPStream", "libcore.java.util.zip.OldAndroidZipStreamTest#testZipStream", @@ -40,7 +41,8 @@ result: EXEC_FAILED, modes: [device], names: ["libcore.icu.RelativeDateTimeFormatterTest#test_bug25821045", - "libcore.java.text.SimpleDateFormatTest#testLocales"], + "libcore.java.text.SimpleDateFormatTest#testLocales", + "libcore.java.util.zip.ZipFileTest#testZipFileWithLotsOfEntries"], bug: 26711853 } ] |