summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/compiled_method.h6
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--compiler/elf_builder.h81
-rw-r--r--compiler/elf_writer.h3
-rw-r--r--compiler/elf_writer_debug.cc94
-rw-r--r--compiler/elf_writer_debug.h10
-rw-r--r--compiler/elf_writer_quick.cc67
-rw-r--r--compiler/optimizing/bounds_check_elimination.cc41
-rw-r--r--compiler/optimizing/induction_var_range.cc9
-rw-r--r--compiler/optimizing/induction_var_range.h32
-rw-r--r--compiler/optimizing/nodes.cc1
-rw-r--r--dex2oat/dex2oat.cc11
-rw-r--r--runtime/art_method.h10
-rw-r--r--runtime/class_linker.cc87
-rw-r--r--runtime/class_linker.h7
-rw-r--r--runtime/class_linker_test.cc25
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h26
-rw-r--r--runtime/gc/collector_type.h2
-rw-r--r--runtime/gc/gc_cause.cc1
-rw-r--r--runtime/gc/gc_cause.h2
-rw-r--r--runtime/gc/heap.cc4
-rw-r--r--runtime/gc/space/image_space.cc2
-rw-r--r--runtime/interpreter/interpreter.cc2
-rw-r--r--runtime/interpreter/interpreter_common.cc16
-rw-r--r--runtime/mirror/class.cc4
-rw-r--r--runtime/mirror/class.h20
-rw-r--r--runtime/modifiers.h18
-rw-r--r--runtime/native/java_lang_Class.cc11
-rw-r--r--runtime/oat_file_manager.cc7
-rw-r--r--runtime/parsed_options.cc2
-rw-r--r--runtime/runtime.cc9
-rw-r--r--runtime/runtime.h3
-rw-r--r--runtime/runtime_options.def1
-rw-r--r--test/048-reflect-v8/expected.txt99
-rw-r--r--test/048-reflect-v8/src/AnnotationTest.java291
-rw-r--r--test/048-reflect-v8/src/AnnotationTestFixture.java48
-rw-r--r--test/048-reflect-v8/src/AnnotationTestHelpers.java86
-rw-r--r--test/048-reflect-v8/src/Calendar.java32
-rw-r--r--test/048-reflect-v8/src/Calendars.java26
-rw-r--r--test/048-reflect-v8/src/IFaceA.java24
-rw-r--r--test/048-reflect-v8/src/IFaceSimple.java21
-rw-r--r--test/048-reflect-v8/src/IsDefaultTest.java60
-rw-r--r--test/048-reflect-v8/src/Main.java43
-rw-r--r--test/048-reflect-v8/src/SingleUser.java21
-rw-r--r--test/048-reflect-v8/src/User.java31
-rw-r--r--test/048-reflect-v8/src/User2.java27
-rw-r--r--test/048-reflect-v8/src/UserComplex.java31
-rw-r--r--test/048-reflect-v8/src/UserSub.java21
-rw-r--r--test/048-reflect-v8/src/UserSub2.java23
-rw-r--r--test/115-native-bridge/run2
-rw-r--r--test/562-bce-preheader/src/Main.java23
-rw-r--r--test/565-checker-doublenegbitwise/src/Main.java30
-rw-r--r--test/Android.run-test.mk17
-rw-r--r--tools/libcore_failures.txt5
-rw-r--r--tools/libcore_failures_concurrent_collector.txt6
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
}
]