Merge "Add test for Change-Id: Ied0412a01922b40a3f5d89bed49707498582abc1"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 730e61d..5d4f1d3 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -30,6 +30,7 @@
Interfaces \
Main \
MultiDex \
+ MultiDexModifiedSecondary \
MyClass \
MyClassNatives \
Nested \
@@ -68,7 +69,7 @@
ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
-ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex Nested
+ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
ART_GTEST_proxy_test_DEX_DEPS := Interfaces
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 03165ed..e02fe4b 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -579,6 +579,8 @@
log_verbosity.class_linker = true;
} else if (verbose_options[j] == "compiler") {
log_verbosity.compiler = true;
+ } else if (verbose_options[j] == "deopt") {
+ log_verbosity.deopt = true;
} else if (verbose_options[j] == "gc") {
log_verbosity.gc = true;
} else if (verbose_options[j] == "heap") {
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index f7501d2..5e345db 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -30,6 +30,8 @@
namespace art {
+constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;
+
class CFITest : public dwarf::DwarfTest {
public:
void GenerateExpected(FILE* f, InstructionSet isa, const char* isa_str,
@@ -46,11 +48,11 @@
// Pretty-print CFI opcodes.
constexpr bool is64bit = false;
dwarf::DebugFrameOpCodeWriter<> initial_opcodes;
- dwarf::WriteEhFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
- initial_opcodes, &eh_frame_data_);
- std::vector<uintptr_t> eh_frame_patches;
- dwarf::WriteEhFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
- &eh_frame_data_, &eh_frame_patches);
+ dwarf::WriteDebugFrameCIE(is64bit, dwarf::DW_EH_PE_absptr, dwarf::Reg(8),
+ initial_opcodes, kCFIFormat, &debug_frame_data_);
+ std::vector<uintptr_t> debug_frame_patches;
+ dwarf::WriteDebugFrameFDE(is64bit, 0, 0, actual_asm.size(), &actual_cfi,
+ kCFIFormat, &debug_frame_data_, &debug_frame_patches);
ReformatCfi(Objdump(false, "-W"), &lines);
// Pretty-print assembly.
auto* opts = new DisassemblerOptions(false, actual_asm.data(), true);
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/dwarf/dwarf_constants.h
index 61a44cd..3b570e5 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/dwarf/dwarf_constants.h
@@ -680,6 +680,14 @@
DW_EH_PE_aligned = 0x50,
};
+enum CFIFormat : uint8_t {
+ // This is the original format as defined by the specification.
+ // It is used for the .debug_frame section.
+ DW_DEBUG_FRAME_FORMAT,
+ // Slightly modified format used for the .eh_frame section.
+ DW_EH_FRAME_FORMAT
+};
+
} // namespace dwarf
} // namespace art
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/dwarf/dwarf_test.cc
index edba00a..4971f0e 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/dwarf/dwarf_test.cc
@@ -26,6 +26,8 @@
namespace art {
namespace dwarf {
+constexpr CFIFormat kCFIFormat = DW_DEBUG_FRAME_FORMAT;
+
// Run the tests only on host since we need objdump.
#ifndef HAVE_ANDROID_OS
@@ -120,30 +122,30 @@
DW_CHECK_NEXT("DW_CFA_restore: r5 (ebp)");
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8),
- initial_opcodes, &eh_frame_data_);
- std::vector<uintptr_t> eh_frame_patches;
+ WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(is64bit ? 16 : 8),
+ initial_opcodes, kCFIFormat, &debug_frame_data_);
+ std::vector<uintptr_t> debug_frame_patches;
std::vector<uintptr_t> expected_patches { 28 }; // NOLINT
- WriteEhFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
- &eh_frame_data_, &eh_frame_patches);
+ WriteDebugFrameFDE(is64bit, 0, 0x01000000, 0x01000000, opcodes.data(),
+ kCFIFormat, &debug_frame_data_, &debug_frame_patches);
- EXPECT_EQ(expected_patches, eh_frame_patches);
+ EXPECT_EQ(expected_patches, debug_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
TEST_F(DwarfTest, DebugFrame64) {
constexpr bool is64bit = true;
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
- initial_opcodes, &eh_frame_data_);
+ WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+ initial_opcodes, kCFIFormat, &debug_frame_data_);
DebugFrameOpCodeWriter<> opcodes;
- std::vector<uintptr_t> eh_frame_patches;
+ std::vector<uintptr_t> debug_frame_patches;
std::vector<uintptr_t> expected_patches { 32 }; // NOLINT
- WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
- opcodes.data(), &eh_frame_data_, &eh_frame_patches);
+ WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
+ opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
DW_CHECK("FDE cie=00000000 pc=100000000000000..300000000000000");
- EXPECT_EQ(expected_patches, eh_frame_patches);
+ EXPECT_EQ(expected_patches, debug_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
@@ -173,11 +175,11 @@
DW_CHECK_NEXT("DW_CFA_offset: r14 (r14)");
DW_CHECK_NEXT("DW_CFA_offset: r15 (r15)");
DebugFrameOpCodeWriter<> initial_opcodes;
- WriteEhFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
- initial_opcodes, &eh_frame_data_);
- std::vector<uintptr_t> eh_frame_patches;
- WriteEhFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
- opcodes.data(), &eh_frame_data_, &eh_frame_patches);
+ WriteDebugFrameCIE(is64bit, DW_EH_PE_absptr, Reg(16),
+ initial_opcodes, kCFIFormat, &debug_frame_data_);
+ std::vector<uintptr_t> debug_frame_patches;
+ WriteDebugFrameFDE(is64bit, 0, 0x0100000000000000, 0x0200000000000000,
+ opcodes.data(), kCFIFormat, &debug_frame_data_, &debug_frame_patches);
CheckObjdumpOutput(is64bit, "-W");
}
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 230ebe3..3afb5ea 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -69,7 +69,7 @@
RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0);
+ RawSection debug_frame(".debug_frame", SHT_PROGBITS, 0, nullptr, 0, 8, 0);
if (!debug_info_data_.empty()) {
debug_info.SetBuffer(debug_info_data_);
builder.RegisterSection(&debug_info);
@@ -86,9 +86,9 @@
debug_line.SetBuffer(debug_line_data_);
builder.RegisterSection(&debug_line);
}
- if (!eh_frame_data_.empty()) {
- eh_frame.SetBuffer(eh_frame_data_);
- builder.RegisterSection(&eh_frame);
+ if (!debug_frame_data_.empty()) {
+ debug_frame.SetBuffer(debug_frame_data_);
+ builder.RegisterSection(&debug_frame);
}
ScratchFile file;
builder.Write(file.GetFile());
@@ -167,7 +167,7 @@
}
// Buffers which are going to assembled into ELF file and passed to objdump.
- std::vector<uint8_t> eh_frame_data_;
+ std::vector<uint8_t> debug_frame_data_;
std::vector<uint8_t> debug_info_data_;
std::vector<uint8_t> debug_abbrev_data_;
std::vector<uint8_t> debug_str_data_;
diff --git a/compiler/dwarf/headers.h b/compiler/dwarf/headers.h
index 9f64766..ad315ee 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/dwarf/headers.h
@@ -35,17 +35,18 @@
// and compilers are expected *not* to use it by default.
// In particular, it is not related to machine architecture.
-// Write common information entry (CIE) to .eh_frame section.
+// Write common information entry (CIE) to .debug_frame or .eh_frame section.
template<typename Allocator>
-void WriteEhFrameCIE(bool is64bit,
- ExceptionHeaderValueApplication address_type,
- Reg return_address_register,
- const DebugFrameOpCodeWriter<Allocator>& opcodes,
- std::vector<uint8_t>* eh_frame) {
- Writer<> writer(eh_frame);
+void WriteDebugFrameCIE(bool is64bit,
+ ExceptionHeaderValueApplication address_type,
+ Reg return_address_register,
+ const DebugFrameOpCodeWriter<Allocator>& opcodes,
+ CFIFormat format,
+ std::vector<uint8_t>* debug_frame) {
+ Writer<> writer(debug_frame);
size_t cie_header_start_ = writer.data()->size();
writer.PushUint32(0); // Length placeholder.
- writer.PushUint32(0); // CIE id.
+ writer.PushUint32((format == DW_EH_FRAME_FORMAT) ? 0 : 0xFFFFFFFF); // CIE id.
writer.PushUint8(1); // Version.
writer.PushString("zR");
writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor);
@@ -62,20 +63,26 @@
writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4);
}
-// Write frame description entry (FDE) to .eh_frame section.
+// Write frame description entry (FDE) to .debug_frame or .eh_frame section.
template<typename Allocator>
-void WriteEhFrameFDE(bool is64bit, size_t cie_offset,
- uint64_t initial_address, uint64_t address_range,
- const std::vector<uint8_t, Allocator>* opcodes,
- std::vector<uint8_t>* eh_frame,
- std::vector<uintptr_t>* eh_frame_patches) {
- Writer<> writer(eh_frame);
+void WriteDebugFrameFDE(bool is64bit, size_t cie_offset,
+ uint64_t initial_address, uint64_t address_range,
+ const std::vector<uint8_t, Allocator>* opcodes,
+ CFIFormat format,
+ std::vector<uint8_t>* debug_frame,
+ std::vector<uintptr_t>* debug_frame_patches) {
+ Writer<> writer(debug_frame);
size_t fde_header_start = writer.data()->size();
writer.PushUint32(0); // Length placeholder.
- uint32_t cie_pointer = writer.data()->size() - cie_offset;
- writer.PushUint32(cie_pointer);
+ if (format == DW_EH_FRAME_FORMAT) {
+ uint32_t cie_pointer = writer.data()->size() - cie_offset;
+ writer.PushUint32(cie_pointer);
+ } else {
+ uint32_t cie_pointer = cie_offset;
+ writer.PushUint32(cie_pointer);
+ }
// Relocate initial_address, but not address_range (it is size).
- eh_frame_patches->push_back(writer.data()->size());
+ debug_frame_patches->push_back(writer.data()->size());
if (is64bit) {
writer.PushUint64(initial_address);
writer.PushUint64(address_range);
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 63d3a0d..972bd08 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -56,12 +56,12 @@
public:
Section(const std::string& name, Elf_Word type, Elf_Word flags,
const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize)
- : header_(), section_index_(0), name_(name), link_(link) {
- header_.sh_type = type;
- header_.sh_flags = flags;
- header_.sh_info = info;
- header_.sh_addralign = align;
- header_.sh_entsize = entsize;
+ : header_(new Elf_Shdr()), section_index_(0), name_(name), link_(link) {
+ header_->sh_type = type;
+ header_->sh_flags = flags;
+ header_->sh_info = info;
+ header_->sh_addralign = align;
+ header_->sh_entsize = entsize;
}
virtual ~Section() {}
@@ -79,11 +79,11 @@
}
const Elf_Shdr* GetHeader() const {
- return &header_;
+ return header_.get();
}
Elf_Shdr* GetHeader() {
- return &header_;
+ return header_.get();
}
Elf_Word GetSectionIndex() const {
@@ -100,7 +100,9 @@
}
private:
- Elf_Shdr header_;
+ // Elf_Shdr is somewhat large so allocate it on the heap.
+ // Otherwise we get in trouble with stack frame sizes.
+ std::unique_ptr<Elf_Shdr> header_;
Elf_Word section_index_;
const std::string name_;
const Section* const link_;
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 5e9cf76..a1aabc3 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -29,9 +29,10 @@
namespace art {
namespace dwarf {
-static void WriteEhFrameCIE(InstructionSet isa,
- ExceptionHeaderValueApplication addr_type,
- std::vector<uint8_t>* eh_frame) {
+static void WriteDebugFrameCIE(InstructionSet isa,
+ ExceptionHeaderValueApplication addr_type,
+ CFIFormat format,
+ std::vector<uint8_t>* eh_frame) {
// Scratch registers should be marked as undefined. This tells the
// debugger that its value in the previous frame is not recoverable.
bool is64bit = Is64BitInstructionSet(isa);
@@ -57,7 +58,8 @@
}
}
auto return_reg = Reg::ArmCore(14); // R14(LR).
- WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+ WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+ opcodes, format, eh_frame);
return;
}
case kArm64: {
@@ -80,7 +82,8 @@
}
}
auto return_reg = Reg::Arm64Core(30); // R30(LR).
- WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+ WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+ opcodes, format, eh_frame);
return;
}
case kMips:
@@ -96,7 +99,8 @@
}
}
auto return_reg = Reg::MipsCore(31); // R31(RA).
- WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+ WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+ opcodes, format, eh_frame);
return;
}
case kX86: {
@@ -122,7 +126,8 @@
}
}
auto return_reg = Reg::X86Core(8); // R8(EIP).
- WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+ WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+ opcodes, format, eh_frame);
return;
}
case kX86_64: {
@@ -148,7 +153,8 @@
}
}
auto return_reg = Reg::X86_64Core(16); // R16(RIP).
- WriteEhFrameCIE(is64bit, addr_type, return_reg, opcodes, eh_frame);
+ WriteDebugFrameCIE(is64bit, addr_type, return_reg,
+ opcodes, format, eh_frame);
return;
}
case kNone:
@@ -158,58 +164,61 @@
UNREACHABLE();
}
-void WriteEhFrame(const CompilerDriver* compiler,
- const OatWriter* oat_writer,
- ExceptionHeaderValueApplication address_type,
- std::vector<uint8_t>* eh_frame,
- std::vector<uintptr_t>* eh_frame_patches,
- std::vector<uint8_t>* eh_frame_hdr,
- std::vector<uintptr_t>* eh_frame_hdr_patches) {
+void WriteCFISection(const CompilerDriver* compiler,
+ const OatWriter* oat_writer,
+ ExceptionHeaderValueApplication address_type,
+ CFIFormat format,
+ std::vector<uint8_t>* debug_frame,
+ std::vector<uintptr_t>* debug_frame_patches,
+ std::vector<uint8_t>* eh_frame_hdr,
+ std::vector<uintptr_t>* eh_frame_hdr_patches) {
const auto& method_infos = oat_writer->GetMethodDebugInfo();
const InstructionSet isa = compiler->GetInstructionSet();
- // Write .eh_frame section.
+ // Write .eh_frame/.debug_frame section.
std::map<uint32_t, size_t> address_to_fde_offset_map;
- size_t cie_offset = eh_frame->size();
- WriteEhFrameCIE(isa, address_type, eh_frame);
+ size_t cie_offset = debug_frame->size();
+ WriteDebugFrameCIE(isa, address_type, format, debug_frame);
for (const OatWriter::DebugInfo& mi : method_infos) {
if (!mi.deduped_) { // Only one FDE per unique address.
const SwapVector<uint8_t>* opcodes = mi.compiled_method_->GetCFIInfo();
if (opcodes != nullptr) {
- address_to_fde_offset_map.emplace(mi.low_pc_, eh_frame->size());
- WriteEhFrameFDE(Is64BitInstructionSet(isa), cie_offset,
- mi.low_pc_, mi.high_pc_ - mi.low_pc_,
- opcodes, eh_frame, eh_frame_patches);
+ address_to_fde_offset_map.emplace(mi.low_pc_, debug_frame->size());
+ WriteDebugFrameFDE(Is64BitInstructionSet(isa), cie_offset,
+ mi.low_pc_, mi.high_pc_ - mi.low_pc_,
+ opcodes, format, debug_frame, debug_frame_patches);
}
}
}
- // Write .eh_frame_hdr section.
- Writer<> header(eh_frame_hdr);
- header.PushUint8(1); // Version.
- // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
- // so we have to use pcrel which means relative to the pointer's location.
- header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
- // Encoding of binary search table size.
- header.PushUint8(DW_EH_PE_udata4);
- // Encoding of binary search table addresses - libunwind supports only this
- // specific combination, which means relative to the start of .eh_frame_hdr.
- header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
- // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section
- const int32_t relative_eh_frame_begin = -static_cast<int32_t>(eh_frame->size());
- header.PushInt32(relative_eh_frame_begin - 4U);
- // Binary search table size (number of entries).
- header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size()));
- // Binary search table.
- for (const auto& address_to_fde_offset : address_to_fde_offset_map) {
- u_int32_t code_address = address_to_fde_offset.first;
- int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second);
- eh_frame_hdr_patches->push_back(header.data()->size());
- header.PushUint32(code_address);
- // We know the exact layout (eh_frame is immediately before eh_frame_hdr)
- // and the data is relative to the start of the eh_frame_hdr,
- // so patching isn't necessary (in contrast to the code address above).
- header.PushInt32(relative_eh_frame_begin + fde_address);
+ if (format == DW_EH_FRAME_FORMAT) {
+ // Write .eh_frame_hdr section.
+ Writer<> header(eh_frame_hdr);
+ header.PushUint8(1); // Version.
+ // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
+ // so we have to use pcrel which means relative to the pointer's location.
+ header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
+ // Encoding of binary search table size.
+ header.PushUint8(DW_EH_PE_udata4);
+ // Encoding of binary search table addresses - libunwind supports only this
+ // specific combination, which means relative to the start of .eh_frame_hdr.
+ header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
+ // .eh_frame pointer - .eh_frame_hdr section is after .eh_frame section
+ const int32_t relative_eh_frame_begin = -static_cast<int32_t>(debug_frame->size());
+ header.PushInt32(relative_eh_frame_begin - 4U);
+ // Binary search table size (number of entries).
+ header.PushUint32(dchecked_integral_cast<uint32_t>(address_to_fde_offset_map.size()));
+ // Binary search table.
+ for (const auto& address_to_fde_offset : address_to_fde_offset_map) {
+ u_int32_t code_address = address_to_fde_offset.first;
+ int32_t fde_address = dchecked_integral_cast<int32_t>(address_to_fde_offset.second);
+ eh_frame_hdr_patches->push_back(header.data()->size());
+ header.PushUint32(code_address);
+ // We know the exact layout (eh_frame is immediately before eh_frame_hdr)
+ // and the data is relative to the start of the eh_frame_hdr,
+ // so patching isn't necessary (in contrast to the code address above).
+ header.PushInt32(relative_eh_frame_begin + fde_address);
+ }
}
}
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index 28d0e2c..69f7e0d 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -25,13 +25,14 @@
namespace art {
namespace dwarf {
-void WriteEhFrame(const CompilerDriver* compiler,
- const OatWriter* oat_writer,
- ExceptionHeaderValueApplication address_type,
- std::vector<uint8_t>* eh_frame,
- std::vector<uintptr_t>* eh_frame_patches,
- std::vector<uint8_t>* eh_frame_hdr,
- std::vector<uintptr_t>* eh_frame_hdr_patches);
+void WriteCFISection(const CompilerDriver* compiler,
+ const OatWriter* oat_writer,
+ ExceptionHeaderValueApplication address_type,
+ CFIFormat format,
+ std::vector<uint8_t>* debug_frame,
+ std::vector<uintptr_t>* debug_frame_patches,
+ std::vector<uint8_t>* eh_frame_hdr,
+ std::vector<uintptr_t>* eh_frame_hdr_patches);
void WriteDebugSections(const CompilerDriver* compiler,
const OatWriter* oat_writer,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 79f9955..96dd7ca 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -37,6 +37,14 @@
namespace art {
+// .eh_frame and .debug_frame are almost identical.
+// Except for some minor formatting differences, the main difference
+// is that .eh_frame is allocated within the running program because
+// it is used by C++ exception handling (which we do not use so we
+// can choose either). C++ compilers generally tend to use .eh_frame
+// because if they need it sometimes, they might as well always use it.
+constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_EH_FRAME_FORMAT;
+
template <typename ElfTypes>
bool ElfWriterQuick<ElfTypes>::Create(File* elf_file,
OatWriter* oat_writer,
@@ -161,12 +169,17 @@
using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
const auto* text = builder->GetText();
const bool is64bit = Is64BitInstructionSet(isa);
+ const int pointer_size = GetInstructionSetPointerSize(isa);
RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0,
is64bit ? Patch<Elf_Addr, uint64_t, kPointerRelativeAddress> :
Patch<Elf_Addr, uint32_t, kPointerRelativeAddress>,
text);
RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0,
Patch<Elf_Addr, uint32_t, kSectionRelativeAddress>, text);
+ RawSection debug_frame(".debug_frame", SHT_PROGBITS, 0, nullptr, 0, pointer_size, 0,
+ is64bit ? Patch<Elf_Addr, uint64_t, kAbsoluteAddress> :
+ Patch<Elf_Addr, uint32_t, kAbsoluteAddress>,
+ text);
RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0,
Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
@@ -175,12 +188,25 @@
Patch<Elf_Addr, uint32_t, kAbsoluteAddress>, text);
if (!oat_writer->GetMethodDebugInfo().empty()) {
if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
- dwarf::WriteEhFrame(
- compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel,
- eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
- eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations());
- builder->RegisterSection(&eh_frame);
- builder->RegisterSection(&eh_frame_hdr);
+ if (kCFIFormat == dwarf::DW_EH_FRAME_FORMAT) {
+ dwarf::WriteCFISection(
+ compiler_driver_, oat_writer,
+ dwarf::DW_EH_PE_pcrel, kCFIFormat,
+ eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
+ eh_frame_hdr.GetBuffer(), eh_frame_hdr.GetPatchLocations());
+ builder->RegisterSection(&eh_frame);
+ builder->RegisterSection(&eh_frame_hdr);
+ } else {
+ DCHECK(kCFIFormat == dwarf::DW_DEBUG_FRAME_FORMAT);
+ dwarf::WriteCFISection(
+ compiler_driver_, oat_writer,
+ dwarf::DW_EH_PE_absptr, kCFIFormat,
+ debug_frame.GetBuffer(), debug_frame.GetPatchLocations(),
+ nullptr, nullptr);
+ builder->RegisterSection(&debug_frame);
+ *oat_writer->GetAbsolutePatchLocationsFor(".debug_frame") =
+ *debug_frame.GetPatchLocations();
+ }
}
if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
// Add methods to .symtab.
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index a5c6f23..c4eaabf 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -539,11 +539,6 @@
}
static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) {
- // dex compilation unit is null only when unit testing.
- if (cu == nullptr) {
- return false;
- }
-
Thread* self = Thread::Current();
return cu->IsConstructor()
&& driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex());
@@ -551,9 +546,12 @@
void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
if (type == Primitive::kPrimVoid) {
- // Note that we might insert redundant barriers when inlining `super` calls.
- // TODO: add a data flow analysis to get rid of duplicate barriers.
- if (RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_)) {
+ if (graph_->ShouldGenerateConstructorBarrier()) {
+ // The compilation unit is null during testing.
+ if (dex_compilation_unit_ != nullptr) {
+ DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_))
+ << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier.";
+ }
current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore));
}
current_block_->AddInstruction(new (arena_) HReturnVoid());
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 0e776b3..4805cee 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -645,23 +645,34 @@
}
}
+ uint32_t outer_dex_pc = dex_pc;
+ uint32_t outer_environment_size = 0;
+ uint32_t inlining_depth = 0;
+ if (instruction != nullptr) {
+ for (HEnvironment* environment = instruction->GetEnvironment();
+ environment != nullptr;
+ environment = environment->GetParent()) {
+ outer_dex_pc = environment->GetDexPc();
+ outer_environment_size = environment->Size();
+ if (environment != instruction->GetEnvironment()) {
+ inlining_depth++;
+ }
+ }
+ }
+
// Collect PC infos for the mapping table.
struct PcInfo pc_info;
- pc_info.dex_pc = dex_pc;
+ pc_info.dex_pc = outer_dex_pc;
pc_info.native_pc = GetAssembler()->CodeSize();
pc_infos_.Add(pc_info);
- uint32_t inlining_depth = 0;
-
if (instruction == nullptr) {
// For stack overflow checks.
- stack_map_stream_.BeginStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, inlining_depth);
+ stack_map_stream_.BeginStackMapEntry(pc_info.dex_pc, pc_info.native_pc, 0, 0, 0, 0);
stack_map_stream_.EndStackMapEntry();
return;
}
LocationSummary* locations = instruction->GetLocations();
- HEnvironment* environment = instruction->GetEnvironment();
- size_t environment_size = instruction->EnvironmentSize();
uint32_t register_mask = locations->GetRegisterMask();
if (locations->OnlyCallsOnSlowPath()) {
@@ -674,23 +685,32 @@
}
// The register mask must be a subset of callee-save registers.
DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
- stack_map_stream_.BeginStackMapEntry(dex_pc,
+ stack_map_stream_.BeginStackMapEntry(pc_info.dex_pc,
pc_info.native_pc,
register_mask,
locations->GetStackMask(),
- environment_size,
+ outer_environment_size,
inlining_depth);
- if (environment != nullptr) {
- // TODO: Handle parent environment.
- DCHECK(environment->GetParent() == nullptr);
- DCHECK_EQ(environment->GetDexPc(), dex_pc);
+
+ EmitEnvironment(instruction->GetEnvironment(), slow_path);
+ stack_map_stream_.EndStackMapEntry();
+}
+
+void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path) {
+ if (environment == nullptr) return;
+
+ if (environment->GetParent() != nullptr) {
+ // We emit the parent environment first.
+ EmitEnvironment(environment->GetParent(), slow_path);
+ stack_map_stream_.BeginInlineInfoEntry(
+ environment->GetMethodIdx(), environment->GetDexPc(), environment->Size());
}
// Walk over the environment, and record the location of dex registers.
- for (size_t i = 0; i < environment_size; ++i) {
+ for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
HInstruction* current = environment->GetInstructionAt(i);
if (current == nullptr) {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
continue;
}
@@ -701,41 +721,44 @@
if (current->IsLongConstant()) {
int64_t value = current->AsLongConstant()->GetValue();
stack_map_stream_.AddDexRegisterEntry(
- i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+ DexRegisterLocation::Kind::kConstant, Low32Bits(value));
stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+ DexRegisterLocation::Kind::kConstant, High32Bits(value));
+ ++i;
DCHECK_LT(i, environment_size);
} else if (current->IsDoubleConstant()) {
int64_t value = bit_cast<int64_t, double>(current->AsDoubleConstant()->GetValue());
stack_map_stream_.AddDexRegisterEntry(
- i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+ DexRegisterLocation::Kind::kConstant, Low32Bits(value));
stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+ DexRegisterLocation::Kind::kConstant, High32Bits(value));
+ ++i;
DCHECK_LT(i, environment_size);
} else if (current->IsIntConstant()) {
int32_t value = current->AsIntConstant()->GetValue();
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
} else if (current->IsNullConstant()) {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, 0);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
} else {
DCHECK(current->IsFloatConstant()) << current->DebugName();
int32_t value = bit_cast<int32_t, float>(current->AsFloatConstant()->GetValue());
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
}
break;
}
case Location::kStackSlot: {
stack_map_stream_.AddDexRegisterEntry(
- i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+ DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
break;
}
case Location::kDoubleStackSlot: {
stack_map_stream_.AddDexRegisterEntry(
- i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+ DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+ DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+ ++i;
DCHECK_LT(i, environment_size);
break;
}
@@ -744,16 +767,18 @@
int id = location.reg();
if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(id)) {
uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(id);
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
if (current->GetType() == Primitive::kPrimLong) {
stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+ DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+ ++i;
DCHECK_LT(i, environment_size);
}
} else {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, id);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
if (current->GetType() == Primitive::kPrimLong) {
- stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInRegister, id);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
+ ++i;
DCHECK_LT(i, environment_size);
}
}
@@ -764,17 +789,18 @@
int id = location.reg();
if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(id)) {
uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(id);
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
if (current->GetType() == Primitive::kPrimDouble) {
stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+ DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+ ++i;
DCHECK_LT(i, environment_size);
}
} else {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, id);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
if (current->GetType() == Primitive::kPrimDouble) {
- stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInFpuRegister, id);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
+ ++i;
DCHECK_LT(i, environment_size);
}
}
@@ -786,16 +812,17 @@
int high = location.high();
if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(low)) {
uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(low);
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
} else {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, low);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, low);
}
if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(high)) {
uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(high);
- stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
+ ++i;
} else {
- stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInFpuRegister, high);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, high);
+ ++i;
}
DCHECK_LT(i, environment_size);
break;
@@ -806,23 +833,23 @@
int high = location.high();
if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(low)) {
uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(low);
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
} else {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, low);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, low);
}
if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(high)) {
uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(high);
- stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
} else {
- stack_map_stream_.AddDexRegisterEntry(
- ++i, DexRegisterLocation::Kind::kInRegister, high);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, high);
}
+ ++i;
DCHECK_LT(i, environment_size);
break;
}
case Location::kInvalid: {
- stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
break;
}
@@ -830,7 +857,10 @@
LOG(FATAL) << "Unexpected kind " << location.GetKind();
}
}
- stack_map_stream_.EndStackMapEntry();
+
+ if (environment->GetParent() != nullptr) {
+ stack_map_stream_.EndInlineInfoEntry();
+ }
}
bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index fcfedab..740beab 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -82,8 +82,8 @@
virtual void EmitNativeCode(CodeGenerator* codegen) = 0;
- void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
- void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+ virtual void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+ virtual void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
void RecordPcInfo(CodeGenerator* codegen, HInstruction* instruction, uint32_t dex_pc);
bool IsCoreRegisterSaved(int reg) const {
@@ -102,11 +102,13 @@
return saved_fpu_stack_offsets_[reg];
}
- private:
+ protected:
static constexpr size_t kMaximumNumberOfExpectedRegisters = 32;
static constexpr uint32_t kRegisterNotSaved = -1;
uint32_t saved_core_stack_offsets_[kMaximumNumberOfExpectedRegisters];
uint32_t saved_fpu_stack_offsets_[kMaximumNumberOfExpectedRegisters];
+
+ private:
DISALLOW_COPY_AND_ASSIGN(SlowPathCode);
};
@@ -441,6 +443,7 @@
size_t GetStackOffsetOfSavedRegister(size_t index);
void CompileInternal(CodeAllocator* allocator, bool is_baseline);
void BlockIfInRegister(Location location, bool is_out = false) const;
+ void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
HGraph* const graph_;
const CompilerOptions& compiler_options_;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 93d0e5b..1c76630 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -17,6 +17,7 @@
#include "code_generator_arm.h"
#include "arch/arm/instruction_set_features_arm.h"
+#include "code_generator_utils.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "gc/accounting/card_table.h"
#include "intrinsics.h"
@@ -390,7 +391,7 @@
location_builder_(graph, this),
instruction_visitor_(graph, this),
move_resolver_(graph->GetArena(), this),
- assembler_(true),
+ assembler_(false /* can_relocate_branches */),
isa_features_(isa_features) {
// Save the PC register to mimic Quick.
AddAllocatedRegister(Location::RegisterLocation(PC));
@@ -2185,11 +2186,134 @@
}
}
+void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+ DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = locations->Out().AsRegister<Register>();
+ Register dividend = locations->InAt(0).AsRegister<Register>();
+ int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+ DCHECK(imm == 1 || imm == -1);
+
+ if (instruction->IsRem()) {
+ __ LoadImmediate(out, 0);
+ } else {
+ if (imm == 1) {
+ __ Mov(out, dividend);
+ } else {
+ __ rsb(out, dividend, ShifterOperand(0));
+ }
+ }
+}
+
+void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+ DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = locations->Out().AsRegister<Register>();
+ Register dividend = locations->InAt(0).AsRegister<Register>();
+ Register temp = locations->GetTemp(0).AsRegister<Register>();
+ int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+ int32_t abs_imm = std::abs(imm);
+ DCHECK(IsPowerOfTwo(abs_imm));
+ int ctz_imm = CTZ(abs_imm);
+
+ if (ctz_imm == 1) {
+ __ Lsr(temp, dividend, 32 - ctz_imm);
+ } else {
+ __ Asr(temp, dividend, 31);
+ __ Lsr(temp, temp, 32 - ctz_imm);
+ }
+ __ add(out, temp, ShifterOperand(dividend));
+
+ if (instruction->IsDiv()) {
+ __ Asr(out, out, ctz_imm);
+ if (imm < 0) {
+ __ rsb(out, out, ShifterOperand(0));
+ }
+ } else {
+ __ ubfx(out, out, 0, ctz_imm);
+ __ sub(out, out, ShifterOperand(temp));
+ }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+ DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = locations->Out().AsRegister<Register>();
+ Register dividend = locations->InAt(0).AsRegister<Register>();
+ Register temp1 = locations->GetTemp(0).AsRegister<Register>();
+ Register temp2 = locations->GetTemp(1).AsRegister<Register>();
+ int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+
+ int64_t magic;
+ int shift;
+ CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
+
+ __ LoadImmediate(temp1, magic);
+ __ smull(temp2, temp1, dividend, temp1);
+
+ if (imm > 0 && magic < 0) {
+ __ add(temp1, temp1, ShifterOperand(dividend));
+ } else if (imm < 0 && magic > 0) {
+ __ sub(temp1, temp1, ShifterOperand(dividend));
+ }
+
+ if (shift != 0) {
+ __ Asr(temp1, temp1, shift);
+ }
+
+ if (instruction->IsDiv()) {
+ __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
+ } else {
+ __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
+ // TODO: Strength reduction for mls.
+ __ LoadImmediate(temp2, imm);
+ __ mls(out, temp1, temp2, dividend);
+ }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+ DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+ if (imm == 0) {
+ // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+ } else if (imm == 1 || imm == -1) {
+ DivRemOneOrMinusOne(instruction);
+ } else if (IsPowerOfTwo(std::abs(imm))) {
+ DivRemByPowerOfTwo(instruction);
+ } else {
+ DCHECK(imm <= -2 || imm >= 2);
+ GenerateDivRemWithAnyConstant(instruction);
+ }
+}
+
void LocationsBuilderARM::VisitDiv(HDiv* div) {
LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
if (div->GetResultType() == Primitive::kPrimLong) {
// pLdiv runtime call.
call_kind = LocationSummary::kCall;
+ } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
+ // sdiv will be replaced by other instruction sequence.
} else if (div->GetResultType() == Primitive::kPrimInt &&
!codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
// pIdivmod runtime call.
@@ -2200,7 +2324,20 @@
switch (div->GetResultType()) {
case Primitive::kPrimInt: {
- if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ if (div->InputAt(1)->IsConstant()) {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
+ if (abs_imm <= 1) {
+ // No temp register required.
+ } else {
+ locations->AddTemp(Location::RequiresRegister());
+ if (!IsPowerOfTwo(abs_imm)) {
+ locations->AddTemp(Location::RequiresRegister());
+ }
+ }
+ } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2244,7 +2381,9 @@
switch (div->GetResultType()) {
case Primitive::kPrimInt: {
- if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ if (second.IsConstant()) {
+ GenerateDivRemConstantIntegral(div);
+ } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
__ sdiv(out.AsRegister<Register>(),
first.AsRegister<Register>(),
second.AsRegister<Register>());
@@ -2296,8 +2435,11 @@
// Most remainders are implemented in the runtime.
LocationSummary::CallKind call_kind = LocationSummary::kCall;
- if (rem->GetResultType() == Primitive::kPrimInt &&
- codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
+ // sdiv will be replaced by other instruction sequence.
+ call_kind = LocationSummary::kNoCall;
+ } else if ((rem->GetResultType() == Primitive::kPrimInt)
+ && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
// Have hardware divide instruction for int, do it with three instructions.
call_kind = LocationSummary::kNoCall;
}
@@ -2306,7 +2448,20 @@
switch (type) {
case Primitive::kPrimInt: {
- if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ if (rem->InputAt(1)->IsConstant()) {
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
+ if (abs_imm <= 1) {
+ // No temp register required.
+ } else {
+ locations->AddTemp(Location::RequiresRegister());
+ if (!IsPowerOfTwo(abs_imm)) {
+ locations->AddTemp(Location::RequiresRegister());
+ }
+ }
+ } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2363,7 +2518,9 @@
Primitive::Type type = rem->GetResultType();
switch (type) {
case Primitive::kPrimInt: {
- if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+ if (second.IsConstant()) {
+ GenerateDivRemConstantIntegral(rem);
+ } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
Register reg1 = first.AsRegister<Register>();
Register reg2 = second.AsRegister<Register>();
Register temp = locations->GetTemp(0).AsRegister<Register>();
@@ -2880,7 +3037,8 @@
}
void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
- const FieldInfo& field_info) {
+ const FieldInfo& field_info,
+ bool value_can_be_null) {
DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
LocationSummary* locations = instruction->GetLocations();
@@ -2969,7 +3127,8 @@
if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+ codegen_->MarkGCCard(
+ temp, card, base, value.AsRegister<Register>(), value_can_be_null);
}
if (is_volatile) {
@@ -3096,7 +3255,7 @@
}
void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3120,7 +3279,7 @@
}
void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3390,7 +3549,7 @@
DCHECK_EQ(value_type, Primitive::kPrimNot);
Register temp = locations->GetTemp(0).AsRegister<Register>();
Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, obj, value);
+ codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
}
} else {
DCHECK_EQ(value_type, Primitive::kPrimNot);
@@ -3495,13 +3654,21 @@
__ b(slow_path->GetEntryLabel(), CS);
}
-void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorARM::MarkGCCard(Register temp,
+ Register card,
+ Register object,
+ Register value,
+ bool can_be_null) {
Label is_null;
- __ CompareAndBranchIfZero(value, &is_null);
+ if (can_be_null) {
+ __ CompareAndBranchIfZero(value, &is_null);
+ }
__ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
__ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
__ strb(card, Address(card, temp));
- __ Bind(&is_null);
+ if (can_be_null) {
+ __ Bind(&is_null);
+ }
}
void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 1a498e1..071bbee 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -181,7 +181,9 @@
HInstruction* instruction);
void GenerateWideAtomicLoad(Register addr, uint32_t offset,
Register out_lo, Register out_hi);
- void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+ void HandleFieldSet(HInstruction* instruction,
+ const FieldInfo& field_info,
+ bool value_can_be_null);
void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
void GenerateImplicitNullCheck(HNullCheck* instruction);
void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -189,6 +191,10 @@
Label* true_target,
Label* false_target,
Label* always_true_target);
+ void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+ void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+ void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+ void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
ArmAssembler* const assembler_;
CodeGeneratorARM* const codegen_;
@@ -270,7 +276,7 @@
int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path);
// Emit a write barrier.
- void MarkGCCard(Register temp, Register card, Register object, Register value);
+ void MarkGCCard(Register temp, Register card, Register object, Register value, bool can_be_null);
Label* GetLabelOf(HBasicBlock* block) const {
return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 0a0902b..b6d99ab 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -17,6 +17,7 @@
#include "code_generator_arm64.h"
#include "arch/arm64/instruction_set_features_arm64.h"
+#include "code_generator_utils.h"
#include "common_arm64.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
@@ -64,6 +65,7 @@
using helpers::WRegisterFrom;
using helpers::XRegisterFrom;
using helpers::ARM64EncodableConstantOrRegister;
+using helpers::ArtVixlRegCodeCoherentForRegSet;
static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>);
static constexpr int kCurrentMethodStackOffset = 0;
@@ -105,6 +107,88 @@
#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
+// Calculate memory accessing operand for save/restore live registers.
+static void SaveRestoreLiveRegistersHelper(CodeGenerator* codegen,
+ RegisterSet* register_set,
+ int64_t spill_offset,
+ bool is_save) {
+ DCHECK(ArtVixlRegCodeCoherentForRegSet(register_set->GetCoreRegisters(),
+ codegen->GetNumberOfCoreRegisters(),
+ register_set->GetFloatingPointRegisters(),
+ codegen->GetNumberOfFloatingPointRegisters()));
+
+ CPURegList core_list = CPURegList(CPURegister::kRegister, kXRegSize,
+ register_set->GetCoreRegisters() & (~callee_saved_core_registers.list()));
+ CPURegList fp_list = CPURegList(CPURegister::kFPRegister, kDRegSize,
+ register_set->GetFloatingPointRegisters() & (~callee_saved_fp_registers.list()));
+
+ MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler();
+ UseScratchRegisterScope temps(masm);
+
+ Register base = masm->StackPointer();
+ int64_t core_spill_size = core_list.TotalSizeInBytes();
+ int64_t fp_spill_size = fp_list.TotalSizeInBytes();
+ int64_t reg_size = kXRegSizeInBytes;
+ int64_t max_ls_pair_offset = spill_offset + core_spill_size + fp_spill_size - 2 * reg_size;
+ uint32_t ls_access_size = WhichPowerOf2(reg_size);
+ if (((core_list.Count() > 1) || (fp_list.Count() > 1)) &&
+ !masm->IsImmLSPair(max_ls_pair_offset, ls_access_size)) {
+ // If the offset does not fit in the instruction's immediate field, use an alternate register
+ // to compute the base address(float point registers spill base address).
+ Register new_base = temps.AcquireSameSizeAs(base);
+ __ Add(new_base, base, Operand(spill_offset + core_spill_size));
+ base = new_base;
+ spill_offset = -core_spill_size;
+ int64_t new_max_ls_pair_offset = fp_spill_size - 2 * reg_size;
+ DCHECK(masm->IsImmLSPair(spill_offset, ls_access_size));
+ DCHECK(masm->IsImmLSPair(new_max_ls_pair_offset, ls_access_size));
+ }
+
+ if (is_save) {
+ __ StoreCPURegList(core_list, MemOperand(base, spill_offset));
+ __ StoreCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+ } else {
+ __ LoadCPURegList(core_list, MemOperand(base, spill_offset));
+ __ LoadCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+ }
+}
+
+void SlowPathCodeARM64::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+ RegisterSet* register_set = locations->GetLiveRegisters();
+ size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
+ for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
+ if (!codegen->IsCoreCalleeSaveRegister(i) && register_set->ContainsCoreRegister(i)) {
+ // If the register holds an object, update the stack mask.
+ if (locations->RegisterContainsObject(i)) {
+ locations->SetStackBit(stack_offset / kVRegSize);
+ }
+ DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+ DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+ saved_core_stack_offsets_[i] = stack_offset;
+ stack_offset += kXRegSizeInBytes;
+ }
+ }
+
+ for (size_t i = 0, e = codegen->GetNumberOfFloatingPointRegisters(); i < e; ++i) {
+ if (!codegen->IsFloatingPointCalleeSaveRegister(i) &&
+ register_set->ContainsFloatingPointRegister(i)) {
+ DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+ DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+ saved_fpu_stack_offsets_[i] = stack_offset;
+ stack_offset += kDRegSizeInBytes;
+ }
+ }
+
+ SaveRestoreLiveRegistersHelper(codegen, register_set,
+ codegen->GetFirstRegisterSlotInSlowPath(), true /* is_save */);
+}
+
+void SlowPathCodeARM64::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+ RegisterSet* register_set = locations->GetLiveRegisters();
+ SaveRestoreLiveRegistersHelper(codegen, register_set,
+ codegen->GetFirstRegisterSlotInSlowPath(), false /* is_save */);
+}
+
class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
public:
BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
@@ -529,6 +613,19 @@
GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
}
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedCoreRegisters() const {
+ DCHECK(ArtVixlRegCodeCoherentForRegSet(core_spill_mask_, GetNumberOfCoreRegisters(), 0, 0));
+ return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
+ core_spill_mask_);
+}
+
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedFPRegisters() const {
+ DCHECK(ArtVixlRegCodeCoherentForRegSet(0, 0, fpu_spill_mask_,
+ GetNumberOfFloatingPointRegisters()));
+ return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
+ fpu_spill_mask_);
+}
+
void CodeGeneratorARM64::Bind(HBasicBlock* block) {
__ Bind(GetLabelOf(block));
}
@@ -604,16 +701,20 @@
return Location::NoLocation();
}
-void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
+void CodeGeneratorARM64::MarkGCCard(Register object, Register value, bool value_can_be_null) {
UseScratchRegisterScope temps(GetVIXLAssembler());
Register card = temps.AcquireX();
Register temp = temps.AcquireW(); // Index within the CardTable - 32bit.
vixl::Label done;
- __ Cbz(value, &done);
+ if (value_can_be_null) {
+ __ Cbz(value, &done);
+ }
__ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
__ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
__ Strb(card, MemOperand(card, temp.X()));
- __ Bind(&done);
+ if (value_can_be_null) {
+ __ Bind(&done);
+ }
}
void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline) const {
@@ -1168,7 +1269,8 @@
}
void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
- const FieldInfo& field_info) {
+ const FieldInfo& field_info,
+ bool value_can_be_null) {
DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
BlockPoolsScope block_pools(GetVIXLAssembler());
@@ -1194,7 +1296,7 @@
}
if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
- codegen_->MarkGCCard(obj, Register(value));
+ codegen_->MarkGCCard(obj, Register(value), value_can_be_null);
}
}
@@ -1420,7 +1522,7 @@
codegen_->MaybeRecordImplicitNullCheck(instruction);
}
if (CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue())) {
- codegen_->MarkGCCard(obj, value.W());
+ codegen_->MarkGCCard(obj, value.W(), instruction->GetValueCanBeNull());
}
}
}
@@ -1603,6 +1705,152 @@
#undef DEFINE_CONDITION_VISITORS
#undef FOR_EACH_CONDITION_INSTRUCTION
+void InstructionCodeGeneratorARM64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = OutputRegister(instruction);
+ Register dividend = InputRegisterAt(instruction, 0);
+ int64_t imm = Int64FromConstant(second.GetConstant());
+ DCHECK(imm == 1 || imm == -1);
+
+ if (instruction->IsRem()) {
+ __ Mov(out, 0);
+ } else {
+ if (imm == 1) {
+ __ Mov(out, dividend);
+ } else {
+ __ Neg(out, dividend);
+ }
+ }
+}
+
+void InstructionCodeGeneratorARM64::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = OutputRegister(instruction);
+ Register dividend = InputRegisterAt(instruction, 0);
+ int64_t imm = Int64FromConstant(second.GetConstant());
+ int64_t abs_imm = std::abs(imm);
+ DCHECK(IsPowerOfTwo(abs_imm));
+ int ctz_imm = CTZ(abs_imm);
+
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register temp = temps.AcquireSameSizeAs(out);
+
+ if (instruction->IsDiv()) {
+ __ Add(temp, dividend, abs_imm - 1);
+ __ Cmp(dividend, 0);
+ __ Csel(out, temp, dividend, lt);
+ if (imm > 0) {
+ __ Asr(out, out, ctz_imm);
+ } else {
+ __ Neg(out, Operand(out, ASR, ctz_imm));
+ }
+ } else {
+ int bits = instruction->GetResultType() == Primitive::kPrimInt ? 32 : 64;
+ __ Asr(temp, dividend, bits - 1);
+ __ Lsr(temp, temp, bits - ctz_imm);
+ __ Add(out, dividend, temp);
+ __ And(out, out, abs_imm - 1);
+ __ Sub(out, out, temp);
+ }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location second = locations->InAt(1);
+ DCHECK(second.IsConstant());
+
+ Register out = OutputRegister(instruction);
+ Register dividend = InputRegisterAt(instruction, 0);
+ int64_t imm = Int64FromConstant(second.GetConstant());
+
+ Primitive::Type type = instruction->GetResultType();
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+ int64_t magic;
+ int shift;
+ CalculateMagicAndShiftForDivRem(imm, type == Primitive::kPrimLong /* is_long */, &magic, &shift);
+
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register temp = temps.AcquireSameSizeAs(out);
+
+ // temp = get_high(dividend * magic)
+ __ Mov(temp, magic);
+ if (type == Primitive::kPrimLong) {
+ __ Smulh(temp, dividend, temp);
+ } else {
+ __ Smull(temp.X(), dividend, temp);
+ __ Lsr(temp.X(), temp.X(), 32);
+ }
+
+ if (imm > 0 && magic < 0) {
+ __ Add(temp, temp, dividend);
+ } else if (imm < 0 && magic > 0) {
+ __ Sub(temp, temp, dividend);
+ }
+
+ if (shift != 0) {
+ __ Asr(temp, temp, shift);
+ }
+
+ if (instruction->IsDiv()) {
+ __ Sub(out, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+ } else {
+ __ Sub(temp, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+ // TODO: Strength reduction for msub.
+ Register temp_imm = temps.AcquireSameSizeAs(out);
+ __ Mov(temp_imm, imm);
+ __ Msub(out, temp, temp_imm, dividend);
+ }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
+ DCHECK(instruction->IsDiv() || instruction->IsRem());
+ Primitive::Type type = instruction->GetResultType();
+ DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Register out = OutputRegister(instruction);
+ Location second = locations->InAt(1);
+
+ if (second.IsConstant()) {
+ int64_t imm = Int64FromConstant(second.GetConstant());
+
+ if (imm == 0) {
+ // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+ } else if (imm == 1 || imm == -1) {
+ DivRemOneOrMinusOne(instruction);
+ } else if (IsPowerOfTwo(std::abs(imm))) {
+ DivRemByPowerOfTwo(instruction);
+ } else {
+ DCHECK(imm <= -2 || imm >= 2);
+ GenerateDivRemWithAnyConstant(instruction);
+ }
+ } else {
+ Register dividend = InputRegisterAt(instruction, 0);
+ Register divisor = InputRegisterAt(instruction, 1);
+ if (instruction->IsDiv()) {
+ __ Sdiv(out, dividend, divisor);
+ } else {
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ Register temp = temps.AcquireSameSizeAs(out);
+ __ Sdiv(temp, dividend, divisor);
+ __ Msub(out, temp, divisor, dividend);
+ }
+ }
+}
+
void LocationsBuilderARM64::VisitDiv(HDiv* div) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
@@ -1610,7 +1858,7 @@
case Primitive::kPrimInt:
case Primitive::kPrimLong:
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
@@ -1631,7 +1879,7 @@
switch (type) {
case Primitive::kPrimInt:
case Primitive::kPrimLong:
- __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
+ GenerateDivRemIntegral(div);
break;
case Primitive::kPrimFloat:
@@ -1846,7 +2094,7 @@
}
void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
@@ -2454,7 +2702,7 @@
case Primitive::kPrimInt:
case Primitive::kPrimLong:
locations->SetInAt(0, Location::RequiresRegister());
- locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
@@ -2479,14 +2727,7 @@
switch (type) {
case Primitive::kPrimInt:
case Primitive::kPrimLong: {
- UseScratchRegisterScope temps(GetVIXLAssembler());
- Register dividend = InputRegisterAt(rem, 0);
- Register divisor = InputRegisterAt(rem, 1);
- Register output = OutputRegister(rem);
- Register temp = temps.AcquireSameSizeAs(output);
-
- __ Sdiv(temp, dividend, divisor);
- __ Msub(output, temp, divisor, dividend);
+ GenerateDivRemIntegral(rem);
break;
}
@@ -2596,7 +2837,7 @@
}
void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 8aeea54..b56ca10 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -70,6 +70,9 @@
vixl::Label* GetEntryLabel() { return &entry_label_; }
vixl::Label* GetExitLabel() { return &exit_label_; }
+ void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+ void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+
private:
vixl::Label entry_label_;
vixl::Label exit_label_;
@@ -154,7 +157,9 @@
void GenerateMemoryBarrier(MemBarrierKind kind);
void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
void HandleBinaryOp(HBinaryOperation* instr);
- void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+ void HandleFieldSet(HInstruction* instruction,
+ const FieldInfo& field_info,
+ bool value_can_be_null);
void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
void HandleShift(HBinaryOperation* instr);
void GenerateImplicitNullCheck(HNullCheck* instruction);
@@ -163,6 +168,11 @@
vixl::Label* true_target,
vixl::Label* false_target,
vixl::Label* always_true_target);
+ void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+ void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+ void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+ void GenerateDivRemIntegral(HBinaryOperation* instruction);
+
Arm64Assembler* const assembler_;
CodeGeneratorARM64* const codegen_;
@@ -227,15 +237,8 @@
void GenerateFrameEntry() OVERRIDE;
void GenerateFrameExit() OVERRIDE;
- vixl::CPURegList GetFramePreservedCoreRegisters() const {
- return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
- core_spill_mask_);
- }
-
- vixl::CPURegList GetFramePreservedFPRegisters() const {
- return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
- fpu_spill_mask_);
- }
+ vixl::CPURegList GetFramePreservedCoreRegisters() const;
+ vixl::CPURegList GetFramePreservedFPRegisters() const;
void Bind(HBasicBlock* block) OVERRIDE;
@@ -266,7 +269,7 @@
vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
// Emit a write barrier.
- void MarkGCCard(vixl::Register object, vixl::Register value);
+ void MarkGCCard(vixl::Register object, vixl::Register value, bool value_can_be_null);
// Register allocation.
@@ -277,10 +280,10 @@
Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
- size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
- size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
- size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
- size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+ size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+ size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
// The number of registers that can be allocated. The register allocator may
// decide to reserve and not use a few of them.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 0212da1..a6f01da 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3227,16 +3227,24 @@
DCHECK(!IsLeafMethod());
}
-void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorX86::MarkGCCard(Register temp,
+ Register card,
+ Register object,
+ Register value,
+ bool value_can_be_null) {
Label is_null;
- __ testl(value, value);
- __ j(kEqual, &is_null);
+ if (value_can_be_null) {
+ __ testl(value, value);
+ __ j(kEqual, &is_null);
+ }
__ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
__ movl(temp, object);
__ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
__ movb(Address(temp, card, TIMES_1, 0),
X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
- __ Bind(&is_null);
+ if (value_can_be_null) {
+ __ Bind(&is_null);
+ }
}
void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -3381,7 +3389,8 @@
}
void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
- const FieldInfo& field_info) {
+ const FieldInfo& field_info,
+ bool value_can_be_null) {
DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
LocationSummary* locations = instruction->GetLocations();
@@ -3454,7 +3463,7 @@
if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+ codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
}
if (is_volatile) {
@@ -3475,7 +3484,7 @@
}
void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -3483,7 +3492,7 @@
}
void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3817,7 +3826,8 @@
if (needs_write_barrier) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
+ codegen_->MarkGCCard(
+ temp, card, obj, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
}
} else {
DCHECK_EQ(value_type, Primitive::kPrimNot);
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 5a5a37b..28766d8 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -170,7 +170,9 @@
void GenerateShrLong(const Location& loc, int shift);
void GenerateUShrLong(const Location& loc, int shift);
void GenerateMemoryBarrier(MemBarrierKind kind);
- void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+ void HandleFieldSet(HInstruction* instruction,
+ const FieldInfo& field_info,
+ bool value_can_be_null);
void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
// Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
// `is_wide` specifies whether it is long/double or not.
@@ -260,7 +262,11 @@
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
// Emit a write barrier.
- void MarkGCCard(Register temp, Register card, Register object, Register value);
+ void MarkGCCard(Register temp,
+ Register card,
+ Register object,
+ Register value,
+ bool value_can_be_null);
void LoadCurrentMethod(Register reg);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 63d6846..f49c26d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3249,7 +3249,8 @@
}
void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
- const FieldInfo& field_info) {
+ const FieldInfo& field_info,
+ bool value_can_be_null) {
DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
LocationSummary* locations = instruction->GetLocations();
@@ -3329,7 +3330,7 @@
if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
- codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
+ codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
}
if (is_volatile) {
@@ -3342,7 +3343,7 @@
}
void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3366,7 +3367,7 @@
}
void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
- HandleFieldSet(instruction, instruction->GetFieldInfo());
+ HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
}
void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
@@ -3671,7 +3672,8 @@
DCHECK_EQ(value_type, Primitive::kPrimNot);
CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
- codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
+ codegen_->MarkGCCard(
+ temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
}
} else {
DCHECK_EQ(value_type, Primitive::kPrimNot);
@@ -3816,16 +3818,21 @@
void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
CpuRegister card,
CpuRegister object,
- CpuRegister value) {
+ CpuRegister value,
+ bool value_can_be_null) {
Label is_null;
- __ testl(value, value);
- __ j(kEqual, &is_null);
+ if (value_can_be_null) {
+ __ testl(value, value);
+ __ j(kEqual, &is_null);
+ }
__ gs()->movq(card, Address::Absolute(
Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
__ movq(temp, object);
__ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
__ movb(Address(temp, card, TIMES_1, 0), card);
- __ Bind(&is_null);
+ if (value_can_be_null) {
+ __ Bind(&is_null);
+ }
}
void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 480ea6b..d7bd525 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -174,7 +174,9 @@
void GenerateDivRemIntegral(HBinaryOperation* instruction);
void HandleShift(HBinaryOperation* operation);
void GenerateMemoryBarrier(MemBarrierKind kind);
- void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+ void HandleFieldSet(HInstruction* instruction,
+ const FieldInfo& field_info,
+ bool value_can_be_null);
void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
void GenerateImplicitNullCheck(HNullCheck* instruction);
void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -248,7 +250,11 @@
}
// Emit a write barrier.
- void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value);
+ void MarkGCCard(CpuRegister temp,
+ CpuRegister card,
+ CpuRegister object,
+ CpuRegister value,
+ bool value_can_be_null);
// Helper method to move a value between two locations.
void Move(Location destination, Location source);
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 53f1f3c..246fff9 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -218,6 +218,28 @@
return Location::RequiresRegister();
}
+// Check if registers in art register set have the same register code in vixl. If the register
+// codes are same, we can initialize vixl register list simply by the register masks. Currently,
+// only SP/WSP and ZXR/WZR codes are different between art and vixl.
+// Note: This function is only used for debug checks.
+static inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
+ size_t num_core,
+ uint32_t art_fpu_registers,
+ size_t num_fpu) {
+ // The register masks won't work if the number of register is larger than 32.
+ DCHECK_GE(sizeof(art_core_registers) * 8, num_core);
+ DCHECK_GE(sizeof(art_fpu_registers) * 8, num_fpu);
+ for (size_t art_reg_code = 0; art_reg_code < num_core; ++art_reg_code) {
+ if (RegisterSet::Contains(art_core_registers, art_reg_code)) {
+ if (art_reg_code != static_cast<size_t>(VIXLRegCodeFromART(art_reg_code))) {
+ return false;
+ }
+ }
+ }
+ // There is no register code translation for float registers.
+ return true;
+}
+
} // namespace helpers
} // namespace arm64
} // namespace art
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 6fbe75e..b31de98 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -17,6 +17,7 @@
#include "dead_code_elimination.h"
#include "base/bit_vector-inl.h"
+#include "ssa_phi_elimination.h"
namespace art {
@@ -132,6 +133,7 @@
void HDeadCodeElimination::Run() {
RemoveDeadBlocks();
+ SsaRedundantPhiElimination(graph_).Run();
RemoveDeadInstructions();
}
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 739fb76..14a8b6f 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -42,13 +42,18 @@
class StringList {
public:
+ enum Format {
+ kArrayBrackets,
+ kSetBrackets,
+ };
+
// Create an empty list
- StringList() : is_empty_(true) {}
+ explicit StringList(Format format = kArrayBrackets) : format_(format), is_empty_(true) {}
// Construct StringList from a linked list. List element class T
// must provide methods `GetNext` and `Dump`.
template<class T>
- explicit StringList(T* first_entry) : StringList() {
+ explicit StringList(T* first_entry, Format format = kArrayBrackets) : StringList(format) {
for (T* current = first_entry; current != nullptr; current = current->GetNext()) {
current->Dump(NewEntryStream());
}
@@ -58,12 +63,13 @@
if (is_empty_) {
is_empty_ = false;
} else {
- sstream_ << " ";
+ sstream_ << ",";
}
return sstream_;
}
private:
+ Format format_;
bool is_empty_;
std::ostringstream sstream_;
@@ -71,7 +77,13 @@
};
std::ostream& operator<<(std::ostream& os, const StringList& list) {
- return os << "[ " << list.sstream_.str() << " ]";
+ switch (list.format_) {
+ case StringList::kArrayBrackets: return os << "[" << list.sstream_.str() << "]";
+ case StringList::kSetBrackets: return os << "{" << list.sstream_.str() << "}";
+ default:
+ LOG(FATAL) << "Invalid StringList format";
+ UNREACHABLE();
+ }
}
/**
@@ -301,7 +313,8 @@
StartAttributeStream("liveness") << instruction->GetLifetimePosition();
if (instruction->HasLiveInterval()) {
LiveInterval* interval = instruction->GetLiveInterval();
- StartAttributeStream("ranges") << StringList(interval->GetFirstRange());
+ StartAttributeStream("ranges")
+ << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
StartAttributeStream("uses") << StringList(interval->GetFirstUse());
StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
StartAttributeStream("is_fixed") << interval->IsFixed();
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index afffc7a..56d868f 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -169,10 +169,30 @@
resolved_method->GetAccessFlags(),
nullptr);
+ bool requires_ctor_barrier = false;
+
+ if (dex_compilation_unit.IsConstructor()) {
+ // If it's a super invocation and we already generate a barrier there's no need
+ // to generate another one.
+ // We identify super calls by looking at the "this" pointer. If its value is the
+ // same as the local "this" pointer then we must have a super invocation.
+ bool is_super_invocation = invoke_instruction->InputAt(0)->IsParameterValue()
+ && invoke_instruction->InputAt(0)->AsParameterValue()->IsThis();
+ if (is_super_invocation && graph_->ShouldGenerateConstructorBarrier()) {
+ requires_ctor_barrier = false;
+ } else {
+ Thread* self = Thread::Current();
+ requires_ctor_barrier = compiler_driver_->RequiresConstructorBarrier(self,
+ dex_compilation_unit.GetDexFile(),
+ dex_compilation_unit.GetClassDefIndex());
+ }
+ }
+
HGraph* callee_graph = new (graph_->GetArena()) HGraph(
graph_->GetArena(),
caller_dex_file,
method_index,
+ requires_ctor_barrier,
graph_->IsDebuggable(),
graph_->GetCurrentInstructionId());
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 46fad17..fcb3471 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -45,6 +45,8 @@
void VisitEqual(HEqual* equal) OVERRIDE;
void VisitNotEqual(HNotEqual* equal) OVERRIDE;
void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
+ void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE;
+ void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE;
void VisitArraySet(HArraySet* equal) OVERRIDE;
void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
@@ -63,6 +65,7 @@
void VisitUShr(HUShr* instruction) OVERRIDE;
void VisitXor(HXor* instruction) OVERRIDE;
void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
+ bool IsDominatedByInputNullCheck(HInstruction* instr);
OptimizingCompilerStats* stats_;
bool simplification_occurred_ = false;
@@ -78,6 +81,8 @@
}
void InstructionSimplifierVisitor::Run() {
+ // Iterate in reverse post order to open up more simplifications to users
+ // of instructions that got simplified.
for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
// The simplification of an instruction to another instruction may yield
// possibilities for other simplifications. So although we perform a reverse
@@ -170,9 +175,20 @@
}
}
+bool InstructionSimplifierVisitor::IsDominatedByInputNullCheck(HInstruction* instr) {
+ HInstruction* input = instr->InputAt(0);
+ for (HUseIterator<HInstruction*> it(input->GetUses()); !it.Done(); it.Advance()) {
+ HInstruction* use = it.Current()->GetUser();
+ if (use->IsNullCheck() && use->StrictlyDominates(instr)) {
+ return true;
+ }
+ }
+ return false;
+}
+
void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
- if (!check_cast->InputAt(0)->CanBeNull()) {
+ if (!check_cast->InputAt(0)->CanBeNull() || IsDominatedByInputNullCheck(check_cast)) {
check_cast->ClearMustDoNullCheck();
}
@@ -194,11 +210,25 @@
}
void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
- if (!instruction->InputAt(0)->CanBeNull()) {
+ if (!instruction->InputAt(0)->CanBeNull() || IsDominatedByInputNullCheck(instruction)) {
instruction->ClearMustDoNullCheck();
}
}
+void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+ if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+ && !instruction->GetValue()->CanBeNull()) {
+ instruction->ClearValueCanBeNull();
+ }
+}
+
+void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+ if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+ && !instruction->GetValue()->CanBeNull()) {
+ instruction->ClearValueCanBeNull();
+ }
+}
+
void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
HBasicBlock* block = check->GetBlock();
// Currently always keep the suspend check at entry.
@@ -294,6 +324,10 @@
instruction->ClearNeedsTypeCheck();
}
}
+
+ if (!value->CanBeNull()) {
+ instruction->ClearValueCanBeNull();
+ }
}
void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index dccfe9a..e785bf9 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -657,7 +657,8 @@
if (type == Primitive::kPrimNot) {
Register temp = locations->GetTemp(0).AsRegister<Register>();
Register card = locations->GetTemp(1).AsRegister<Register>();
- codegen->MarkGCCard(temp, card, base, value);
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
+ codegen->MarkGCCard(temp, card, base, value, value_can_be_null);
}
}
@@ -725,7 +726,8 @@
if (type == Primitive::kPrimNot) {
// Mark card for object assuming new value is stored. Worst case we will mark an unchanged
// object and scan the receiver at the next GC for nothing.
- codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo);
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
+ codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null);
}
// Prevent reordering with prior memory operations.
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 2c4fab0..53497b6 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -797,7 +797,8 @@
}
if (type == Primitive::kPrimNot) {
- codegen->MarkGCCard(base, value);
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
+ codegen->MarkGCCard(base, value, value_can_be_null);
}
}
@@ -856,7 +857,8 @@
// This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
if (type == Primitive::kPrimNot) {
// Mark card for object assuming new value is stored.
- codegen->MarkGCCard(base, value);
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
+ codegen->MarkGCCard(base, value, value_can_be_null);
}
UseScratchRegisterScope temps(masm);
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 28b7a07..d2ca42d 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1503,10 +1503,12 @@
}
if (type == Primitive::kPrimNot) {
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
locations->GetTemp(1).AsRegister<Register>(),
base,
- value_loc.AsRegister<Register>());
+ value_loc.AsRegister<Register>(),
+ value_can_be_null);
}
}
@@ -1602,10 +1604,12 @@
Register value = locations->InAt(4).AsRegister<Register>();
if (type == Primitive::kPrimNot) {
// Mark card for object assuming new value is stored.
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
locations->GetTemp(1).AsRegister<Register>(),
base,
- value);
+ value,
+ value_can_be_null);
}
__ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 0efa714..2ccecfe 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1374,10 +1374,12 @@
}
if (type == Primitive::kPrimNot) {
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
locations->GetTemp(1).AsRegister<CpuRegister>(),
base,
- value);
+ value,
+ value_can_be_null);
}
}
@@ -1459,10 +1461,12 @@
// Integer or object.
if (type == Primitive::kPrimNot) {
// Mark card for object assuming new value is stored.
+ bool value_can_be_null = true; // TODO: Worth finding out this information?
codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
locations->GetTemp(1).AsRegister<CpuRegister>(),
base,
- value);
+ value,
+ value_can_be_null);
}
__ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index cb2e5cc..680fb47 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -120,6 +120,7 @@
HGraph(ArenaAllocator* arena,
const DexFile& dex_file,
uint32_t method_idx,
+ bool should_generate_constructor_barrier,
bool debuggable = false,
int start_instruction_id = 0)
: arena_(arena),
@@ -137,6 +138,7 @@
current_instruction_id_(start_instruction_id),
dex_file_(dex_file),
method_idx_(method_idx),
+ should_generate_constructor_barrier_(should_generate_constructor_barrier),
cached_null_constant_(nullptr),
cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
cached_float_constants_(std::less<int32_t>(), arena->Adapter()),
@@ -247,6 +249,10 @@
has_bounds_checks_ = value;
}
+ bool ShouldGenerateConstructorBarrier() const {
+ return should_generate_constructor_barrier_;
+ }
+
bool IsDebuggable() const { return debuggable_; }
// Returns a constant of the given type and value. If it does not exist
@@ -359,6 +365,8 @@
// The method index in the dex file.
const uint32_t method_idx_;
+ const bool should_generate_constructor_barrier_;
+
// Cached constants.
HNullConstant* cached_null_constant_;
ArenaSafeMap<int32_t, HIntConstant*> cached_int_constants_;
@@ -2902,6 +2910,8 @@
bool CanBeNull() const OVERRIDE { return !is_this_; }
+ bool IsThis() const { return is_this_; }
+
DECLARE_INSTRUCTION(ParameterValue);
private:
@@ -3163,7 +3173,8 @@
MemberOffset field_offset,
bool is_volatile)
: HTemplateInstruction(SideEffects::ChangesSomething()),
- field_info_(field_offset, field_type, is_volatile) {
+ field_info_(field_offset, field_type, is_volatile),
+ value_can_be_null_(true) {
SetRawInputAt(0, object);
SetRawInputAt(1, value);
}
@@ -3177,11 +3188,14 @@
Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
bool IsVolatile() const { return field_info_.IsVolatile(); }
HInstruction* GetValue() const { return InputAt(1); }
+ bool GetValueCanBeNull() const { return value_can_be_null_; }
+ void ClearValueCanBeNull() { value_can_be_null_ = false; }
DECLARE_INSTRUCTION(InstanceFieldSet);
private:
const FieldInfo field_info_;
+ bool value_can_be_null_;
DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
};
@@ -3230,7 +3244,8 @@
: HTemplateInstruction(SideEffects::ChangesSomething()),
dex_pc_(dex_pc),
expected_component_type_(expected_component_type),
- needs_type_check_(value->GetType() == Primitive::kPrimNot) {
+ needs_type_check_(value->GetType() == Primitive::kPrimNot),
+ value_can_be_null_(true) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
@@ -3252,6 +3267,11 @@
needs_type_check_ = false;
}
+ void ClearValueCanBeNull() {
+ value_can_be_null_ = false;
+ }
+
+ bool GetValueCanBeNull() const { return value_can_be_null_; }
bool NeedsTypeCheck() const { return needs_type_check_; }
uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
@@ -3277,6 +3297,7 @@
const uint32_t dex_pc_;
const Primitive::Type expected_component_type_;
bool needs_type_check_;
+ bool value_can_be_null_;
DISALLOW_COPY_AND_ASSIGN(HArraySet);
};
@@ -3577,7 +3598,8 @@
MemberOffset field_offset,
bool is_volatile)
: HTemplateInstruction(SideEffects::ChangesSomething()),
- field_info_(field_offset, field_type, is_volatile) {
+ field_info_(field_offset, field_type, is_volatile),
+ value_can_be_null_(true) {
SetRawInputAt(0, cls);
SetRawInputAt(1, value);
}
@@ -3588,11 +3610,14 @@
bool IsVolatile() const { return field_info_.IsVolatile(); }
HInstruction* GetValue() const { return InputAt(1); }
+ bool GetValueCanBeNull() const { return value_can_be_null_; }
+ void ClearValueCanBeNull() { value_can_be_null_ = false; }
DECLARE_INSTRUCTION(StaticFieldSet);
private:
const FieldInfo field_info_;
+ bool value_can_be_null_;
DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
};
@@ -3895,7 +3920,9 @@
}
for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
DCHECK(!destination.OverlapsWith(moves_.Get(i).GetDestination()))
- << "Overlapped destination for two moves in a parallel move.";
+ << "Overlapped destination for two moves in a parallel move: "
+ << moves_.Get(i).GetSource() << " ==> " << moves_.Get(i).GetDestination() << " and "
+ << source << " ==> " << destination;
}
}
moves_.Add(MoveOperands(source, destination, type, instruction));
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8bb5d8e..be9a424 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -512,9 +512,14 @@
class_def_idx, method_idx, access_flags,
compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
+ bool requires_barrier = dex_compilation_unit.IsConstructor()
+ && compiler_driver->RequiresConstructorBarrier(Thread::Current(),
+ dex_compilation_unit.GetDexFile(),
+ dex_compilation_unit.GetClassDefIndex());
ArenaAllocator arena(Runtime::Current()->GetArenaPool());
HGraph* graph = new (&arena) HGraph(
- &arena, dex_file, method_idx, compiler_driver->GetCompilerOptions().GetDebuggable());
+ &arena, dex_file, method_idx, requires_barrier,
+ compiler_driver->GetCompilerOptions().GetDebuggable());
// For testing purposes, we put a special marker on method names that should be compiled
// with this compiler. This makes sure we're not regressing.
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 4f8ec65..1fe9346 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -74,7 +74,7 @@
inline HGraph* CreateGraph(ArenaAllocator* allocator) {
return new (allocator) HGraph(
- allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1);
+ allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1, false);
}
// Create a control-flow graph from Dex instructions.
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index f53f846..925099a 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -775,7 +775,7 @@
} else if (current->IsLowInterval()) {
reg = FindAvailableRegisterPair(free_until, current->GetStart());
} else {
- reg = FindAvailableRegister(free_until);
+ reg = FindAvailableRegister(free_until, current);
}
}
@@ -839,14 +839,52 @@
return reg;
}
-int RegisterAllocator::FindAvailableRegister(size_t* next_use) const {
+bool RegisterAllocator::IsCallerSaveRegister(int reg) const {
+ return processing_core_registers_
+ ? !codegen_->IsCoreCalleeSaveRegister(reg)
+ : !codegen_->IsFloatingPointCalleeSaveRegister(reg);
+}
+
+int RegisterAllocator::FindAvailableRegister(size_t* next_use, LiveInterval* current) const {
+ // We special case intervals that do not span a safepoint to try to find a caller-save
+ // register if one is available. We iterate from 0 to the number of registers,
+ // so if there are caller-save registers available at the end, we continue the iteration.
+ bool prefers_caller_save = !current->HasWillCallSafepoint();
int reg = kNoRegister;
- // Pick the register that is used the last.
for (size_t i = 0; i < number_of_registers_; ++i) {
- if (IsBlocked(i)) continue;
- if (reg == kNoRegister || next_use[i] > next_use[reg]) {
+ if (IsBlocked(i)) {
+ // Register cannot be used. Continue.
+ continue;
+ }
+
+ // Best case: we found a register fully available.
+ if (next_use[i] == kMaxLifetimePosition) {
+ if (prefers_caller_save && !IsCallerSaveRegister(i)) {
+ // We can get shorter encodings on some platforms by using
+ // small register numbers. So only update the candidate if the previous
+ // one was not available for the whole method.
+ if (reg == kNoRegister || next_use[reg] != kMaxLifetimePosition) {
+ reg = i;
+ }
+ // Continue the iteration in the hope of finding a caller save register.
+ continue;
+ } else {
+ reg = i;
+ // We know the register is good enough. Return it.
+ break;
+ }
+ }
+
+ // If we had no register before, take this one as a reference.
+ if (reg == kNoRegister) {
reg = i;
- if (next_use[i] == kMaxLifetimePosition) break;
+ continue;
+ }
+
+ // Pick the register that is used the last.
+ if (next_use[i] > next_use[reg]) {
+ reg = i;
+ continue;
}
}
return reg;
@@ -971,7 +1009,7 @@
|| (first_use >= next_use[GetHighForLowRegister(reg)]);
} else {
DCHECK(!current->IsHighInterval());
- reg = FindAvailableRegister(next_use);
+ reg = FindAvailableRegister(next_use, current);
should_spill = (first_use >= next_use[reg]);
}
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index dc9c708..6d5bfc3 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -140,7 +140,8 @@
void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
void DumpAllIntervals(std::ostream& stream) const;
int FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const;
- int FindAvailableRegister(size_t* next_use) const;
+ int FindAvailableRegister(size_t* next_use, LiveInterval* current) const;
+ bool IsCallerSaveRegister(int reg) const;
// Try splitting an active non-pair or unaligned pair interval at the given `position`.
// Returns whether it was successful at finding such an interval.
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 59a2852..aac5211 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -504,7 +504,7 @@
// typed and the value in a dex register will not be used for both floating point and
// non-floating point operations. So the only reason an instruction would want a floating
// point equivalent is for an unused phi that will be removed by the dead phi elimination phase.
- DCHECK(user->IsPhi());
+ DCHECK(user->IsPhi()) << "is actually " << user->DebugName() << " (" << user->GetId() << ")";
return value;
}
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index bd55e9f..4b19c5b 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -76,7 +76,7 @@
}
void Dump(std::ostream& stream) const {
- stream << start_ << "-" << end_;
+ stream << "[" << start_ << "," << end_ << ")";
}
LiveRange* Dup(ArenaAllocator* allocator) const {
@@ -542,6 +542,15 @@
return defined_by_;
}
+ bool HasWillCallSafepoint() const {
+ for (SafepointPosition* safepoint = first_safepoint_;
+ safepoint != nullptr;
+ safepoint = safepoint->GetNext()) {
+ if (safepoint->GetLocations()->WillCall()) return true;
+ }
+ return false;
+ }
+
SafepointPosition* FindSafepointJustBefore(size_t position) const {
for (SafepointPosition* safepoint = first_safepoint_, *previous = nullptr;
safepoint != nullptr;
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 8344fc3..89035a3 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include "stack_map_stream.h"
namespace art {
@@ -52,6 +51,7 @@
dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
register_mask_max_ = std::max(register_mask_max_, register_mask);
+ current_dex_register_ = 0;
}
void StackMapStream::EndStackMapEntry() {
@@ -60,11 +60,7 @@
current_entry_ = StackMapEntry();
}
-void StackMapStream::AddDexRegisterEntry(uint16_t dex_register,
- DexRegisterLocation::Kind kind,
- int32_t value) {
- DCHECK_LT(dex_register, current_entry_.num_dex_registers);
-
+void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
if (kind != DexRegisterLocation::Kind::kNone) {
// Ensure we only use non-compressed location kind at this stage.
DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
@@ -87,18 +83,47 @@
location_catalog_entries_indices_.Insert(std::make_pair(location, index));
}
- current_entry_.live_dex_registers_mask->SetBit(dex_register);
- current_entry_.dex_register_map_hash +=
- (1 << (dex_register % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
- current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
- current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+ if (in_inline_frame_) {
+ // TODO: Support sharing DexRegisterMap across InlineInfo.
+ DCHECK_LT(current_dex_register_, current_inline_info_.num_dex_registers);
+ current_inline_info_.live_dex_registers_mask->SetBit(current_dex_register_);
+ } else {
+ DCHECK_LT(current_dex_register_, current_entry_.num_dex_registers);
+ current_entry_.live_dex_registers_mask->SetBit(current_dex_register_);
+ current_entry_.dex_register_map_hash += (1 <<
+ (current_dex_register_ % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
+ current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
+ current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+ }
}
+ current_dex_register_++;
}
-void StackMapStream::AddInlineInfoEntry(uint32_t method_index) {
- InlineInfoEntry entry;
- entry.method_index = method_index;
- inline_infos_.Add(entry);
+void StackMapStream::BeginInlineInfoEntry(uint32_t method_index,
+ uint32_t dex_pc,
+ uint32_t num_dex_registers) {
+ DCHECK(!in_inline_frame_);
+ in_inline_frame_ = true;
+ current_inline_info_.method_index = method_index;
+ current_inline_info_.dex_pc = dex_pc;
+ current_inline_info_.num_dex_registers = num_dex_registers;
+ current_inline_info_.dex_register_locations_start_index = dex_register_locations_.Size();
+ if (num_dex_registers != 0) {
+ current_inline_info_.live_dex_registers_mask =
+ new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
+ } else {
+ current_inline_info_.live_dex_registers_mask = nullptr;
+ }
+ current_dex_register_ = 0;
+}
+
+void StackMapStream::EndInlineInfoEntry() {
+ DCHECK(in_inline_frame_);
+ DCHECK_EQ(current_dex_register_, current_inline_info_.num_dex_registers)
+ << "Inline information contains less registers than expected";
+ in_inline_frame_ = false;
+ inline_infos_.Add(current_inline_info_);
+ current_inline_info_ = InlineInfoEntry();
}
size_t StackMapStream::PrepareForFillIn() {
@@ -142,17 +167,18 @@
return size;
}
-size_t StackMapStream::ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
+size_t StackMapStream::ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+ const BitVector& live_dex_registers_mask) const {
// Size of the map in bytes.
size_t size = DexRegisterMap::kFixedSize;
// Add the live bit mask for the Dex register liveness.
- size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
+ size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
// Compute the size of the set of live Dex register entries.
size_t number_of_live_dex_registers = 0;
for (size_t dex_register_number = 0;
- dex_register_number < entry.num_dex_registers;
+ dex_register_number < num_dex_registers;
++dex_register_number) {
- if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+ if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
++number_of_live_dex_registers;
}
}
@@ -167,11 +193,18 @@
size_t StackMapStream::ComputeDexRegisterMapsSize() const {
size_t size = 0;
+ size_t inline_info_index = 0;
for (size_t i = 0; i < stack_maps_.Size(); ++i) {
StackMapEntry entry = stack_maps_.Get(i);
if (entry.same_dex_register_map_as_ == kNoSameDexMapFound) {
+ size += ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask);
+ } else {
// Entries with the same dex map will have the same offset.
- size += ComputeDexRegisterMapSize(entry);
+ }
+ for (size_t j = 0; j < entry.inlining_depth; ++j) {
+ InlineInfoEntry inline_entry = inline_infos_.Get(inline_info_index++);
+ size += ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+ *inline_entry.live_dex_registers_mask);
}
}
return size;
@@ -247,34 +280,19 @@
.GetDexRegisterMapOffset(code_info));
} else {
// New dex registers maps should be added to the stack map.
- MemoryRegion register_region =
- dex_register_locations_region.Subregion(
- next_dex_register_map_offset,
- ComputeDexRegisterMapSize(entry));
+ MemoryRegion register_region = dex_register_locations_region.Subregion(
+ next_dex_register_map_offset,
+ ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask));
next_dex_register_map_offset += register_region.size();
DexRegisterMap dex_register_map(register_region);
stack_map.SetDexRegisterMapOffset(
code_info, register_region.start() - dex_register_locations_region.start());
- // Set the live bit mask.
- dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
-
- // Set the dex register location mapping data.
- for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
- dex_register_number < entry.num_dex_registers;
- ++dex_register_number) {
- if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
- size_t location_catalog_entry_index =
- dex_register_locations_.Get(entry.dex_register_locations_start_index
- + index_in_dex_register_locations);
- dex_register_map.SetLocationCatalogEntryIndex(
- index_in_dex_register_locations,
- location_catalog_entry_index,
- entry.num_dex_registers,
- location_catalog_entries_.Size());
- ++index_in_dex_register_locations;
- }
- }
+ // Set the dex register location.
+ FillInDexRegisterMap(dex_register_map,
+ entry.num_dex_registers,
+ *entry.live_dex_registers_mask,
+ entry.dex_register_locations_start_index);
}
}
@@ -291,9 +309,29 @@
code_info, inline_region.start() - dex_register_locations_region.start());
inline_info.SetDepth(entry.inlining_depth);
- for (size_t j = 0; j < entry.inlining_depth; ++j) {
- InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
- inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
+ for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
+ InlineInfoEntry inline_entry = inline_infos_.Get(depth + entry.inline_infos_start_index);
+ inline_info.SetMethodIndexAtDepth(depth, inline_entry.method_index);
+ inline_info.SetDexPcAtDepth(depth, inline_entry.dex_pc);
+ if (inline_entry.num_dex_registers == 0) {
+ // No dex map available.
+ inline_info.SetDexRegisterMapOffsetAtDepth(depth, StackMap::kNoDexRegisterMap);
+ DCHECK(inline_entry.live_dex_registers_mask == nullptr);
+ } else {
+ MemoryRegion register_region = dex_register_locations_region.Subregion(
+ next_dex_register_map_offset,
+ ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+ *inline_entry.live_dex_registers_mask));
+ next_dex_register_map_offset += register_region.size();
+ DexRegisterMap dex_register_map(register_region);
+ inline_info.SetDexRegisterMapOffsetAtDepth(
+ depth, register_region.start() - dex_register_locations_region.start());
+
+ FillInDexRegisterMap(dex_register_map,
+ inline_entry.num_dex_registers,
+ *inline_entry.live_dex_registers_mask,
+ inline_entry.dex_register_locations_start_index);
+ }
}
} else {
if (inline_info_size_ != 0) {
@@ -303,6 +341,28 @@
}
}
+void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
+ uint32_t num_dex_registers,
+ const BitVector& live_dex_registers_mask,
+ uint32_t start_index_in_dex_register_locations) const {
+ dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
+ // Set the dex register location mapping data.
+ for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+ dex_register_number < num_dex_registers;
+ ++dex_register_number) {
+ if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
+ size_t location_catalog_entry_index = dex_register_locations_.Get(
+ start_index_in_dex_register_locations + index_in_dex_register_locations);
+ dex_register_map.SetLocationCatalogEntryIndex(
+ index_in_dex_register_locations,
+ location_catalog_entry_index,
+ num_dex_registers,
+ location_catalog_entries_.Size());
+ ++index_in_dex_register_locations;
+ }
+ }
+}
+
size_t StackMapStream::FindEntryWithTheSameDexMap() {
size_t current_entry_index = stack_maps_.Size();
auto entries_it = dex_map_hash_to_stack_map_indices_.find(current_entry_.dex_register_map_hash);
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 0c626be..4c03f9f 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -72,6 +72,7 @@
number_of_stack_maps_with_inline_info_(0),
dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()),
current_entry_(),
+ current_inline_info_(),
stack_mask_size_(0),
inline_info_size_(0),
dex_register_maps_size_(0),
@@ -81,7 +82,9 @@
stack_maps_start_(0),
dex_register_maps_start_(0),
inline_infos_start_(0),
- needed_size_(0) {}
+ needed_size_(0),
+ current_dex_register_(0),
+ in_inline_frame_(false) {}
// See runtime/stack_map.h to know what these fields contain.
struct StackMapEntry {
@@ -99,7 +102,11 @@
};
struct InlineInfoEntry {
+ uint32_t dex_pc;
uint32_t method_index;
+ uint32_t num_dex_registers;
+ BitVector* live_dex_registers_mask;
+ size_t dex_register_locations_start_index;
};
void BeginStackMapEntry(uint32_t dex_pc,
@@ -110,11 +117,12 @@
uint8_t inlining_depth);
void EndStackMapEntry();
- void AddDexRegisterEntry(uint16_t dex_register,
- DexRegisterLocation::Kind kind,
- int32_t value);
+ void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value);
- void AddInlineInfoEntry(uint32_t method_index);
+ void BeginInlineInfoEntry(uint32_t method_index,
+ uint32_t dex_pc,
+ uint32_t num_dex_registers);
+ void EndInlineInfoEntry();
// Prepares the stream to fill in a memory region. Must be called before FillIn.
// Returns the size (in bytes) needed to store this stream.
@@ -123,7 +131,8 @@
private:
size_t ComputeDexRegisterLocationCatalogSize() const;
- size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const;
+ size_t ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+ const BitVector& live_dex_registers_mask) const;
size_t ComputeDexRegisterMapsSize() const;
size_t ComputeInlineInfoSize() const;
@@ -131,6 +140,10 @@
// or kNoSameDexMapFound if no such entry exists.
size_t FindEntryWithTheSameDexMap();
bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const;
+ void FillInDexRegisterMap(DexRegisterMap dex_register_map,
+ uint32_t num_dex_registers,
+ const BitVector& live_dex_registers_mask,
+ uint32_t start_index_in_dex_register_locations) const;
ArenaAllocator* allocator_;
GrowableArray<StackMapEntry> stack_maps_;
@@ -155,6 +168,7 @@
ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
StackMapEntry current_entry_;
+ InlineInfoEntry current_inline_info_;
size_t stack_mask_size_;
size_t inline_info_size_;
size_t dex_register_maps_size_;
@@ -165,6 +179,8 @@
size_t dex_register_maps_start_;
size_t inline_infos_start_;
size_t needed_size_;
+ uint32_t current_dex_register_;
+ bool in_inline_frame_;
static constexpr uint32_t kNoSameDexMapFound = -1;
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 3291a77..e04fa98 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -41,8 +41,8 @@
ArenaBitVector sp_mask(&arena, 0, false);
size_t number_of_dex_registers = 2;
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kInStack, 0); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Short location.
+ stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Short location.
stream.EndStackMapEntry();
size_t size = stream.PrepareForFillIn();
@@ -124,19 +124,22 @@
sp_mask1.SetBit(2);
sp_mask1.SetBit(4);
size_t number_of_dex_registers = 2;
+ size_t number_of_dex_registers_in_inline_info = 0;
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2);
- stream.AddDexRegisterEntry(0, Kind::kInStack, 0); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Large location.
- stream.AddInlineInfoEntry(42);
- stream.AddInlineInfoEntry(82);
+ stream.AddDexRegisterEntry(Kind::kInStack, 0); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
+ stream.BeginInlineInfoEntry(82, 3, number_of_dex_registers_in_inline_info);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(42, 2, number_of_dex_registers_in_inline_info);
+ stream.EndInlineInfoEntry();
stream.EndStackMapEntry();
ArenaBitVector sp_mask2(&arena, 0, true);
sp_mask2.SetBit(3);
sp_mask1.SetBit(8);
stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kInRegister, 18); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kInFpuRegister, 3); // Short location.
+ stream.AddDexRegisterEntry(Kind::kInRegister, 18); // Short location.
+ stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3); // Short location.
stream.EndStackMapEntry();
size_t size = stream.PrepareForFillIn();
@@ -211,8 +214,10 @@
ASSERT_TRUE(stack_map.HasInlineInfo(code_info));
InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
ASSERT_EQ(2u, inline_info.GetDepth());
- ASSERT_EQ(42u, inline_info.GetMethodReferenceIndexAtDepth(0));
- ASSERT_EQ(82u, inline_info.GetMethodReferenceIndexAtDepth(1));
+ ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(0));
+ ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(1));
+ ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0));
+ ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1));
}
// Second stack map.
@@ -277,8 +282,8 @@
ArenaBitVector sp_mask(&arena, 0, false);
uint32_t number_of_dex_registers = 2;
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kNone, 0); // No location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Large location.
+ stream.AddDexRegisterEntry(Kind::kNone, 0); // No location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
size_t size = stream.PrepareForFillIn();
@@ -364,13 +369,13 @@
// as using a single value (in the whole CodeInfo object) would
// make this Dex register mapping data empty (see
// art::DexRegisterMap::SingleEntrySizeInBits).
- stream.AddDexRegisterEntry(i, Kind::kConstant, i % 2); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, i % 2); // Short location.
}
stream.EndStackMapEntry();
// Create the second stack map (and its Dex register map).
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
for (uint32_t i = 0; i < number_of_dex_registers; ++i) {
- stream.AddDexRegisterEntry(i, Kind::kConstant, 0); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, 0); // Short location.
}
stream.EndStackMapEntry();
@@ -420,18 +425,18 @@
uint32_t number_of_dex_registers = 2;
// First stack map.
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kInRegister, 0); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Large location.
+ stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
// Second stack map, which should share the same dex register map.
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kInRegister, 0); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Large location.
+ stream.AddDexRegisterEntry(Kind::kInRegister, 0); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
// Third stack map (doesn't share the dex register map).
stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
- stream.AddDexRegisterEntry(0, Kind::kInRegister, 2); // Short location.
- stream.AddDexRegisterEntry(1, Kind::kConstant, -2); // Large location.
+ stream.AddDexRegisterEntry(Kind::kInRegister, 2); // Short location.
+ stream.AddDexRegisterEntry(Kind::kConstant, -2); // Large location.
stream.EndStackMapEntry();
size_t size = stream.PrepareForFillIn();
@@ -500,4 +505,167 @@
ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
}
+TEST(StackMapTest, InlineTest) {
+ ArenaPool pool;
+ ArenaAllocator arena(&pool);
+ StackMapStream stream(&arena);
+
+ ArenaBitVector sp_mask1(&arena, 0, true);
+ sp_mask1.SetBit(2);
+ sp_mask1.SetBit(4);
+
+ // First stack map.
+ stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, 2, 2);
+ stream.AddDexRegisterEntry(Kind::kInStack, 0);
+ stream.AddDexRegisterEntry(Kind::kConstant, 4);
+
+ stream.BeginInlineInfoEntry(42, 2, 1);
+ stream.AddDexRegisterEntry(Kind::kInStack, 8);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(82, 3, 3);
+ stream.AddDexRegisterEntry(Kind::kInStack, 16);
+ stream.AddDexRegisterEntry(Kind::kConstant, 20);
+ stream.AddDexRegisterEntry(Kind::kInRegister, 15);
+ stream.EndInlineInfoEntry();
+
+ stream.EndStackMapEntry();
+
+ // Second stack map.
+ stream.BeginStackMapEntry(2, 22, 0x3, &sp_mask1, 2, 3);
+ stream.AddDexRegisterEntry(Kind::kInStack, 56);
+ stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+ stream.BeginInlineInfoEntry(42, 2, 1);
+ stream.AddDexRegisterEntry(Kind::kInStack, 12);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(82, 3, 3);
+ stream.AddDexRegisterEntry(Kind::kInStack, 80);
+ stream.AddDexRegisterEntry(Kind::kConstant, 10);
+ stream.AddDexRegisterEntry(Kind::kInRegister, 5);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(52, 5, 0);
+ stream.EndInlineInfoEntry();
+
+ stream.EndStackMapEntry();
+
+ // Third stack map.
+ stream.BeginStackMapEntry(4, 56, 0x3, &sp_mask1, 2, 0);
+ stream.AddDexRegisterEntry(Kind::kNone, 0);
+ stream.AddDexRegisterEntry(Kind::kConstant, 4);
+ stream.EndStackMapEntry();
+
+ // Fourth stack map.
+ stream.BeginStackMapEntry(6, 78, 0x3, &sp_mask1, 2, 3);
+ stream.AddDexRegisterEntry(Kind::kInStack, 56);
+ stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+ stream.BeginInlineInfoEntry(42, 2, 0);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(52, 5, 1);
+ stream.AddDexRegisterEntry(Kind::kInRegister, 2);
+ stream.EndInlineInfoEntry();
+ stream.BeginInlineInfoEntry(52, 10, 2);
+ stream.AddDexRegisterEntry(Kind::kNone, 0);
+ stream.AddDexRegisterEntry(Kind::kInRegister, 3);
+ stream.EndInlineInfoEntry();
+
+ stream.EndStackMapEntry();
+
+ size_t size = stream.PrepareForFillIn();
+ void* memory = arena.Alloc(size, kArenaAllocMisc);
+ MemoryRegion region(memory, size);
+ stream.FillIn(region);
+
+ CodeInfo ci(region);
+
+ {
+ // Verify first stack map.
+ StackMap sm0 = ci.GetStackMapAt(0);
+
+ DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, 2);
+ ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+ ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci));
+
+ InlineInfo if0 = ci.GetInlineInfoOf(sm0);
+ ASSERT_EQ(2u, if0.GetDepth());
+ ASSERT_EQ(2u, if0.GetDexPcAtDepth(0));
+ ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(0));
+ ASSERT_EQ(3u, if0.GetDexPcAtDepth(1));
+ ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(1));
+
+ DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, 1);
+ ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci));
+
+ DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, 3);
+ ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci));
+ ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci));
+ ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci));
+ }
+
+ {
+ // Verify second stack map.
+ StackMap sm1 = ci.GetStackMapAt(1);
+
+ DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, 2);
+ ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+ ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci));
+
+ InlineInfo if1 = ci.GetInlineInfoOf(sm1);
+ ASSERT_EQ(3u, if1.GetDepth());
+ ASSERT_EQ(2u, if1.GetDexPcAtDepth(0));
+ ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(0));
+ ASSERT_EQ(3u, if1.GetDexPcAtDepth(1));
+ ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(1));
+ ASSERT_EQ(5u, if1.GetDexPcAtDepth(2));
+ ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(2));
+
+ DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, 1);
+ ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci));
+
+ DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, 3);
+ ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci));
+ ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci));
+ ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci));
+
+ ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2));
+ }
+
+ {
+ // Verify third stack map.
+ StackMap sm2 = ci.GetStackMapAt(2);
+
+ DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, 2);
+ ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0));
+ ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci));
+ ASSERT_FALSE(sm2.HasInlineInfo(ci));
+ }
+
+ {
+ // Verify fourth stack map.
+ StackMap sm3 = ci.GetStackMapAt(3);
+
+ DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, 2);
+ ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci));
+ ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci));
+
+ InlineInfo if2 = ci.GetInlineInfoOf(sm3);
+ ASSERT_EQ(3u, if2.GetDepth());
+ ASSERT_EQ(2u, if2.GetDexPcAtDepth(0));
+ ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(0));
+ ASSERT_EQ(5u, if2.GetDexPcAtDepth(1));
+ ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(1));
+ ASSERT_EQ(10u, if2.GetDexPcAtDepth(2));
+ ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(2));
+
+ ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0));
+
+ DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, 1);
+ ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci));
+
+ DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, 2);
+ ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0));
+ ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci));
+ }
+}
+
} // namespace art
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index c410660..eca6f5a 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -860,8 +860,6 @@
// Set up call to Thread::Current()->pDeliverException.
__ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
__ blx(R12);
- // Call never returns.
- __ bkpt(0);
#undef __
}
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 313f365..dee8287 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -398,6 +398,8 @@
Condition cond = AL) = 0;
virtual void mls(Register rd, Register rn, Register rm, Register ra,
Condition cond = AL) = 0;
+ virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL) = 0;
virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL) = 0;
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 9579691..6e165fc 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -200,6 +200,13 @@
}
+void Arm32Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+ Register rm, Condition cond) {
+ // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
+}
+
+
void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
Register rm, Condition cond) {
// Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index b922d66..55ec7b4 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -90,6 +90,8 @@
Condition cond = AL) OVERRIDE;
void mls(Register rd, Register rn, Register rm, Register ra,
Condition cond = AL) OVERRIDE;
+ void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL) OVERRIDE;
void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL) OVERRIDE;
diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc
index 4a0ae0b..efd517b 100644
--- a/compiler/utils/arm/assembler_arm32_test.cc
+++ b/compiler/utils/arm/assembler_arm32_test.cc
@@ -293,12 +293,29 @@
f();
}
+ // NOTE: Only support simple test like "aaa=bbb"
+ bool EvalFilterString(std::string filter) {
+ if (filter.compare("") == 0) {
+ return false;
+ }
+
+ size_t equal_sign_index = filter.find('=');
+ if (equal_sign_index == std::string::npos) {
+ EXPECT_TRUE(false) << "Unsupported filter string.";
+ }
+
+ std::string lhs = filter.substr(0, equal_sign_index);
+ std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
+ return lhs.compare(rhs) == 0;
+ }
+
void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc,
- std::string fmt, std::ostringstream& oss) {
+ bool without_pc, std::string fmt, std::string filter,
+ std::ostringstream& oss) {
std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
for (auto reg : registers) {
std::string after_reg = fmt;
+ std::string after_reg_filter = filter;
std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
size_t reg_index;
@@ -308,14 +325,23 @@
after_reg.replace(reg_index, strlen(reg_token), reg_string);
}
+ while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+ after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+ }
+ if (EvalFilterString(after_reg_filter)) {
+ continue;
+ }
+
ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
}
}
void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+ bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+ std::ostringstream& oss) {
for (const arm::ShifterOperand& shift : GetShiftOperands()) {
std::string after_shift = fmt;
+ std::string after_shift_filter = filter;
std::string shift_string = GetShiftString(shift);
size_t shift_index;
@@ -323,30 +349,48 @@
after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
}
+ while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+ after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+ }
+ if (EvalFilterString(after_shift_filter)) {
+ continue;
+ }
+
ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
}
}
void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
- bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+ bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+ std::ostringstream& oss) {
for (arm::Condition c : GetConditions()) {
std::string after_cond = fmt;
+ std::string after_cond_filter = filter;
size_t cond_index = after_cond.find(COND_TOKEN);
if (cond_index != std::string::npos) {
after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
}
+ cond_index = after_cond_filter.find(COND_TOKEN);
+ if (cond_index != std::string::npos) {
+ after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+ }
+ if (EvalFilterString(after_cond_filter)) {
+ continue;
+ }
+
ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
}
}
template <typename... Args>
void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
- std::string fmt, std::ostringstream& oss) {
+ std::string fmt, std::string filter, std::ostringstream& oss) {
std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
for (auto reg : registers) {
std::string after_reg = fmt;
+ std::string after_reg_filter = filter;
std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
size_t reg_index;
@@ -356,17 +400,26 @@
after_reg.replace(reg_index, strlen(reg_token), reg_string);
}
+ while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+ after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+ }
+ if (EvalFilterString(after_reg_filter)) {
+ continue;
+ }
+
auto lambda = [&] (Args... args) { f(*reg, args...); }; // NOLINT [readability/braces] [4]
TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
- after_reg, oss);
+ after_reg, after_reg_filter, oss);
}
}
template <typename... Args>
void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
- bool without_pc, std::string fmt, std::ostringstream& oss) {
+ bool without_pc, std::string fmt, std::string filter,
+ std::ostringstream& oss) {
for (const arm::ShifterOperand& shift : GetShiftOperands()) {
std::string after_shift = fmt;
+ std::string after_shift_filter = filter;
std::string shift_string = GetShiftString(shift);
size_t shift_index;
@@ -374,26 +427,42 @@
after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
}
+ while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+ after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+ }
+ if (EvalFilterString(after_shift_filter)) {
+ continue;
+ }
+
auto lambda = [&] (Args... args) { f(shift, args...); }; // NOLINT [readability/braces] [4]
TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
- after_shift, oss);
+ after_shift, after_shift_filter, oss);
}
}
template <typename... Args>
void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
- std::string fmt, std::ostringstream& oss) {
+ std::string fmt, std::string filter, std::ostringstream& oss) {
for (arm::Condition c : GetConditions()) {
std::string after_cond = fmt;
+ std::string after_cond_filter = filter;
size_t cond_index = after_cond.find(COND_TOKEN);
if (cond_index != std::string::npos) {
after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
}
+ cond_index = after_cond_filter.find(COND_TOKEN);
+ if (cond_index != std::string::npos) {
+ after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+ }
+ if (EvalFilterString(after_cond_filter)) {
+ continue;
+ }
+
auto lambda = [&] (Args... args) { f(c, args...); }; // NOLINT [readability/braces] [4]
TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
- after_cond, oss);
+ after_cond, after_cond_filter, oss);
}
}
@@ -421,13 +490,13 @@
template <typename... Args>
void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
- std::string fmt, std::string test_name) {
+ std::string fmt, std::string test_name, std::string filter) {
first_ = false;
WarnOnCombinations(CountHelper<Args...>(without_pc));
std::ostringstream oss;
- TemplateHelper(f, 0, without_pc, fmt, oss);
+ TemplateHelper(f, 0, without_pc, fmt, filter, oss);
oss << "\n"; // Trailing newline.
@@ -436,26 +505,26 @@
template <typename... Args>
void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name) {
- GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
+ std::string test_name, std::string filter = "") {
+ GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
}
template <typename... Args>
void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name) {
- GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
+ std::string test_name, std::string filter = "") {
+ GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
}
template <typename... Args>
void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name) {
- GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
+ std::string test_name, std::string filter = "") {
+ GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
}
template <typename... Args>
void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
- std::string test_name) {
- GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
+ std::string test_name, std::string filter = "") {
+ GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
}
private:
@@ -565,15 +634,18 @@
}
TEST_F(AssemblerArm32Test, Mla) {
- T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
+ T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
}
-/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
TEST_F(AssemblerArm32Test, Umull) {
T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
- "umull");
+ "umull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
}
-*/
+
+TEST_F(AssemblerArm32Test, Smull) {
+ T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
+ "smull", "{reg1}={reg2}"); // Skip the cases where reg1 == reg2.
+}
TEST_F(AssemblerArm32Test, Sdiv) {
T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
@@ -655,9 +727,10 @@
T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
}
-/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
+/* TODO: Need better filter support.
TEST_F(AssemblerArm32Test, Strex) {
- RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
+ T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
+ "{reg1}={reg2}||{reg1}={reg3}"); // Skip the cases where reg1 == reg2 || reg1 == reg3.
}
*/
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 3b42f63..75f2b77 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -238,6 +238,24 @@
}
+void Thumb2Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+ Register rm, Condition cond) {
+ CheckCondition(cond);
+
+ uint32_t op1 = 0U /* 0b000; */;
+ uint32_t op2 = 0U /* 0b0000 */;
+ int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
+ op1 << 20 |
+ op2 << 4 |
+ static_cast<uint32_t>(rd_lo) << 12 |
+ static_cast<uint32_t>(rd_hi) << 8 |
+ static_cast<uint32_t>(rn) << 16 |
+ static_cast<uint32_t>(rm);
+
+ Emit32(encoding);
+}
+
+
void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
Register rm, Condition cond) {
CheckCondition(cond);
@@ -740,13 +758,6 @@
return true;
}
- // Check for MOV with an ROR.
- if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
- if (so.GetImmediate() != 0) {
- return true;
- }
- }
-
bool rn_is_valid = true;
// Check for single operand instructions and ADD/SUB.
@@ -792,6 +803,19 @@
}
}
+ // Check for register shift operand.
+ if (so.IsRegister() && so.IsShift()) {
+ if (opcode != MOV) {
+ return true;
+ }
+ // Check for MOV with an ROR.
+ if (so.GetShift() == ROR) {
+ if (so.GetImmediate() != 0) {
+ return true;
+ }
+ }
+ }
+
// The instruction can be encoded in 16 bits.
return false;
}
@@ -1614,7 +1638,6 @@
// branch the size may change if it so happens that other branches change size that change
// the distance to the target and that distance puts this branch over the limit for 16 bits.
if (size == Branch::k16Bit) {
- DCHECK(!force_32bit_branches_);
Emit16(0); // Space for a 16 bit branch.
} else {
Emit32(0); // Space for a 32 bit branch.
@@ -1622,7 +1645,7 @@
} else {
// Branch is to an unbound label. Emit space for it.
uint16_t branch_id = AddBranch(branch_type, pc, cond); // Unresolved branch.
- if (force_32bit_branches_ || force_32bit_) {
+ if (!CanRelocateBranches() || force_32bit_) {
Emit16(static_cast<uint16_t>(label->position_)); // Emit current label link.
Emit16(0); // another 16 bits.
} else {
@@ -2258,7 +2281,7 @@
uint32_t branch_location = branch->GetLocation();
uint16_t next = buffer_.Load<uint16_t>(branch_location); // Get next in chain.
if (changed) {
- DCHECK(!force_32bit_branches_);
+ DCHECK(CanRelocateBranches());
MakeHoleForBranch(branch->GetLocation(), 2);
if (branch->IsCompareAndBranch()) {
// A cbz/cbnz instruction has changed size. There is no valid encoding for
@@ -2718,21 +2741,21 @@
void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
- if (force_32bit_branches_) {
+ if (CanRelocateBranches()) {
+ cbz(r, label);
+ } else {
cmp(r, ShifterOperand(0));
b(label, EQ);
- } else {
- cbz(r, label);
}
}
void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
- if (force_32bit_branches_) {
+ if (CanRelocateBranches()) {
+ cbnz(r, label);
+ } else {
cmp(r, ShifterOperand(0));
b(label, NE);
- } else {
- cbnz(r, label);
}
}
} // namespace arm
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index e33c240..90d489f 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -31,8 +31,8 @@
class Thumb2Assembler FINAL : public ArmAssembler {
public:
- explicit Thumb2Assembler(bool force_32bit_branches = false)
- : force_32bit_branches_(force_32bit_branches),
+ explicit Thumb2Assembler(bool can_relocate_branches = true)
+ : can_relocate_branches_(can_relocate_branches),
force_32bit_(false),
it_cond_index_(kNoItCondition),
next_condition_(AL) {
@@ -52,8 +52,8 @@
return force_32bit_;
}
- bool IsForced32BitBranches() const {
- return force_32bit_branches_;
+ bool CanRelocateBranches() const {
+ return can_relocate_branches_;
}
void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
@@ -112,6 +112,8 @@
Condition cond = AL) OVERRIDE;
void mls(Register rd, Register rn, Register rm, Register ra,
Condition cond = AL) OVERRIDE;
+ void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+ Condition cond = AL) OVERRIDE;
void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL) OVERRIDE;
@@ -437,8 +439,12 @@
void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc = false);
void EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc = false);
- bool force_32bit_branches_; // Force the assembler to use 32 bit branch instructions.
- bool force_32bit_; // Force the assembler to use 32 bit thumb2 instructions.
+ // Whether the assembler can relocate branches. If false, unresolved branches will be
+ // emitted on 32bits.
+ bool can_relocate_branches_;
+
+ // Force the assembler to use 32 bit thumb2 instructions.
+ bool force_32bit_;
// IfThen conditions. Used to check that conditional instructions match the preceding IT.
Condition it_conditions_[4];
@@ -554,12 +560,21 @@
// size of the branch to change return true. Otherwise return false.
bool Resolve(uint32_t target) {
target_ = target;
- Size newsize = CalculateSize();
- if (size_ != newsize) {
- size_ = newsize;
- return true;
+ if (assembler_->CanRelocateBranches()) {
+ Size new_size = CalculateSize();
+ if (size_ != new_size) {
+ size_ = new_size;
+ return true;
+ }
+ return false;
+ } else {
+ if (kIsDebugBuild) {
+ Size new_size = CalculateSize();
+ // Check that the size has not increased.
+ DCHECK(!(new_size == k32Bit && size_ == k16Bit));
+ }
+ return false;
}
- return false;
}
// Move a cbz/cbnz branch. This is always forward.
@@ -575,6 +590,7 @@
// size of the branch instruction. It returns true if the branch
// has changed size.
bool Relocate(uint32_t oldlocation, int32_t delta) {
+ DCHECK(assembler_->CanRelocateBranches());
if (location_ > oldlocation) {
location_ += delta;
}
@@ -587,9 +603,9 @@
}
// Calculate the new size.
- Size newsize = CalculateSize();
- if (size_ != newsize) {
- size_ = newsize;
+ Size new_size = CalculateSize();
+ if (size_ != new_size) {
+ size_ = new_size;
return true;
}
return false;
@@ -631,15 +647,13 @@
private:
// Calculate the size of the branch instruction based on its type and offset.
Size CalculateSize() const {
- if (assembler_->IsForced32BitBranches()) {
- return k32Bit;
- }
if (target_ == kUnresolved) {
if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
return k32Bit;
}
- return k16Bit;
+ return assembler_->CanRelocateBranches() ? k16Bit : k32Bit;
}
+ // When the target is resolved, we know the best encoding for it.
int32_t delta = target_ - location_ - 4;
if (delta < 0) {
delta = -delta;
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 5f5561a..733441b 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -89,23 +89,24 @@
EXPECT_TRUE(CheckTools());
}
+#define __ GetAssembler()->
TEST_F(AssemblerThumb2Test, Sbfx) {
- GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1);
- GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8);
- GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16);
- GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32);
+ __ sbfx(arm::R0, arm::R1, 0, 1);
+ __ sbfx(arm::R0, arm::R1, 0, 8);
+ __ sbfx(arm::R0, arm::R1, 0, 16);
+ __ sbfx(arm::R0, arm::R1, 0, 32);
- GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1);
- GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8);
- GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16);
- GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24);
+ __ sbfx(arm::R0, arm::R1, 8, 1);
+ __ sbfx(arm::R0, arm::R1, 8, 8);
+ __ sbfx(arm::R0, arm::R1, 8, 16);
+ __ sbfx(arm::R0, arm::R1, 8, 24);
- GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1);
- GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8);
- GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16);
+ __ sbfx(arm::R0, arm::R1, 16, 1);
+ __ sbfx(arm::R0, arm::R1, 16, 8);
+ __ sbfx(arm::R0, arm::R1, 16, 16);
- GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1);
+ __ sbfx(arm::R0, arm::R1, 31, 1);
const char* expected =
"sbfx r0, r1, #0, #1\n"
@@ -127,21 +128,21 @@
}
TEST_F(AssemblerThumb2Test, Ubfx) {
- GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1);
- GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8);
- GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16);
- GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32);
+ __ ubfx(arm::R0, arm::R1, 0, 1);
+ __ ubfx(arm::R0, arm::R1, 0, 8);
+ __ ubfx(arm::R0, arm::R1, 0, 16);
+ __ ubfx(arm::R0, arm::R1, 0, 32);
- GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1);
- GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8);
- GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16);
- GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24);
+ __ ubfx(arm::R0, arm::R1, 8, 1);
+ __ ubfx(arm::R0, arm::R1, 8, 8);
+ __ ubfx(arm::R0, arm::R1, 8, 16);
+ __ ubfx(arm::R0, arm::R1, 8, 24);
- GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1);
- GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8);
- GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16);
+ __ ubfx(arm::R0, arm::R1, 16, 1);
+ __ ubfx(arm::R0, arm::R1, 16, 8);
+ __ ubfx(arm::R0, arm::R1, 16, 16);
- GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1);
+ __ ubfx(arm::R0, arm::R1, 31, 1);
const char* expected =
"ubfx r0, r1, #0, #1\n"
@@ -163,7 +164,7 @@
}
TEST_F(AssemblerThumb2Test, Vmstat) {
- GetAssembler()->vmstat();
+ __ vmstat();
const char* expected = "vmrs APSR_nzcv, FPSCR\n";
@@ -171,10 +172,10 @@
}
TEST_F(AssemblerThumb2Test, ldrexd) {
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
- GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
- GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7);
+ __ ldrexd(arm::R0, arm::R1, arm::R0);
+ __ ldrexd(arm::R0, arm::R1, arm::R1);
+ __ ldrexd(arm::R0, arm::R1, arm::R2);
+ __ ldrexd(arm::R5, arm::R3, arm::R7);
const char* expected =
"ldrexd r0, r1, [r0]\n"
@@ -185,10 +186,10 @@
}
TEST_F(AssemblerThumb2Test, strexd) {
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
- GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
- GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7);
+ __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
+ __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
+ __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
+ __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
const char* expected =
"strexd r9, r0, r1, [r0]\n"
@@ -199,9 +200,9 @@
}
TEST_F(AssemblerThumb2Test, LdrdStrd) {
- GetAssembler()->ldrd(arm::R0, arm::Address(arm::R2, 8));
- GetAssembler()->ldrd(arm::R0, arm::Address(arm::R12));
- GetAssembler()->strd(arm::R0, arm::Address(arm::R2, 8));
+ __ ldrd(arm::R0, arm::Address(arm::R2, 8));
+ __ ldrd(arm::R0, arm::Address(arm::R12));
+ __ strd(arm::R0, arm::Address(arm::R2, 8));
const char* expected =
"ldrd r0, r1, [r2, #8]\n"
@@ -211,7 +212,6 @@
}
TEST_F(AssemblerThumb2Test, eor) {
-#define __ GetAssembler()->
__ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
__ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
__ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
@@ -230,23 +230,47 @@
TEST_F(AssemblerThumb2Test, sub) {
__ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
__ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
+ __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+ __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
const char* expected =
"subs r1, r0, #42\n"
- "subw r1, r0, #42\n";
+ "subw r1, r0, #42\n"
+ "subs r1, r0, r2, asr #31\n"
+ "sub r1, r0, r2, asr #31\n";
DriverStr(expected, "sub");
}
TEST_F(AssemblerThumb2Test, add) {
__ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
__ add(arm::R1, arm::R0, arm::ShifterOperand(42));
+ __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+ __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
const char* expected =
"adds r1, r0, #42\n"
- "addw r1, r0, #42\n";
+ "addw r1, r0, #42\n"
+ "adds r1, r0, r2, asr #31\n"
+ "add r1, r0, r2, asr #31\n";
DriverStr(expected, "add");
}
+TEST_F(AssemblerThumb2Test, umull) {
+ __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+ const char* expected =
+ "umull r0, r1, r2, r3\n";
+ DriverStr(expected, "umull");
+}
+
+TEST_F(AssemblerThumb2Test, smull) {
+ __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+ const char* expected =
+ "smull r0, r1, r2, r3\n";
+ DriverStr(expected, "smull");
+}
+
TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
arm::StoreOperandType type = arm::kStoreWord;
int32_t offset = 4092;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b4a45c6..3cf458a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -979,7 +979,10 @@
oss.str(""); // Reset.
oss << kRuntimeISA;
key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
- key_value_store_->Put(OatHeader::kPicKey, compile_pic ? "true" : "false");
+ key_value_store_->Put(OatHeader::kPicKey,
+ compile_pic ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+ key_value_store_->Put(OatHeader::kDebuggableKey,
+ debuggable ? OatHeader::kTrueValue : OatHeader::kFalseValue);
}
}
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 7488578..3c145d7 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -313,8 +313,7 @@
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
- * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
- * stack and call the appropriate C helper.
+ * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
* NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
*
* The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -330,13 +329,10 @@
.extern \cxx_name
ENTRY \c_name
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case allocation triggers GC
- ldr r2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] @ pass caller Method*
- mov r3, r9 @ pass Thread::Current
- mov r12, sp
- str r12, [sp, #-16]! @ expand the frame and pass SP
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp
.cfi_adjust_cfa_offset 16
bl \cxx_name @ (method_idx, this, caller, Thread*, SP)
- add sp, #16 @ strip the extra frame
.cfi_adjust_cfa_offset -16
mov r12, r1 @ save Method*->code_
RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index f8b0734..6b16a2e5 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -459,8 +459,7 @@
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
- * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
- * stack and call the appropriate C helper.
+ * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
* NOTE: "this" is first visible argument of the target, and so can be found in arg1/x1.
*
* The helper will attempt to locate the target and return a 128-bit result in x0/x1 consisting
@@ -483,10 +482,9 @@
// Helper signature is always
// (method_idx, *this_object, *caller_method, *self, sp)
- ldr w2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] // pass caller Method*
- mov x3, xSELF // pass Thread::Current
- mov x4, sp
- bl \cxx_name // (method_idx, this, caller, Thread*, SP)
+ mov x2, xSELF // pass Thread::Current
+ mov x3, sp
+ bl \cxx_name // (method_idx, this, Thread*, SP)
mov xIP0, x1 // save Method*->code_
RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
cbz x0, 1f // did we find the target? if not go to exception delivery
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index ee5c59f..92b180e 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -439,8 +439,7 @@
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
- * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
- * stack and call the appropriate C helper.
+ * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
* NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
*
* The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
@@ -456,15 +455,13 @@
.extern \cxx_name
ENTRY \c_name
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME # save callee saves in case allocation triggers GC
- lw $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE+ARG_SLOT_SIZE($sp) # pass caller Method*
- addiu $t0, $sp, ARG_SLOT_SIZE # save $sp (remove arg slots)
- move $a3, rSELF # pass Thread::Current
- jal \cxx_name # (method_idx, this, caller, Thread*, $sp)
- sw $t0, 16($sp) # pass $sp
- move $a0, $v0 # save target Method*
+ move $a2, rSELF # pass Thread::Current
+ jal \cxx_name # (method_idx, this, Thread*, $sp)
+ addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
+ move $a0, $v0 # save target Method*
RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
beqz $v0, 1f
- move $t9, $v1 # save $v0->code_
+ move $t9, $v1 # save $v0->code_
jalr $zero, $t9
nop
1:
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index ff79b5d..b7320a6 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -529,10 +529,9 @@
.extern \cxx_name
ENTRY \c_name
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME # save callee saves in case allocation triggers GC
- lwu $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE($sp) # pass caller Method*
- move $a3, rSELF # pass Thread::Current
- jal \cxx_name # (method_idx, this, caller, Thread*, $sp)
- move $a4, $sp # pass $sp
+ move $a2, rSELF # pass Thread::Current
+ jal \cxx_name # (method_idx, this, Thread*, $sp)
+ move $a3, $sp # pass $sp
move $a0, $v0 # save target Method*
move $t9, $v1 # save $v0->code_
RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 6ebeba3..d62c1bc 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -278,8 +278,7 @@
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
- * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
- * stack and call the appropriate C helper.
+ * the method_idx. This wrapper will save arg1-arg3 and call the appropriate C helper.
* NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
*
* The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -297,19 +296,15 @@
movl %esp, %edx // remember SP
// Outgoing argument set up
- subl MACRO_LITERAL(12), %esp // alignment padding
- CFI_ADJUST_CFA_OFFSET(12)
PUSH edx // pass SP
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
- pushl 32+32(%edx) // pass caller Method*
- CFI_ADJUST_CFA_OFFSET(4)
PUSH ecx // pass arg2
PUSH eax // pass arg1
call VAR(cxx_name, 1) // cxx_name(arg1, arg2, arg3, Thread*, SP)
movl %edx, %edi // save code pointer in EDI
- addl MACRO_LITERAL(36), %esp // Pop arguments skip eax
- CFI_ADJUST_CFA_OFFSET(-36)
+ addl MACRO_LITERAL(20), %esp // Pop arguments skip eax
+ CFI_ADJUST_CFA_OFFSET(-20)
// Restore FPRs.
movsd 0(%esp), %xmm0
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index da4d92b..ddeb5b8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -341,8 +341,7 @@
/*
* All generated callsites for interface invokes and invocation slow paths will load arguments
* as usual - except instead of loading arg0/rdi with the target Method*, arg0/rdi will contain
- * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
- * stack and call the appropriate C helper.
+ * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
* NOTE: "this" is first visible argument of the target, and so can be found in arg1/rsi.
*
* The helper will attempt to locate the target and return a 128-bit result in rax/rdx consisting
@@ -362,11 +361,10 @@
// Helper signature is always
// (method_idx, *this_object, *caller_method, *self, sp)
- movl FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE(%rsp), %edx // pass caller Method*
- movq %gs:THREAD_SELF_OFFSET, %rcx // pass Thread
- movq %rsp, %r8 // pass SP
+ movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread
+ movq %rsp, %rcx // pass SP
- call VAR(cxx_name, 1) // cxx_name(arg1, arg2, caller method*, Thread*, SP)
+ call VAR(cxx_name, 1) // cxx_name(arg1, arg2, Thread*, SP)
// save the code pointer
movq %rax, %rdi
movq %rdx, %rax
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 8b34374..35b50d1 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -39,6 +39,7 @@
struct LogVerbosity {
bool class_linker; // Enabled with "-verbose:class".
bool compiler;
+ bool deopt;
bool gc;
bool heap;
bool jdwp;
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index f272d88..07cadc4 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -107,7 +107,7 @@
}
int FdFile::Close() {
- int result = TEMP_FAILURE_RETRY(close(fd_));
+ int result = close(fd_);
// Test here, so the file is closed and not leaked.
if (kCheckSafeUsage) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b099088..292f830 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -819,6 +819,34 @@
}
}
+const OatFile* ClassLinker::GetBootOatFile() {
+ // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
+ // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
+ // exist if the boot class-path isn't empty.
+ if (boot_class_path_.empty()) {
+ return nullptr;
+ }
+ const DexFile* boot_dex_file = boot_class_path_[0];
+ // Is it from an oat file?
+ if (boot_dex_file->GetOatDexFile() != nullptr) {
+ return boot_dex_file->GetOatDexFile()->GetOatFile();
+ }
+ return nullptr;
+}
+
+const OatFile* ClassLinker::GetPrimaryOatFile() {
+ ReaderMutexLock mu(Thread::Current(), dex_lock_);
+ const OatFile* boot_oat_file = GetBootOatFile();
+ if (boot_oat_file != nullptr) {
+ for (const OatFile* oat_file : oat_files_) {
+ if (oat_file != boot_oat_file) {
+ return oat_file;
+ }
+ }
+ }
+ return nullptr;
+}
+
// Check for class-def collisions in dex files.
//
// This works by maintaining a heap with one class from each dex file, sorted by the class
@@ -835,18 +863,7 @@
// Add dex files from already loaded oat files, but skip boot.
{
- // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
- // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
- // exist if the boot class-path isn't empty.
- const OatFile* boot_oat = nullptr;
- if (!boot_class_path_.empty()) {
- const DexFile* boot_dex_file = boot_class_path_[0];
- // Is it from an oat file?
- if (boot_dex_file->GetOatDexFile() != nullptr) {
- boot_oat = boot_dex_file->GetOatDexFile()->GetOatFile();
- }
- }
-
+ const OatFile* boot_oat = GetBootOatFile();
for (const OatFile* loaded_oat_file : oat_files_) {
if (loaded_oat_file == boot_oat) {
continue;
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 57989b2..95c8aa0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -295,6 +295,10 @@
return boot_class_path_;
}
+ // Returns the first non-image oat file in the class path.
+ const OatFile* GetPrimaryOatFile()
+ LOCKS_EXCLUDED(dex_lock_);
+
void VisitClasses(ClassVisitor* visitor, void* arg)
LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -615,6 +619,9 @@
const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
LOCKS_EXCLUDED(dex_lock_);
+ // Returns the boot image oat file.
+ const OatFile* GetBootOatFile() SHARED_LOCKS_REQUIRED(dex_lock_);
+
mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
mirror::Class* proxy_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 4bc9f98..852ba49 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -411,7 +411,7 @@
}
void SingleStepControl::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
- visitor->VisitRootIfNonNull(reinterpret_cast<mirror::Object**>(&method_), root_info);
+ method_.VisitRootIfNonNull(visitor, root_info);
}
void SingleStepControl::AddDexPc(uint32_t dex_pc) {
@@ -2929,10 +2929,11 @@
if (!IsDebuggerActive()) {
return;
}
- StackHandleScope<1> handle_scope(Thread::Current());
+ Thread* const self = Thread::Current();
+ StackHandleScope<1> handle_scope(self);
Handle<mirror::Throwable> h_exception(handle_scope.NewHandle(exception_object));
std::unique_ptr<Context> context(Context::Create());
- CatchLocationFinder clf(Thread::Current(), h_exception, context.get());
+ CatchLocationFinder clf(self, h_exception, context.get());
clf.WalkStack(/* include_transitions */ false);
JDWP::EventLocation exception_throw_location;
SetEventLocation(&exception_throw_location, clf.GetThrowMethod(), clf.GetThrowDexPc());
@@ -3981,7 +3982,7 @@
Handle<mirror::Object> object_result = hs.NewHandle(is_object_result ? result.GetL() : nullptr);
Handle<mirror::Throwable> exception = hs.NewHandle(soa.Self()->GetException());
soa.Self()->ClearException();
- pReq->exception = gRegistry->Add(exception.Get());
+ pReq->exception = gRegistry->Add(exception);
if (pReq->exception != 0) {
VLOG(jdwp) << " JDWP invocation returning with exception=" << exception.Get()
<< " " << exception->Dump();
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 789a0a4..811d345 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -109,8 +109,8 @@
return stack_depth_;
}
- mirror::ArtMethod* GetMethod() const {
- return method_;
+ mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return method_.Read();
}
const std::set<uint32_t>& GetDexPcs() const {
@@ -138,7 +138,7 @@
// set of DEX pcs associated to the source line number where the suspension occurred.
// This is used to support SD_INTO and SD_OVER single-step depths so we detect when a single-step
// causes the execution of an instruction in a different method or at a different line number.
- mirror::ArtMethod* method_;
+ GcRoot<mirror::ArtMethod> method_;
std::set<uint32_t> dex_pcs_;
DISALLOW_COPY_AND_ASSIGN(SingleStepControl);
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 0c5210d..b1d933d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1402,25 +1402,23 @@
template <typename ElfTypes>
bool ElfFileImpl<ElfTypes>::FixupDebugSections(typename std::make_signed<Elf_Off>::type base_address_delta) {
- const Elf_Shdr* debug_info = FindSectionByName(".debug_info");
- const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
- const Elf_Shdr* debug_str = FindSectionByName(".debug_str");
- const Elf_Shdr* strtab_sec = FindSectionByName(".strtab");
- const Elf_Shdr* symtab_sec = FindSectionByName(".symtab");
-
- if (debug_info == nullptr || debug_abbrev == nullptr ||
- debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
- // Release version of ART does not generate debug info.
- return true;
- }
if (base_address_delta == 0) {
return true;
}
- if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
- return false;
+ if (FindSectionByName(".debug_frame") != nullptr) {
+ if (!ApplyOatPatchesTo(".debug_frame", base_address_delta)) {
+ return false;
+ }
}
- if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) {
- return false;
+ if (FindSectionByName(".debug_info") != nullptr) {
+ if (!ApplyOatPatchesTo(".debug_info", base_address_delta)) {
+ return false;
+ }
+ }
+ if (FindSectionByName(".debug_line") != nullptr) {
+ if (!ApplyOatPatchesTo(".debug_line", base_address_delta)) {
+ return false;
+ }
}
return true;
}
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 9292cff..625e695 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -38,25 +38,34 @@
namespace art {
-inline mirror::ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+inline mirror::ArtMethod* GetCalleeSaveMethodCaller(StackReference<mirror::ArtMethod>* sp,
+ Runtime::CalleeSaveType type,
+ bool do_caller_check = false)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- auto* refs_only_sp = self->GetManagedStack()->GetTopQuickFrame();
- DCHECK_EQ(refs_only_sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(type));
+ DCHECK_EQ(sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(type));
const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
auto* caller_sp = reinterpret_cast<StackReference<mirror::ArtMethod>*>(
- reinterpret_cast<uintptr_t>(refs_only_sp) + callee_frame_size);
+ reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
auto* caller = caller_sp->AsMirrorPtr();
- if (kIsDebugBuild) {
- NthCallerVisitor visitor(self, 1, true);
+ if (kIsDebugBuild && do_caller_check) {
+ // Note that do_caller_check is optional, as this method can be called by
+ // stubs, and tests without a proper call stack.
+ NthCallerVisitor visitor(Thread::Current(), 1, true);
visitor.WalkStack();
- CHECK(caller == visitor.caller);
+ CHECK_EQ(caller, visitor.caller);
}
return caller;
}
+inline mirror::ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return GetCalleeSaveMethodCaller(
+ self->GetManagedStack()->GetTopQuickFrame(), type, true /* do_caller_check */);
+}
+
template <const bool kAccessCheck>
ALWAYS_INLINE
inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 6a8aaf2..1b1ef66 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/logging.h"
#include "callee_save_frame.h"
#include "dex_file-inl.h"
#include "interpreter/interpreter.h"
@@ -29,6 +30,12 @@
extern "C" NO_RETURN void artDeoptimize(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
+
+ if (VLOG_IS_ON(deopt)) {
+ LOG(INFO) << "Deopting:";
+ self->Dump(LOG(INFO));
+ }
+
self->SetException(Thread::GetDeoptimizationException());
self->QuickDeliverException();
}
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 46629f5..9148878 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -25,8 +25,7 @@
namespace art {
-extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
- Thread* self)
+extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx, Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Called to ensure static storage base is initialized for direct static field reads and writes.
// A class may be accessing another class' fields when it doesn't have access, as access has been
@@ -36,8 +35,7 @@
return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
}
-extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx,
- Thread* self)
+extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Called when method->dex_cache_resolved_types_[] misses.
ScopedQuickEntrypointChecks sqec(self);
@@ -45,8 +43,7 @@
return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
}
-extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
- Thread* self)
+extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Called when caller isn't guaranteed to have access to a type and the dex cache may be
// unpopulated.
@@ -55,8 +52,7 @@
return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
}
-extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx,
- Thread* self)
+extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kRefsOnly);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2e7e2df..345b0ad 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -294,8 +294,13 @@
static mirror::ArtMethod* GetCallingMethod(StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
- uint8_t* previous_sp = reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
- return reinterpret_cast<StackReference<mirror::ArtMethod>*>(previous_sp)->AsMirrorPtr();
+ return GetCalleeSaveMethodCaller(sp, Runtime::kRefsAndArgs);
+ }
+
+ static uint32_t GetCallingDexPc(StackReference<mirror::ArtMethod>* sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
+ return GetCallingMethod(sp)->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
}
// For the given quick ref and args quick frame, return the caller's PC.
@@ -827,12 +832,13 @@
// Compute details about the called method (avoid GCs)
ClassLinker* linker = Runtime::Current()->GetClassLinker();
- mirror::ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
InvokeType invoke_type;
MethodReference called_method(nullptr, 0);
const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+ mirror::ArtMethod* caller = nullptr;
if (!called_method_known_on_entry) {
- uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
+ caller = QuickArgumentVisitor::GetCallingMethod(sp);
+ uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
const DexFile::CodeItem* code;
called_method.dex_file = caller->GetDexFile();
code = caller->GetCodeItem();
@@ -1946,16 +1952,13 @@
// to hold the mutator lock (see SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) annotations).
template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method,
- Thread* self, StackReference<mirror::ArtMethod>* sp);
-
-template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method,
- Thread* self, StackReference<mirror::ArtMethod>* sp) {
+static TwoWordReturn artInvokeCommon(uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
+ StackReference<mirror::ArtMethod>* sp) {
ScopedQuickEntrypointChecks sqec(self);
DCHECK_EQ(sp->AsMirrorPtr(), Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+ mirror::ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
type);
if (UNLIKELY(method == nullptr)) {
@@ -1994,7 +1997,6 @@
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \
TwoWordReturn artInvokeCommon<type, access_check>(uint32_t method_idx, \
mirror::Object* this_object, \
- mirror::ArtMethod* caller_method, \
Thread* self, \
StackReference<mirror::ArtMethod>* sp) \
@@ -2012,58 +2014,58 @@
// See comments in runtime_support_asm.S
extern "C" TwoWordReturn artInvokeInterfaceTrampolineWithAccessCheck(
- uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* self,
+ uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return artInvokeCommon<kInterface, true>(method_idx, this_object,
- caller_method, self, sp);
+ return artInvokeCommon<kInterface, true>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeDirectTrampolineWithAccessCheck(
- uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* self,
+ uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method,
- self, sp);
+ return artInvokeCommon<kDirect, true>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeStaticTrampolineWithAccessCheck(
- uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* self,
+ uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method,
- self, sp);
+ return artInvokeCommon<kStatic, true>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeSuperTrampolineWithAccessCheck(
- uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* self,
+ uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method,
- self, sp);
+ return artInvokeCommon<kSuper, true>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeVirtualTrampolineWithAccessCheck(
- uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* self,
+ uint32_t method_idx,
+ mirror::Object* this_object,
+ Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method,
- self, sp);
+ return artInvokeCommon<kVirtual, true>(method_idx, this_object, self, sp);
}
// Determine target of interface dispatch. This object is known non-null.
extern "C" TwoWordReturn artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_method,
mirror::Object* this_object,
- mirror::ArtMethod* caller_method,
Thread* self,
StackReference<mirror::ArtMethod>* sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
+ mirror::ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
mirror::ArtMethod* method;
if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
@@ -2075,12 +2077,7 @@
} else {
DCHECK(interface_method == Runtime::Current()->GetResolutionMethod());
- // Find the caller PC.
- constexpr size_t pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsAndArgs);
- uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + pc_offset);
-
- // Map the caller PC to a dex PC.
- uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
+ uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
const DexFile::CodeItem* code = caller_method->GetCodeItem();
CHECK_LT(dex_pc, code->insns_size_in_code_units_);
const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 53e56da..5401b56 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -373,8 +373,7 @@
: mark_sweep_(mark_sweep), holder_(holder), offset_(offset) {
}
- void operator()(const Object* obj) const ALWAYS_INLINE
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ void operator()(const Object* obj) const ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS {
if (kProfileLargeObjects) {
// TODO: Differentiate between marking and testing somehow.
++mark_sweep_->large_object_test_;
@@ -385,17 +384,51 @@
(kIsDebugBuild && large_object_space != nullptr &&
!large_object_space->Contains(obj)))) {
LOG(INTERNAL_FATAL) << "Tried to mark " << obj << " not contained by any spaces";
- LOG(INTERNAL_FATAL) << "Attempting see if it's a bad root";
- mark_sweep_->VerifyRoots();
if (holder_ != nullptr) {
+ size_t holder_size = holder_->SizeOf();
ArtField* field = holder_->FindFieldByOffset(offset_);
- LOG(INTERNAL_FATAL) << "Field info: holder=" << holder_
+ LOG(INTERNAL_FATAL) << "Field info: "
+ << " holder=" << holder_
+ << " holder_size=" << holder_size
<< " holder_type=" << PrettyTypeOf(holder_)
<< " offset=" << offset_.Uint32Value()
- << " field=" << (field != nullptr ? field->GetName() : "nullptr");
+ << " field=" << (field != nullptr ? field->GetName() : "nullptr")
+ << " field_type="
+ << (field != nullptr ? field->GetTypeDescriptor() : "")
+ << " first_ref_field_offset="
+ << (holder_->IsClass()
+ ? holder_->AsClass()->GetFirstReferenceStaticFieldOffset()
+ : holder_->GetClass()->GetFirstReferenceInstanceFieldOffset())
+ << " num_of_ref_fields="
+ << (holder_->IsClass()
+ ? holder_->AsClass()->NumReferenceStaticFields()
+ : holder_->GetClass()->NumReferenceInstanceFields())
+ << "\n";
}
PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
+ {
+ LOG(INTERNAL_FATAL) << "Attempting see if it's a bad root";
+ Thread* self = Thread::Current();
+ if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
+ mark_sweep_->VerifyRoots();
+ } else {
+ const bool heap_bitmap_exclusive_locked =
+ Locks::heap_bitmap_lock_->IsExclusiveHeld(self);
+ if (heap_bitmap_exclusive_locked) {
+ Locks::heap_bitmap_lock_->ExclusiveUnlock(self);
+ }
+ Locks::mutator_lock_->SharedUnlock(self);
+ ThreadList* tl = Runtime::Current()->GetThreadList();
+ tl->SuspendAll(__FUNCTION__);
+ mark_sweep_->VerifyRoots();
+ tl->ResumeAll();
+ Locks::mutator_lock_->SharedLock(self);
+ if (heap_bitmap_exclusive_locked) {
+ Locks::heap_bitmap_lock_->ExclusiveLock(self);
+ }
+ }
+ }
LOG(FATAL) << "Can't mark invalid object";
}
}
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index f350038..99f5d45 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -203,6 +203,9 @@
oat_file_option_string += ImageHeader::GetOatLocationFromImageLocation(image_filename);
arg_vector.push_back(oat_file_option_string);
+ // Note: we do not generate a fully debuggable boot image so we do not pass the
+ // compiler flag --debuggable here.
+
Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
CHECK_EQ(image_isa, kRuntimeISA)
<< "We should always be generating an image for the current isa.";
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 9006257..317106b 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -767,8 +767,12 @@
AbortTransactionOrFail(self, "String.getCharsNoCheck with null object");
return;
}
+ DCHECK_GE(start, 0);
+ DCHECK_GE(end, string->GetLength());
StackHandleScope<1> hs(self);
Handle<mirror::CharArray> h_char_array(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset + 3)->AsCharArray()));
+ DCHECK_LE(index, h_char_array->GetLength());
+ DCHECK_LE(end - start, h_char_array->GetLength() - index);
string->GetChars(start, end, h_char_array, index);
}
@@ -785,6 +789,20 @@
result->SetC(string->CharAt(index));
}
+// This allows setting chars from the new style of String objects during compilation.
+static void UnstartedStringSetCharAt(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ jint index = shadow_frame->GetVReg(arg_offset + 1);
+ jchar c = shadow_frame->GetVReg(arg_offset + 2);
+ mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString();
+ if (string == nullptr) {
+ AbortTransactionOrFail(self, "String.setCharAt with null object");
+ return;
+ }
+ string->SetCharAt(index, c);
+}
+
// This allows creating the new style of String objects during compilation.
static void UnstartedStringFactoryNewStringFromChars(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
@@ -800,19 +818,51 @@
}
// This allows creating the new style of String objects during compilation.
+static void UnstartedStringFactoryNewStringFromString(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::String* to_copy = shadow_frame->GetVRegReference(arg_offset)->AsString();
+ if (to_copy == nullptr) {
+ AbortTransactionOrFail(self, "StringFactory.newStringFromString with null object");
+ return;
+ }
+ StackHandleScope<1> hs(self);
+ Handle<mirror::String> h_string(hs.NewHandle(to_copy));
+ Runtime* runtime = Runtime::Current();
+ gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
+ result->SetL(mirror::String::AllocFromString<true>(self, h_string->GetLength(), h_string, 0,
+ allocator));
+}
+
+// This allows creating the new style of String objects during compilation.
static void UnstartedStringFastSubstring(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
jint start = shadow_frame->GetVReg(arg_offset + 1);
jint length = shadow_frame->GetVReg(arg_offset + 2);
+ DCHECK_GE(start, 0);
DCHECK_GE(length, 0);
StackHandleScope<1> hs(self);
Handle<mirror::String> h_string(hs.NewHandle(shadow_frame->GetVRegReference(arg_offset)->AsString()));
+ DCHECK_LE(start, h_string->GetLength());
+ DCHECK_LE(start + length, h_string->GetLength());
Runtime* runtime = Runtime::Current();
gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
result->SetL(mirror::String::AllocFromString<true>(self, length, h_string, start, allocator));
}
+// This allows getting the char array for new style of String objects during compilation.
+static void UnstartedStringToCharArray(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::String* string = shadow_frame->GetVRegReference(arg_offset)->AsString();
+ if (string == nullptr) {
+ AbortTransactionOrFail(self, "String.charAt with null object");
+ return;
+ }
+ result->SetL(string->ToCharArray(self));
+}
+
static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self,
mirror::ArtMethod* method ATTRIBUTE_UNUSED,
mirror::Object* receiver ATTRIBUTE_UNUSED,
@@ -1141,10 +1191,16 @@
&UnstartedStringGetCharsNoCheck },
{ "char java.lang.String.charAt(int)",
&UnstartedStringCharAt },
+ { "void java.lang.String.setCharAt(int, char)",
+ &UnstartedStringSetCharAt },
{ "java.lang.String java.lang.StringFactory.newStringFromChars(int, int, char[])",
&UnstartedStringFactoryNewStringFromChars },
+ { "java.lang.String java.lang.StringFactory.newStringFromString(java.lang.String)",
+ &UnstartedStringFactoryNewStringFromString },
{ "java.lang.String java.lang.String.fastSubstring(int, int)",
&UnstartedStringFastSubstring },
+ { "char[] java.lang.String.toCharArray()",
+ &UnstartedStringToCharArray },
};
for (auto& def : defs) {
@@ -1228,6 +1284,8 @@
std::string name(PrettyMethod(shadow_frame->GetMethod()));
const auto& iter = invoke_handlers_.find(name);
if (iter != invoke_handlers_.end()) {
+ // Clear out the result in case it's not zeroed out.
+ result->SetL(0);
(*iter->second)(self, shadow_frame, result, arg_offset);
} else {
// Not special, continue with regular interpreter execution.
@@ -1241,6 +1299,8 @@
std::string name(PrettyMethod(method));
const auto& iter = jni_handlers_.find(name);
if (iter != jni_handlers_.end()) {
+ // Clear out the result in case it's not zeroed out.
+ result->SetL(0);
(*iter->second)(self, method, receiver, args, result);
} else if (Runtime::Current()->IsActiveTransaction()) {
AbortTransactionF(self, "Attempt to invoke native method in non-started runtime: %s",
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index ab3f2e4..ff75268 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -32,6 +32,8 @@
#include "scoped_thread_state_change.h"
#include "thread-inl.h"
+#include "handle_scope-inl.h"
+
/*
General notes:
@@ -108,20 +110,32 @@
* Stuff to compare against when deciding if a mod matches. Only the
* values for mods valid for the event being evaluated will be filled in.
* The rest will be zeroed.
+ * Must be allocated on the stack only. This is enforced by removing the
+ * operator new.
*/
struct ModBasket {
- ModBasket() : pLoc(nullptr), thread(nullptr), locationClass(nullptr), exceptionClass(nullptr),
- caught(false), field(nullptr), thisPtr(nullptr) { }
+ explicit ModBasket(Thread* self)
+ : hs(self), pLoc(nullptr), thread(self),
+ locationClass(hs.NewHandle<mirror::Class>(nullptr)),
+ exceptionClass(hs.NewHandle<mirror::Class>(nullptr)),
+ caught(false),
+ field(nullptr),
+ thisPtr(hs.NewHandle<mirror::Object>(nullptr)) { }
- const EventLocation* pLoc; /* LocationOnly */
- std::string className; /* ClassMatch/ClassExclude */
- Thread* thread; /* ThreadOnly */
- mirror::Class* locationClass; /* ClassOnly */
- mirror::Class* exceptionClass; /* ExceptionOnly */
- bool caught; /* ExceptionOnly */
- ArtField* field; /* FieldOnly */
- mirror::Object* thisPtr; /* InstanceOnly */
+ StackHandleScope<3> hs;
+ const EventLocation* pLoc; /* LocationOnly */
+ std::string className; /* ClassMatch/ClassExclude */
+ Thread* const thread; /* ThreadOnly */
+ MutableHandle<mirror::Class> locationClass; /* ClassOnly */
+ MutableHandle<mirror::Class> exceptionClass; /* ExceptionOnly */
+ bool caught; /* ExceptionOnly */
+ ArtField* field; /* FieldOnly */
+ MutableHandle<mirror::Object> thisPtr; /* InstanceOnly */
/* nothing for StepOnly -- handled differently */
+
+ private:
+ DISALLOW_ALLOCATION(); // forbids allocation on the heap.
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ModBasket);
};
static bool NeedsFullDeoptimization(JdwpEventKind eventKind) {
@@ -457,7 +471,7 @@
}
break;
case MK_CLASS_ONLY:
- if (!Dbg::MatchType(basket.locationClass, pMod->classOnly.refTypeId)) {
+ if (!Dbg::MatchType(basket.locationClass.Get(), pMod->classOnly.refTypeId)) {
return false;
}
break;
@@ -478,7 +492,7 @@
break;
case MK_EXCEPTION_ONLY:
if (pMod->exceptionOnly.refTypeId != 0 &&
- !Dbg::MatchType(basket.exceptionClass, pMod->exceptionOnly.refTypeId)) {
+ !Dbg::MatchType(basket.exceptionClass.Get(), pMod->exceptionOnly.refTypeId)) {
return false;
}
if ((basket.caught && !pMod->exceptionOnly.caught) ||
@@ -497,7 +511,7 @@
}
break;
case MK_INSTANCE_ONLY:
- if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr)) {
+ if (!Dbg::MatchInstance(pMod->instanceOnly.objectId, basket.thisPtr.Get())) {
return false;
}
break;
@@ -825,12 +839,11 @@
DCHECK(pLoc->method != nullptr);
DCHECK_EQ(pLoc->method->IsStatic(), thisPtr == nullptr);
- ModBasket basket;
+ ModBasket basket(Thread::Current());
basket.pLoc = pLoc;
- basket.locationClass = pLoc->method->GetDeclaringClass();
- basket.thisPtr = thisPtr;
- basket.thread = Thread::Current();
- basket.className = Dbg::GetClassName(basket.locationClass);
+ basket.locationClass.Assign(pLoc->method->GetDeclaringClass());
+ basket.thisPtr.Assign(thisPtr);
+ basket.className = Dbg::GetClassName(basket.locationClass.Get());
/*
* On rare occasions we may need to execute interpreted code in the VM
@@ -924,16 +937,15 @@
DCHECK_EQ(fieldValue != nullptr, is_modification);
DCHECK_EQ(field->IsStatic(), this_object == nullptr);
- ModBasket basket;
+ ModBasket basket(Thread::Current());
basket.pLoc = pLoc;
- basket.locationClass = pLoc->method->GetDeclaringClass();
- basket.thisPtr = this_object;
- basket.thread = Thread::Current();
- basket.className = Dbg::GetClassName(basket.locationClass);
+ basket.locationClass.Assign(pLoc->method->GetDeclaringClass());
+ basket.thisPtr.Assign(this_object);
+ basket.className = Dbg::GetClassName(basket.locationClass.Get());
basket.field = field;
if (InvokeInProgress()) {
- VLOG(jdwp) << "Not posting field event during invoke";
+ VLOG(jdwp) << "Not posting field event during invoke (" << basket.className << ")";
return;
}
@@ -975,7 +987,7 @@
uint8_t tag;
{
ScopedObjectAccessUnchecked soa(Thread::Current());
- tag = Dbg::TagFromObject(soa, basket.thisPtr);
+ tag = Dbg::TagFromObject(soa, basket.thisPtr.Get());
}
for (const JdwpEvent* pEvent : match_list) {
@@ -1028,8 +1040,7 @@
return;
}
- ModBasket basket;
- basket.thread = thread;
+ ModBasket basket(thread);
std::vector<JdwpEvent*> match_list;
const JdwpEventKind match_kind = (start) ? EK_THREAD_START : EK_THREAD_DEATH;
@@ -1106,18 +1117,15 @@
VLOG(jdwp) << "Unexpected: exception event with empty throw location";
}
- ModBasket basket;
+ ModBasket basket(Thread::Current());
basket.pLoc = pThrowLoc;
if (pThrowLoc->method != nullptr) {
- basket.locationClass = pThrowLoc->method->GetDeclaringClass();
- } else {
- basket.locationClass = nullptr;
+ basket.locationClass.Assign(pThrowLoc->method->GetDeclaringClass());
}
- basket.thread = Thread::Current();
- basket.className = Dbg::GetClassName(basket.locationClass);
- basket.exceptionClass = exception_object->GetClass();
+ basket.className = Dbg::GetClassName(basket.locationClass.Get());
+ basket.exceptionClass.Assign(exception_object->GetClass());
basket.caught = (pCatchLoc->method != 0);
- basket.thisPtr = thisPtr;
+ basket.thisPtr.Assign(thisPtr);
/* don't try to post an exception caused by the debugger */
if (InvokeInProgress()) {
@@ -1188,10 +1196,9 @@
void JdwpState::PostClassPrepare(mirror::Class* klass) {
DCHECK(klass != nullptr);
- ModBasket basket;
- basket.locationClass = klass;
- basket.thread = Thread::Current();
- basket.className = Dbg::GetClassName(basket.locationClass);
+ ModBasket basket(Thread::Current());
+ basket.locationClass.Assign(klass);
+ basket.className = Dbg::GetClassName(basket.locationClass.Get());
/* suppress class prep caused by debugger */
if (InvokeInProgress()) {
@@ -1214,7 +1221,7 @@
// debuggers seem to like that. There might be some advantage to honesty,
// since the class may not yet be verified.
int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
- JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
+ JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass.Get());
std::string temp;
std::string signature(basket.locationClass->GetDescriptor(&temp));
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index a42a58f..2b28f7d 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -36,17 +36,45 @@
}
JDWP::RefTypeId ObjectRegistry::AddRefType(mirror::Class* c) {
- return InternalAdd(c);
+ return Add(c);
+}
+
+JDWP::RefTypeId ObjectRegistry::AddRefType(Handle<mirror::Class> c_h) {
+ return Add(c_h);
}
JDWP::ObjectId ObjectRegistry::Add(mirror::Object* o) {
- return InternalAdd(o);
-}
-
-JDWP::ObjectId ObjectRegistry::InternalAdd(mirror::Object* o) {
if (o == nullptr) {
return 0;
}
+ Thread* const self = Thread::Current();
+ StackHandleScope<1> hs(self);
+ return InternalAdd(hs.NewHandle(o));
+}
+
+// Template instantiations must be declared below.
+template<class T>
+JDWP::ObjectId ObjectRegistry::Add(Handle<T> obj_h) {
+ if (obj_h.Get() == nullptr) {
+ return 0;
+ }
+ return InternalAdd(obj_h);
+}
+
+// Explicit template instantiation.
+template
+SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_)
+JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Object> obj_h);
+
+template
+SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_)
+JDWP::ObjectId ObjectRegistry::Add(Handle<mirror::Throwable> obj_h);
+
+template<class T>
+JDWP::ObjectId ObjectRegistry::InternalAdd(Handle<T> obj_h) {
+ CHECK(obj_h.Get() != nullptr);
Thread* const self = Thread::Current();
self->AssertNoPendingException();
@@ -55,9 +83,6 @@
Locks::thread_list_lock_->AssertNotHeld(self);
Locks::thread_suspend_count_lock_->AssertNotHeld(self);
- StackHandleScope<1> hs(self);
- Handle<mirror::Object> obj_h(hs.NewHandle(o));
-
// Call IdentityHashCode here to avoid a lock level violation between lock_ and monitor_lock.
int32_t identity_hash_code = obj_h->IdentityHashCode();
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index 27a4e55..4c149cd 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -23,6 +23,7 @@
#include <map>
#include "base/casts.h"
+#include "handle.h"
#include "jdwp/jdwp.h"
#include "safe_map.h"
@@ -65,11 +66,23 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
LOCKS_EXCLUDED(Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_);
+
JDWP::RefTypeId AddRefType(mirror::Class* c)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
LOCKS_EXCLUDED(Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_);
+ template<class T>
+ JDWP::ObjectId Add(Handle<T> obj_h)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(Locks::thread_list_lock_,
+ Locks::thread_suspend_count_lock_);
+
+ JDWP::RefTypeId AddRefType(Handle<mirror::Class> c_h)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(Locks::thread_list_lock_,
+ Locks::thread_suspend_count_lock_);
+
template<typename T> T Get(JDWP::ObjectId id, JDWP::JdwpError* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (id == 0) {
@@ -98,7 +111,8 @@
jobject GetJObject(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
- JDWP::ObjectId InternalAdd(mirror::Object* o)
+ template<class T>
+ JDWP::ObjectId InternalAdd(Handle<T> obj_h)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
LOCKS_EXCLUDED(lock_,
Locks::thread_list_lock_,
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c223e2e..4f6aabc 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -27,6 +27,8 @@
constexpr uint8_t OatHeader::kOatMagic[4];
constexpr uint8_t OatHeader::kOatVersion[4];
+constexpr const char OatHeader::kTrueValue[];
+constexpr const char OatHeader::kFalseValue[];
static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
size_t estimate = 0U;
@@ -443,9 +445,16 @@
}
bool OatHeader::IsPic() const {
- const char* pic_string = GetStoreValueByKey(OatHeader::kPicKey);
- static const char kTrue[] = "true";
- return (pic_string != nullptr && strncmp(pic_string, kTrue, sizeof(kTrue)) == 0);
+ return IsKeyEnabled(OatHeader::kPicKey);
+}
+
+bool OatHeader::IsDebuggable() const {
+ return IsKeyEnabled(OatHeader::kDebuggableKey);
+}
+
+bool OatHeader::IsKeyEnabled(const char* key) const {
+ const char* key_value = GetStoreValueByKey(key);
+ return (key_value != nullptr && strncmp(key_value, kTrueValue, sizeof(kTrueValue)) == 0);
}
void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
diff --git a/runtime/oat.h b/runtime/oat.h
index aaf442a..604e161 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,14 +32,18 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '6', '2', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '6', '3', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static constexpr const char* kPicKey = "pic";
+ static constexpr const char* kDebuggableKey = "debuggable";
static constexpr const char* kClassPathKey = "classpath";
+ static constexpr const char kTrueValue[] = "true";
+ static constexpr const char kFalseValue[] = "false";
+
static OatHeader* Create(InstructionSet instruction_set,
const InstructionSetFeatures* instruction_set_features,
const std::vector<const DexFile*>* dex_files,
@@ -99,6 +103,7 @@
size_t GetHeaderSize() const;
bool IsPic() const;
+ bool IsDebuggable() const;
private:
OatHeader(InstructionSet instruction_set,
@@ -108,6 +113,9 @@
uint32_t image_file_location_oat_data_begin,
const SafeMap<std::string, std::string>* variable_data);
+ // Returns true if the value of the given key is "true", false otherwise.
+ bool IsKeyEnabled(const char* key) const;
+
void Flatten(const SafeMap<std::string, std::string>* variable_data);
uint8_t magic_[4];
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index b0cbd0e..63ee4b1 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -703,6 +703,10 @@
// TODO: Check against oat_patches. b/18144996
}
+bool OatFile::IsDebuggable() const {
+ return GetOatHeader().IsDebuggable();
+}
+
static constexpr char kDexClassPathEncodingSeparator = '*';
std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index b32dd22..12e9f6c 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -81,6 +81,9 @@
bool IsPic() const;
+ // Indicates whether the oat file was compiled with full debugging capability.
+ bool IsDebuggable() const;
+
ElfFile* GetElfFile() const {
CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
<< "Cannot get an elf file from " << GetLocation();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index d07c09c..094d8b7 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -417,7 +417,7 @@
<< secondary_dex_location
<< ". Expected: " << expected_secondary_checksum
<< ", Actual: " << actual_secondary_checksum;
- return false;
+ return true;
}
} else {
// If we can't get the checksum for the secondary location, we assume
@@ -690,12 +690,20 @@
return false;
}
+ ClassLinker* linker = runtime->GetClassLinker();
+ CHECK(linker != nullptr) << "ClassLinker is not created yet";
+ const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
+ const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
+
std::vector<std::string> argv;
argv.push_back(runtime->GetCompilerExecutable());
argv.push_back("--runtime-arg");
argv.push_back("-classpath");
argv.push_back("--runtime-arg");
argv.push_back(runtime->GetClassPathString());
+ if (debuggable) {
+ argv.push_back("--debuggable");
+ }
runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
if (!runtime->IsVerificationEnabled()) {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 865fcb0..d8e3797 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -67,10 +67,23 @@
<< "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
<< "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
- ASSERT_TRUE(OS::FileExists(GetMultiDexSrc1().c_str()))
- << "Expected multidex file to be at: " << GetMultiDexSrc1();
ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
<< "Expected dex file to be at: " << GetDexSrc2();
+
+ // GetMultiDexSrc2 should have the same primary dex checksum as
+ // GetMultiDexSrc1, but a different secondary dex checksum.
+ std::vector<std::unique_ptr<const DexFile>> multi1;
+ ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
+ GetMultiDexSrc1().c_str(), &error_msg, &multi1)) << error_msg;
+ ASSERT_GT(multi1.size(), 1u);
+
+ std::vector<std::unique_ptr<const DexFile>> multi2;
+ ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
+ GetMultiDexSrc2().c_str(), &error_msg, &multi2)) << error_msg;
+ ASSERT_GT(multi2.size(), 1u);
+
+ ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
+ ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
}
virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
@@ -149,6 +162,12 @@
return GetTestDexFileName("MultiDex");
}
+ // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
+ // with the contents of the secondary dex file changed.
+ std::string GetMultiDexSrc2() {
+ return GetTestDexFileName("MultiDexModifiedSecondary");
+ }
+
std::string GetDexSrc2() {
return GetTestDexFileName("Nested");
}
@@ -344,6 +363,23 @@
EXPECT_EQ(2u, dex_files.size());
}
+// Case: We have a MultiDEX file where the secondary dex file is out of date.
+// Expect: The status is kDex2OatNeeded.
+TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/MultiDexSecondaryOutOfDate.jar";
+
+ // Compile code for GetMultiDexSrc1.
+ Copy(GetMultiDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str());
+
+ // Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum
+ // is out of date.
+ Copy(GetMultiDexSrc2(), dex_location);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+}
+
// Case: We have a MultiDEX file and up-to-date OAT file for it with relative
// encoded dex locations.
// Expect: The oat file status is kNoDexOptNeeded.
@@ -1001,9 +1037,6 @@
// TODO: More Tests:
// * Test class linker falls back to unquickened dex for DexNoOat
// * Test class linker falls back to unquickened dex for MultiDexNoOat
-// * Test multidex files:
-// - Multidex with only classes2.dex out of date should have status
-// kOutOfDate
// * Test using secondary isa
// * Test with profiling info?
// * Test for status of oat while oat is being generated (how?)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2633898..2618661 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1678,10 +1678,6 @@
std::string feature_string("--instruction-set-features=");
feature_string += features->GetFeatureString();
argv->push_back(feature_string);
-
- if (Dbg::IsJdwpConfigured()) {
- argv->push_back("--debuggable");
- }
}
void Runtime::UpdateProfilerState(int state) {
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 8b504c1..922334e 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -62,7 +62,7 @@
RUNTIME_OPTIONS_KEY (Unit, DumpJITInfoOnShutdown)
RUNTIME_OPTIONS_KEY (Unit, IgnoreMaxFootprint)
RUNTIME_OPTIONS_KEY (Unit, LowMemoryMode)
-RUNTIME_OPTIONS_KEY (bool, UseTLAB, kUseTlab)
+RUNTIME_OPTIONS_KEY (bool, UseTLAB, (kUseTlab || kUseReadBarrier))
RUNTIME_OPTIONS_KEY (bool, EnableHSpaceCompactForOOM, true)
RUNTIME_OPTIONS_KEY (bool, UseJIT, false)
RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold, jit::Jit::kDefaultCompileThreshold)
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 800acaa..6795516 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -99,15 +99,45 @@
cur_quick_frame_pc_(0),
num_frames_(num_frames),
cur_depth_(0),
+ current_inlining_depth_(0),
context_(context) {
DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
}
+InlineInfo StackVisitor::GetCurrentInlineInfo() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::ArtMethod* outer_method = GetCurrentQuickFrame()->AsMirrorPtr();
+ uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+ CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ return code_info.GetInlineInfoOf(stack_map);
+}
+
+mirror::ArtMethod* StackVisitor::GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (cur_shadow_frame_ != nullptr) {
+ return cur_shadow_frame_->GetMethod();
+ } else if (cur_quick_frame_ != nullptr) {
+ if (IsInInlinedFrame()) {
+ size_t depth_in_stack_map = current_inlining_depth_ - 1;
+ return GetCurrentQuickFrame()->AsMirrorPtr()->GetDexCacheResolvedMethod(
+ GetCurrentInlineInfo().GetMethodIndexAtDepth(depth_in_stack_map));
+ } else {
+ return cur_quick_frame_->AsMirrorPtr();
+ }
+ } else {
+ return nullptr;
+ }
+}
+
uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const {
if (cur_shadow_frame_ != nullptr) {
return cur_shadow_frame_->GetDexPC();
} else if (cur_quick_frame_ != nullptr) {
- return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+ if (IsInInlinedFrame()) {
+ size_t depth_in_stack_map = current_inlining_depth_ - 1;
+ return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map);
+ } else {
+ return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+ }
} else {
return 0;
}
@@ -225,18 +255,27 @@
bool StackVisitor::GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t* val) const {
- const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
- DCHECK(code_pointer != nullptr);
- uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
- CodeInfo code_info = m->GetOptimizedCodeInfo();
- StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ DCHECK_EQ(m, GetMethod());
const DexFile::CodeItem* code_item = m->GetCodeItem();
DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile
// its instructions?
- DCHECK_LT(vreg, code_item->registers_size_);
uint16_t number_of_dex_registers = code_item->registers_size_;
- DexRegisterMap dex_register_map =
- code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+ DCHECK_LT(vreg, code_item->registers_size_);
+
+ mirror::ArtMethod* outer_method = GetCurrentQuickFrame()->AsMirrorPtr();
+ const void* code_pointer = outer_method->GetQuickOatCodePointer(sizeof(void*));
+ DCHECK(code_pointer != nullptr);
+ CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+
+ uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ size_t depth_in_stack_map = current_inlining_depth_ - 1;
+
+ DexRegisterMap dex_register_map = IsInInlinedFrame()
+ ? code_info.GetDexRegisterMapAtDepth(
+ depth_in_stack_map, code_info.GetInlineInfoOf(stack_map), number_of_dex_registers)
+ : code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+
DexRegisterLocation::Kind location_kind =
dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info);
switch (location_kind) {
@@ -704,6 +743,26 @@
mirror::ArtMethod* method = cur_quick_frame_->AsMirrorPtr();
while (method != nullptr) {
SanityCheckFrame();
+
+ if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
+ && method->IsOptimized(sizeof(void*))) {
+ CodeInfo code_info = method->GetOptimizedCodeInfo();
+ uint32_t native_pc_offset = method->NativeQuickPcOffset(cur_quick_frame_pc_);
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+ if (stack_map.HasInlineInfo(code_info)) {
+ InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
+ DCHECK_EQ(current_inlining_depth_, 0u);
+ for (current_inlining_depth_ = inline_info.GetDepth();
+ current_inlining_depth_ != 0;
+ --current_inlining_depth_) {
+ bool should_continue = VisitFrame();
+ if (UNLIKELY(!should_continue)) {
+ return;
+ }
+ }
+ }
+ }
+
bool should_continue = VisitFrame();
if (UNLIKELY(!should_continue)) {
return;
diff --git a/runtime/stack.h b/runtime/stack.h
index bf61016..5b43848 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -36,9 +36,10 @@
} // namespace mirror
class Context;
-class ShadowFrame;
class HandleScope;
+class InlineInfo;
class ScopedObjectAccess;
+class ShadowFrame;
class StackVisitor;
class Thread;
@@ -430,15 +431,7 @@
void WalkStack(bool include_transitions = false)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- if (cur_shadow_frame_ != nullptr) {
- return cur_shadow_frame_->GetMethod();
- } else if (cur_quick_frame_ != nullptr) {
- return cur_quick_frame_->AsMirrorPtr();
- } else {
- return nullptr;
- }
- }
+ mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsShadowFrame() const {
return cur_shadow_frame_ != nullptr;
@@ -611,7 +604,7 @@
}
bool IsInInlinedFrame() const {
- return false;
+ return current_inlining_depth_ != 0;
}
uintptr_t GetCurrentQuickFramePc() const {
@@ -703,6 +696,8 @@
void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ InlineInfo GetCurrentInlineInfo() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
Thread* const thread_;
const StackWalkKind walk_kind_;
ShadowFrame* cur_shadow_frame_;
@@ -712,6 +707,9 @@
size_t num_frames_;
// Depth of the frame we're currently at.
size_t cur_depth_;
+ // Current inlining depth of the method we are currently at.
+ // 0 if there is no inlined frame.
+ size_t current_inlining_depth_;
protected:
Context* const context_;
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 11e7e44..6a0c07d 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -257,21 +257,48 @@
DumpStackMapHeader(os, i);
if (stack_map.HasDexRegisterMap(*this)) {
DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
- // TODO: Display the bit mask of live Dex registers.
- for (size_t j = 0; j < number_of_dex_registers; ++j) {
- if (dex_register_map.IsDexRegisterLive(j)) {
- size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex(
- j, number_of_dex_registers, number_of_location_catalog_entries);
- DexRegisterLocation location =
- dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this);
- DumpRegisterMapping(
- os, j, location, "v",
- "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
- }
- }
+ dex_register_map.Dump(os, *this, number_of_dex_registers);
}
}
- // TODO: Dump the stack map's inline information.
+ // TODO: Dump the stack map's inline information? We need to know more from the caller:
+ // we need to know the number of dex registers for each inlined method.
+}
+
+void DexRegisterMap::Dump(std::ostream& os,
+ const CodeInfo& code_info,
+ uint16_t number_of_dex_registers) const {
+ size_t number_of_location_catalog_entries =
+ code_info.GetNumberOfDexRegisterLocationCatalogEntries();
+ // TODO: Display the bit mask of live Dex registers.
+ for (size_t j = 0; j < number_of_dex_registers; ++j) {
+ if (IsDexRegisterLive(j)) {
+ size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
+ j, number_of_dex_registers, number_of_location_catalog_entries);
+ DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, code_info);
+ DumpRegisterMapping(
+ os, j, location, "v",
+ "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
+ }
+ }
+}
+
+void InlineInfo::Dump(std::ostream& os,
+ const CodeInfo& code_info,
+ uint16_t number_of_dex_registers[]) const {
+ os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
+
+ for (size_t i = 0; i < GetDepth(); ++i) {
+ os << " At depth " << i
+ << std::hex
+ << " (dex_pc=0x" << GetDexPcAtDepth(i)
+ << ", method_index=0x" << GetMethodIndexAtDepth(i)
+ << ")\n";
+ if (HasDexRegisterMapAtDepth(i)) {
+ DexRegisterMap dex_register_map =
+ code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]);
+ dex_register_map.Dump(os, code_info, number_of_dex_registers[i]);
+ }
+ }
}
} // namespace art
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index f68cafe..16ae772 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -39,47 +39,6 @@
* their own fields.
*/
-/**
- * Inline information for a specific PC. The information is of the form:
- * [inlining_depth, [method_dex reference]+]
- */
-class InlineInfo {
- public:
- explicit InlineInfo(MemoryRegion region) : region_(region) {}
-
- uint8_t GetDepth() const {
- return region_.LoadUnaligned<uint8_t>(kDepthOffset);
- }
-
- void SetDepth(uint8_t depth) {
- region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
- }
-
- uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
- return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
- }
-
- void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
- region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
- }
-
- static size_t SingleEntrySize() {
- return sizeof(uint32_t);
- }
-
- private:
- // TODO: Instead of plain types such as "uint8_t", introduce
- // typedefs (and document the memory layout of InlineInfo).
- static constexpr int kDepthOffset = 0;
- static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
-
- MemoryRegion region_;
-
- friend class CodeInfo;
- friend class StackMap;
- friend class StackMapStream;
-};
-
// Dex register location container used by DexRegisterMap and StackMapStream.
class DexRegisterLocation {
public:
@@ -506,7 +465,8 @@
const CodeInfo& code_info) const {
DexRegisterLocation location =
GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info);
- DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
+ DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
+ << DexRegisterLocation::PrettyDescriptor(location.GetKind());
return location.GetValue();
}
@@ -641,6 +601,8 @@
return region_.size();
}
+ void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
+
private:
// Return the index in the Dex register map corresponding to the Dex
// register number `dex_register_number`.
@@ -675,9 +637,6 @@
* The information is of the form:
* [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
* stack_mask].
- *
- * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
- * stack size of a method.
*/
class StackMap {
public:
@@ -759,6 +718,72 @@
friend class StackMapStream;
};
+/**
+ * Inline information for a specific PC. The information is of the form:
+ * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
+ */
+class InlineInfo {
+ public:
+ explicit InlineInfo(MemoryRegion region) : region_(region) {}
+
+ uint8_t GetDepth() const {
+ return region_.LoadUnaligned<uint8_t>(kDepthOffset);
+ }
+
+ void SetDepth(uint8_t depth) {
+ region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
+ }
+
+ uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
+ return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
+ }
+
+ void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
+ region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
+ }
+
+ uint32_t GetDexPcAtDepth(uint8_t depth) const {
+ return region_.LoadUnaligned<uint32_t>(
+ kFixedSize + depth * SingleEntrySize() + sizeof(uint32_t));
+ }
+
+ void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
+ region_.StoreUnaligned<uint32_t>(
+ kFixedSize + depth * SingleEntrySize() + sizeof(uint32_t), dex_pc);
+ }
+
+ uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
+ return region_.LoadUnaligned<uint32_t>(
+ kFixedSize + depth * SingleEntrySize() + sizeof(uint32_t) + sizeof(uint32_t));
+ }
+
+ void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
+ region_.StoreUnaligned<uint32_t>(
+ kFixedSize + depth * SingleEntrySize() + sizeof(uint32_t) + sizeof(uint32_t), offset);
+ }
+
+ bool HasDexRegisterMapAtDepth(uint8_t depth) const {
+ return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
+ }
+
+ static size_t SingleEntrySize() {
+ return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t);
+ }
+
+ void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
+
+ private:
+ // TODO: Instead of plain types such as "uint8_t", introduce
+ // typedefs (and document the memory layout of InlineInfo).
+ static constexpr int kDepthOffset = 0;
+ static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
+
+ MemoryRegion region_;
+
+ friend class CodeInfo;
+ friend class StackMap;
+ friend class StackMapStream;
+};
/**
* Wrapper around all compiler information collected for a method.
@@ -960,6 +985,17 @@
return DexRegisterMap(region_.Subregion(offset, size));
}
+ // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
+ DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
+ InlineInfo inline_info,
+ uint32_t number_of_dex_registers) const {
+ DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
+ uint32_t offset =
+ GetDexRegisterMapsOffset() + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
+ size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
+ return DexRegisterMap(region_.Subregion(offset, size));
+ }
+
InlineInfo GetInlineInfoOf(StackMap stack_map) const {
DCHECK(stack_map.HasInlineInfo(*this));
uint32_t offset = stack_map.GetInlineDescriptorOffset(*this) + GetDexRegisterMapsOffset();
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 475fe8b..1b1bc54 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -286,6 +286,13 @@
}
}
+static bool IsLargeMethod(const DexFile::CodeItem* const code_item) {
+ uint16_t registers_size = code_item->registers_size_;
+ uint32_t insns_size = code_item->insns_size_in_code_units_;
+
+ return registers_size * insns_size > 4*1024*1024;
+}
+
MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t method_idx,
const DexFile* dex_file,
Handle<mirror::DexCache> dex_cache,
@@ -329,7 +336,8 @@
uint64_t duration_ns = NanoTime() - start_ns;
if (duration_ns > MsToNs(100)) {
LOG(WARNING) << "Verification of " << PrettyMethod(method_idx, *dex_file)
- << " took " << PrettyDuration(duration_ns);
+ << " took " << PrettyDuration(duration_ns)
+ << (IsLargeMethod(code_item) ? " (large method)" : "");
}
}
return result;
@@ -1211,10 +1219,6 @@
uint16_t registers_size = code_item_->registers_size_;
uint32_t insns_size = code_item_->insns_size_in_code_units_;
- if (registers_size * insns_size > 4*1024*1024) {
- LOG(WARNING) << "warning: method is huge (regs=" << registers_size
- << " insns_size=" << insns_size << ")";
- }
/* Create and initialize table holding register status */
reg_table_.Init(kTrackCompilerInterestPoints,
insn_flags_.get(),
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
index 1c3855f..8894d4e 100644
--- a/test/441-checker-inliner/src/Main.java
+++ b/test/441-checker-inliner/src/Main.java
@@ -19,7 +19,7 @@
// CHECK-START: void Main.InlineVoid() inliner (before)
// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
// CHECK-DAG: InvokeStaticOrDirect
- // CHECK-DAG: InvokeStaticOrDirect [ <<Const42>> ]
+ // CHECK-DAG: InvokeStaticOrDirect [<<Const42>>]
// CHECK-START: void Main.InlineVoid() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
@@ -31,12 +31,12 @@
// CHECK-START: int Main.InlineParameter(int) inliner (before)
// CHECK-DAG: <<Param:i\d+>> ParameterValue
- // CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [ <<Param>> ]
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Param>>]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: int Main.InlineParameter(int) inliner (after)
// CHECK-DAG: <<Param:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Param>> ]
+ // CHECK-DAG: Return [<<Param>>]
public static int InlineParameter(int a) {
return returnParameter(a);
@@ -44,12 +44,12 @@
// CHECK-START: long Main.InlineWideParameter(long) inliner (before)
// CHECK-DAG: <<Param:j\d+>> ParameterValue
- // CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [ <<Param>> ]
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<Param>>]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: long Main.InlineWideParameter(long) inliner (after)
// CHECK-DAG: <<Param:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Param>> ]
+ // CHECK-DAG: Return [<<Param>>]
public static long InlineWideParameter(long a) {
return returnWideParameter(a);
@@ -57,12 +57,12 @@
// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
// CHECK-DAG: <<Param:l\d+>> ParameterValue
- // CHECK-DAG: <<Result:l\d+>> InvokeStaticOrDirect [ <<Param>> ]
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: <<Result:l\d+>> InvokeStaticOrDirect [<<Param>>]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
// CHECK-DAG: <<Param:l\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Param>> ]
+ // CHECK-DAG: Return [<<Param>>]
public static Object InlineReferenceParameter(Object o) {
return returnReferenceParameter(o);
@@ -70,11 +70,11 @@
// CHECK-START: int Main.InlineInt() inliner (before)
// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: int Main.InlineInt() inliner (after)
// CHECK-DAG: <<Const4:i\d+>> IntConstant 4
- // CHECK-DAG: Return [ <<Const4>> ]
+ // CHECK-DAG: Return [<<Const4>>]
public static int InlineInt() {
return returnInt();
@@ -82,11 +82,11 @@
// CHECK-START: long Main.InlineWide() inliner (before)
// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: long Main.InlineWide() inliner (after)
// CHECK-DAG: <<Const8:j\d+>> LongConstant 8
- // CHECK-DAG: Return [ <<Const8>> ]
+ // CHECK-DAG: Return [<<Const8>>]
public static long InlineWide() {
return returnWide();
@@ -96,13 +96,13 @@
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Result>> ]
+ // CHECK-DAG: Return [<<Result>>]
// CHECK-START: int Main.InlineAdd() inliner (after)
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Const3>> <<Const5>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Const3>>,<<Const5>>]
+ // CHECK-DAG: Return [<<Add>>]
public static int InlineAdd() {
return returnAdd(3, 5);
@@ -110,14 +110,14 @@
// CHECK-START: int Main.InlineFieldAccess() inliner (before)
// CHECK-DAG: <<After:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<After>> ]
+ // CHECK-DAG: Return [<<After>>]
// CHECK-START: int Main.InlineFieldAccess() inliner (after)
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
// CHECK-DAG: <<Before:i\d+>> StaticFieldGet
- // CHECK-DAG: <<After:i\d+>> Add [ <<Before>> <<Const1>> ]
- // CHECK-DAG: StaticFieldSet [ {{l\d+}} <<After>> ]
- // CHECK-DAG: Return [ <<After>> ]
+ // CHECK-DAG: <<After:i\d+>> Add [<<Before>>,<<Const1>>]
+ // CHECK-DAG: StaticFieldSet [{{l\d+}},<<After>>]
+ // CHECK-DAG: Return [<<After>>]
// CHECK-START: int Main.InlineFieldAccess() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
@@ -130,19 +130,19 @@
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- // CHECK-DAG: <<Add:i\d+>> InvokeStaticOrDirect [ <<Const1>> <<Const3>> ]
- // CHECK-DAG: <<Sub:i\d+>> InvokeStaticOrDirect [ <<Const5>> <<Const3>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Add>> <<Sub>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Add:i\d+>> InvokeStaticOrDirect [<<Const1>>,<<Const3>>]
+ // CHECK-DAG: <<Sub:i\d+>> InvokeStaticOrDirect [<<Const5>>,<<Const3>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Const1>> <<Const3>> ]
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Const5>> <<Const3>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Add>> <<Sub>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Const1>>,<<Const3>>]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Const5>>,<<Const3>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ // CHECK-DAG: Return [<<Phi>>]
public static int InlineWithControlFlow(boolean cond) {
int x, const1, const3, const5;
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 9a2e4fc..c258db9 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -53,12 +53,12 @@
// CHECK-START: int Main.IntNegation() constant_folding (before)
// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Const42>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Const42>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.IntNegation() constant_folding (after)
// CHECK-DAG: <<ConstN42:i\d+>> IntConstant -42
- // CHECK-DAG: Return [ <<ConstN42>> ]
+ // CHECK-DAG: Return [<<ConstN42>>]
public static int IntNegation() {
int x, y;
@@ -75,12 +75,12 @@
// CHECK-START: int Main.IntAddition1() constant_folding (before)
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Const1>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Const1>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.IntAddition1() constant_folding (after)
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
- // CHECK-DAG: Return [ <<Const3>> ]
+ // CHECK-DAG: Return [<<Const3>>]
public static int IntAddition1() {
int a, b, c;
@@ -100,14 +100,14 @@
// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
// CHECK-DAG: <<Const6:i\d+>> IntConstant 6
- // CHECK-DAG: <<Add1:i\d+>> Add [ <<Const1>> <<Const2>> ]
- // CHECK-DAG: <<Add2:i\d+>> Add [ <<Const5>> <<Const6>> ]
- // CHECK-DAG: <<Add3:i\d+>> Add [ <<Add1>> <<Add2>> ]
- // CHECK-DAG: Return [ <<Add3>> ]
+ // CHECK-DAG: <<Add1:i\d+>> Add [<<Const1>>,<<Const2>>]
+ // CHECK-DAG: <<Add2:i\d+>> Add [<<Const5>>,<<Const6>>]
+ // CHECK-DAG: <<Add3:i\d+>> Add [<<Add1>>,<<Add2>>]
+ // CHECK-DAG: Return [<<Add3>>]
// CHECK-START: int Main.IntAddition2() constant_folding (after)
// CHECK-DAG: <<Const14:i\d+>> IntConstant 14
- // CHECK-DAG: Return [ <<Const14>> ]
+ // CHECK-DAG: Return [<<Const14>>]
public static int IntAddition2() {
int a, b, c;
@@ -129,12 +129,12 @@
// CHECK-START: int Main.IntSubtraction() constant_folding (before)
// CHECK-DAG: <<Const6:i\d+>> IntConstant 6
// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Const6>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Const6>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.IntSubtraction() constant_folding (after)
// CHECK-DAG: <<Const4:i\d+>> IntConstant 4
- // CHECK-DAG: Return [ <<Const4>> ]
+ // CHECK-DAG: Return [<<Const4>>]
public static int IntSubtraction() {
int a, b, c;
@@ -152,12 +152,12 @@
// CHECK-START: long Main.LongAddition() constant_folding (before)
// CHECK-DAG: <<Const1:j\d+>> LongConstant 1
// CHECK-DAG: <<Const2:j\d+>> LongConstant 2
- // CHECK-DAG: <<Add:j\d+>> Add [ <<Const1>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:j\d+>> Add [<<Const1>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: long Main.LongAddition() constant_folding (after)
// CHECK-DAG: <<Const3:j\d+>> LongConstant 3
- // CHECK-DAG: Return [ <<Const3>> ]
+ // CHECK-DAG: Return [<<Const3>>]
public static long LongAddition() {
long a, b, c;
@@ -175,12 +175,12 @@
// CHECK-START: long Main.LongSubtraction() constant_folding (before)
// CHECK-DAG: <<Const6:j\d+>> LongConstant 6
// CHECK-DAG: <<Const2:j\d+>> LongConstant 2
- // CHECK-DAG: <<Sub:j\d+>> Sub [ <<Const6>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:j\d+>> Sub [<<Const6>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: long Main.LongSubtraction() constant_folding (after)
// CHECK-DAG: <<Const4:j\d+>> LongConstant 4
- // CHECK-DAG: Return [ <<Const4>> ]
+ // CHECK-DAG: Return [<<Const4>>]
public static long LongSubtraction() {
long a, b, c;
@@ -197,12 +197,12 @@
// CHECK-START: int Main.StaticCondition() constant_folding (before)
// CHECK-DAG: <<Const7:i\d+>> IntConstant 7
// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
- // CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [ <<Const7>> <<Const2>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<Const7>>,<<Const2>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.StaticCondition() constant_folding (after)
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: If [ <<Const1>> ]
+ // CHECK-DAG: If [<<Const1>>]
public static int StaticCondition() {
int a, b, c;
@@ -227,16 +227,16 @@
// CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (before)
// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Const5>> <<Const2>> ]
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Const5>> <<Const2>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Add>> <<Sub>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Const5>>,<<Const2>>]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Const5>>,<<Const2>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (after)
// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
// CHECK-DAG: <<Const7:i\d+>> IntConstant 7
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const7>> <<Const3>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const7>>,<<Const3>>]
+ // CHECK-DAG: Return [<<Phi>>]
public static int JumpsAndConditionals(boolean cond) {
int a, b, c;
@@ -256,14 +256,14 @@
// CHECK-START: int Main.And0(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<And:i\d+>> And [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<And>> ]
+ // CHECK-DAG: <<And:i\d+>> And [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<And>>]
// CHECK-START: int Main.And0(int) constant_folding (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: And
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int And0(int arg) {
return arg & 0;
@@ -272,14 +272,14 @@
// CHECK-START: long Main.Mul0(long) constant_folding (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<Mul:j\d+>> Mul [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:j\d+>> Mul [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: long Main.Mul0(long) constant_folding (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
// CHECK-NOT: Mul
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long Mul0(long arg) {
return arg * 0;
@@ -288,13 +288,13 @@
// CHECK-START: int Main.OrAllOnes(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Arg>> <<ConstF>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Arg>>,<<ConstF>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.OrAllOnes(int) constant_folding (after)
// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1
// CHECK-NOT: Or
- // CHECK-DAG: Return [ <<ConstF>> ]
+ // CHECK-DAG: Return [<<ConstF>>]
public static int OrAllOnes(int arg) {
return arg | -1;
@@ -303,14 +303,14 @@
// CHECK-START: long Main.Rem0(long) constant_folding (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<DivZeroCheck:j\d+>> DivZeroCheck [ <<Arg>> ]
- // CHECK-DAG: <<Rem:j\d+>> Rem [ <<Const0>> <<DivZeroCheck>> ]
- // CHECK-DAG: Return [ <<Rem>> ]
+ // CHECK-DAG: <<DivZeroCheck:j\d+>> DivZeroCheck [<<Arg>>]
+ // CHECK-DAG: <<Rem:j\d+>> Rem [<<Const0>>,<<DivZeroCheck>>]
+ // CHECK-DAG: Return [<<Rem>>]
// CHECK-START: long Main.Rem0(long) constant_folding (after)
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
// CHECK-NOT: Rem
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long Rem0(long arg) {
return 0 % arg;
@@ -319,13 +319,13 @@
// CHECK-START: int Main.Rem1(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Rem:i\d+>> Rem [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: Return [ <<Rem>> ]
+ // CHECK-DAG: <<Rem:i\d+>> Rem [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: Return [<<Rem>>]
// CHECK-START: int Main.Rem1(int) constant_folding (after)
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: Rem
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int Rem1(int arg) {
return arg % 1;
@@ -334,14 +334,14 @@
// CHECK-START: long Main.RemN1(long) constant_folding (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<ConstN1:j\d+>> LongConstant -1
- // CHECK-DAG: <<DivZeroCheck:j\d+>> DivZeroCheck [ <<Arg>> ]
- // CHECK-DAG: <<Rem:j\d+>> Rem [ <<Arg>> <<DivZeroCheck>> ]
- // CHECK-DAG: Return [ <<Rem>> ]
+ // CHECK-DAG: <<DivZeroCheck:j\d+>> DivZeroCheck [<<ConstN1>>]
+ // CHECK-DAG: <<Rem:j\d+>> Rem [<<Arg>>,<<DivZeroCheck>>]
+ // CHECK-DAG: Return [<<Rem>>]
// CHECK-START: long Main.RemN1(long) constant_folding (after)
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
// CHECK-NOT: Rem
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long RemN1(long arg) {
return arg % -1;
@@ -350,14 +350,14 @@
// CHECK-START: int Main.Shl0(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Shl:i\d+>> Shl [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Shl>> ]
+ // CHECK-DAG: <<Shl:i\d+>> Shl [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Shl>>]
// CHECK-START: int Main.Shl0(int) constant_folding (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: Shl
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int Shl0(int arg) {
return 0 << arg;
@@ -366,14 +366,14 @@
// CHECK-START: long Main.Shr0(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<Shr:j\d+>> Shr [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Shr>> ]
+ // CHECK-DAG: <<Shr:j\d+>> Shr [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Shr>>]
// CHECK-START: long Main.Shr0(int) constant_folding (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
// CHECK-NOT: Shr
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long Shr0(int arg) {
return (long)0 >> arg;
@@ -381,14 +381,14 @@
// CHECK-START: long Main.SubSameLong(long) constant_folding (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: <<Sub:j\d+>> Sub [ <<Arg>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:j\d+>> Sub [<<Arg>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: long Main.SubSameLong(long) constant_folding (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
// CHECK-NOT: Sub
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long SubSameLong(long arg) {
return arg - arg;
@@ -397,14 +397,14 @@
// CHECK-START: int Main.UShr0(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<UShr:i\d+>> UShr [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: Return [ <<UShr>> ]
+ // CHECK-DAG: <<UShr:i\d+>> UShr [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: Return [<<UShr>>]
// CHECK-START: int Main.UShr0(int) constant_folding (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: UShr
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int UShr0(int arg) {
return 0 >>> arg;
@@ -412,14 +412,14 @@
// CHECK-START: int Main.XorSameInt(int) constant_folding (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Xor:i\d+>> Xor [ <<Arg>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Xor>> ]
+ // CHECK-DAG: <<Xor:i\d+>> Xor [<<Arg>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Xor>>]
// CHECK-START: int Main.XorSameInt(int) constant_folding (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: Xor
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int XorSameInt(int arg) {
return arg ^ arg;
@@ -430,16 +430,16 @@
// CHECK-DAG: <<ConstNan:f\d+>> FloatConstant nan
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: IntConstant 1
- // CHECK-DAG: <<Cmp:i\d+>> Compare [ <<Arg>> <<ConstNan>> ]
- // CHECK-DAG: <<Le:z\d+>> LessThanOrEqual [ <<Cmp>> <<Const0>> ]
- // CHECK-DAG: If [ <<Le>> ]
+ // CHECK-DAG: <<Cmp:i\d+>> Compare [<<Arg>>,<<ConstNan>>]
+ // CHECK-DAG: <<Le:z\d+>> LessThanOrEqual [<<Cmp>>,<<Const0>>]
+ // CHECK-DAG: If [<<Le>>]
// CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
// CHECK-DAG: ParameterValue
// CHECK-DAG: FloatConstant nan
// CHECK-DAG: IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: If [ <<Const1>> ]
+ // CHECK-DAG: If [<<Const1>>]
// CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
// CHECK-NOT: Compare
@@ -454,16 +454,16 @@
// CHECK-DAG: <<ConstNan:d\d+>> DoubleConstant nan
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: IntConstant 1
- // CHECK-DAG: <<Cmp:i\d+>> Compare [ <<Arg>> <<ConstNan>> ]
- // CHECK-DAG: <<Ge:z\d+>> GreaterThanOrEqual [ <<Cmp>> <<Const0>> ]
- // CHECK-DAG: If [ <<Ge>> ]
+ // CHECK-DAG: <<Cmp:i\d+>> Compare [<<Arg>>,<<ConstNan>>]
+ // CHECK-DAG: <<Ge:z\d+>> GreaterThanOrEqual [<<Cmp>>,<<Const0>>]
+ // CHECK-DAG: If [<<Ge>>]
// CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
// CHECK-DAG: ParameterValue
// CHECK-DAG: DoubleConstant nan
// CHECK-DAG: IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: If [ <<Const1>> ]
+ // CHECK-DAG: If [<<Const1>>]
// CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
// CHECK-NOT: Compare
@@ -475,12 +475,12 @@
// CHECK-START: int Main.ReturnInt33() constant_folding (before)
// CHECK-DAG: <<Const33:j\d+>> LongConstant 33
- // CHECK-DAG: <<Convert:i\d+>> TypeConversion <<Const33>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:i\d+>> TypeConversion [<<Const33>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: int Main.ReturnInt33() constant_folding (after)
// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
- // CHECK-DAG: Return [ <<Const33>> ]
+ // CHECK-DAG: Return [<<Const33>>]
public static int ReturnInt33() {
long imm = 33L;
@@ -489,12 +489,12 @@
// CHECK-START: int Main.ReturnIntMax() constant_folding (before)
// CHECK-DAG: <<ConstMax:f\d+>> FloatConstant 1e+34
- // CHECK-DAG: <<Convert:i\d+>> TypeConversion <<ConstMax>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:i\d+>> TypeConversion [<<ConstMax>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: int Main.ReturnIntMax() constant_folding (after)
// CHECK-DAG: <<ConstMax:i\d+>> IntConstant 2147483647
- // CHECK-DAG: Return [ <<ConstMax>> ]
+ // CHECK-DAG: Return [<<ConstMax>>]
public static int ReturnIntMax() {
float imm = 1.0e34f;
@@ -503,12 +503,12 @@
// CHECK-START: int Main.ReturnInt0() constant_folding (before)
// CHECK-DAG: <<ConstNaN:d\d+>> DoubleConstant nan
- // CHECK-DAG: <<Convert:i\d+>> TypeConversion <<ConstNaN>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:i\d+>> TypeConversion [<<ConstNaN>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: int Main.ReturnInt0() constant_folding (after)
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static int ReturnInt0() {
double imm = Double.NaN;
@@ -517,12 +517,12 @@
// CHECK-START: long Main.ReturnLong33() constant_folding (before)
// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
- // CHECK-DAG: <<Convert:j\d+>> TypeConversion <<Const33>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:j\d+>> TypeConversion [<<Const33>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: long Main.ReturnLong33() constant_folding (after)
// CHECK-DAG: <<Const33:j\d+>> LongConstant 33
- // CHECK-DAG: Return [ <<Const33>> ]
+ // CHECK-DAG: Return [<<Const33>>]
public static long ReturnLong33() {
int imm = 33;
@@ -531,12 +531,12 @@
// CHECK-START: long Main.ReturnLong34() constant_folding (before)
// CHECK-DAG: <<Const34:f\d+>> FloatConstant 34
- // CHECK-DAG: <<Convert:j\d+>> TypeConversion <<Const34>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:j\d+>> TypeConversion [<<Const34>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: long Main.ReturnLong34() constant_folding (after)
// CHECK-DAG: <<Const34:j\d+>> LongConstant 34
- // CHECK-DAG: Return [ <<Const34>> ]
+ // CHECK-DAG: Return [<<Const34>>]
public static long ReturnLong34() {
float imm = 34.0f;
@@ -545,12 +545,12 @@
// CHECK-START: long Main.ReturnLong0() constant_folding (before)
// CHECK-DAG: <<ConstNaN:d\d+>> DoubleConstant nan
- // CHECK-DAG: <<Convert:j\d+>> TypeConversion <<ConstNaN>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:j\d+>> TypeConversion [<<ConstNaN>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: long Main.ReturnLong0() constant_folding (after)
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: Return [ <<Const0>> ]
+ // CHECK-DAG: Return [<<Const0>>]
public static long ReturnLong0() {
double imm = -Double.NaN;
@@ -559,12 +559,12 @@
// CHECK-START: float Main.ReturnFloat33() constant_folding (before)
// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
- // CHECK-DAG: <<Convert:f\d+>> TypeConversion <<Const33>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:f\d+>> TypeConversion [<<Const33>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: float Main.ReturnFloat33() constant_folding (after)
// CHECK-DAG: <<Const33:f\d+>> FloatConstant 33
- // CHECK-DAG: Return [ <<Const33>> ]
+ // CHECK-DAG: Return [<<Const33>>]
public static float ReturnFloat33() {
int imm = 33;
@@ -573,12 +573,12 @@
// CHECK-START: float Main.ReturnFloat34() constant_folding (before)
// CHECK-DAG: <<Const34:j\d+>> LongConstant 34
- // CHECK-DAG: <<Convert:f\d+>> TypeConversion <<Const34>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:f\d+>> TypeConversion [<<Const34>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: float Main.ReturnFloat34() constant_folding (after)
// CHECK-DAG: <<Const34:f\d+>> FloatConstant 34
- // CHECK-DAG: Return [ <<Const34>> ]
+ // CHECK-DAG: Return [<<Const34>>]
public static float ReturnFloat34() {
long imm = 34L;
@@ -587,12 +587,12 @@
// CHECK-START: float Main.ReturnFloat99P25() constant_folding (before)
// CHECK-DAG: <<Const:d\d+>> DoubleConstant 99.25
- // CHECK-DAG: <<Convert:f\d+>> TypeConversion <<Const>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:f\d+>> TypeConversion [<<Const>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: float Main.ReturnFloat99P25() constant_folding (after)
// CHECK-DAG: <<Const:f\d+>> FloatConstant 99.25
- // CHECK-DAG: Return [ <<Const>> ]
+ // CHECK-DAG: Return [<<Const>>]
public static float ReturnFloat99P25() {
double imm = 99.25;
@@ -601,12 +601,12 @@
// CHECK-START: double Main.ReturnDouble33() constant_folding (before)
// CHECK-DAG: <<Const33:i\d+>> IntConstant 33
- // CHECK-DAG: <<Convert:d\d+>> TypeConversion <<Const33>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:d\d+>> TypeConversion [<<Const33>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: double Main.ReturnDouble33() constant_folding (after)
// CHECK-DAG: <<Const33:d\d+>> DoubleConstant 33
- // CHECK-DAG: Return [ <<Const33>> ]
+ // CHECK-DAG: Return [<<Const33>>]
public static double ReturnDouble33() {
int imm = 33;
@@ -615,12 +615,12 @@
// CHECK-START: double Main.ReturnDouble34() constant_folding (before)
// CHECK-DAG: <<Const34:j\d+>> LongConstant 34
- // CHECK-DAG: <<Convert:d\d+>> TypeConversion <<Const34>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:d\d+>> TypeConversion [<<Const34>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: double Main.ReturnDouble34() constant_folding (after)
// CHECK-DAG: <<Const34:d\d+>> DoubleConstant 34
- // CHECK-DAG: Return [ <<Const34>> ]
+ // CHECK-DAG: Return [<<Const34>>]
public static double ReturnDouble34() {
long imm = 34L;
@@ -629,12 +629,12 @@
// CHECK-START: double Main.ReturnDouble99P25() constant_folding (before)
// CHECK-DAG: <<Const:f\d+>> FloatConstant 99.25
- // CHECK-DAG: <<Convert:d\d+>> TypeConversion <<Const>>
- // CHECK-DAG: Return [ <<Convert>> ]
+ // CHECK-DAG: <<Convert:d\d+>> TypeConversion [<<Const>>]
+ // CHECK-DAG: Return [<<Convert>>]
// CHECK-START: double Main.ReturnDouble99P25() constant_folding (after)
// CHECK-DAG: <<Const:d\d+>> DoubleConstant 99.25
- // CHECK-DAG: Return [ <<Const>> ]
+ // CHECK-DAG: Return [<<Const>>]
public static double ReturnDouble99P25() {
float imm = 99.25f;
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index ce2ab9a..96918d3 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -89,7 +89,7 @@
// CHECK-START: int Main.arrayLength(int[]) licm (before)
// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}}
- // CHECK-DAG: ArrayLength [ <<NullCheck>> ] loop:{{B\d+}}
+ // CHECK-DAG: ArrayLength [<<NullCheck>>] loop:{{B\d+}}
// CHECK-START: int Main.arrayLength(int[]) licm (after)
// CHECK-NOT: NullCheck loop:{{B\d+}}
@@ -97,7 +97,7 @@
// CHECK-START: int Main.arrayLength(int[]) licm (after)
// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none
- // CHECK-DAG: ArrayLength [ <<NullCheck>> ] loop:none
+ // CHECK-DAG: ArrayLength [<<NullCheck>>] loop:none
public static int arrayLength(int[] array) {
int result = 0;
diff --git a/test/446-checker-inliner2/src/Main.java b/test/446-checker-inliner2/src/Main.java
index 5d4ddf8..9ed66d6 100644
--- a/test/446-checker-inliner2/src/Main.java
+++ b/test/446-checker-inliner2/src/Main.java
@@ -18,14 +18,14 @@
// CHECK-START: int Main.inlineInstanceCall(Main) inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
// CHECK-DAG: <<Field:i\d+>> InstanceFieldGet
- // CHECK-DAG: Return [ <<Field>> ]
+ // CHECK-DAG: Return [<<Field>>]
public static int inlineInstanceCall(Main m) {
return m.foo();
@@ -39,14 +39,14 @@
// CHECK-START: int Main.inlineNestedCall() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineNestedCall() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: int Main.inlineNestedCall() inliner (after)
// CHECK-DAG: <<Const38:i\d+>> IntConstant 38
- // CHECK-DAG: Return [ <<Const38>> ]
+ // CHECK-DAG: Return [<<Const38>>]
public static int inlineNestedCall() {
return nestedCall();
diff --git a/test/447-checker-inliner3/src/Main.java b/test/447-checker-inliner3/src/Main.java
index 34faafa..9d022b9 100644
--- a/test/447-checker-inliner3/src/Main.java
+++ b/test/447-checker-inliner3/src/Main.java
@@ -18,7 +18,7 @@
// CHECK-START: int Main.inlineIfThenElse() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineIfThenElse() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index ebad8e5..742210c 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -53,12 +53,12 @@
// CHECK-START: long Main.Add0(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<Add:j\d+>> Add [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:j\d+>> Add [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: long Main.Add0(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.Add0(long) instruction_simplifier (after)
// CHECK-NOT: Add
@@ -70,12 +70,12 @@
// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1
- // CHECK-DAG: <<And:i\d+>> And [ <<Arg>> <<ConstF>> ]
- // CHECK-DAG: Return [ <<And>> ]
+ // CHECK-DAG: <<And:i\d+>> And [<<Arg>>,<<ConstF>>]
+ // CHECK-DAG: Return [<<And>>]
// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
// CHECK-NOT: And
@@ -87,12 +87,12 @@
// CHECK-START: long Main.Div1(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const1:j\d+>> LongConstant 1
- // CHECK-DAG: <<Div:j\d+>> Div [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:j\d+>> Div [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: long Main.Div1(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.Div1(long) instruction_simplifier (after)
// CHECK-NOT: Div
@@ -104,13 +104,13 @@
// CHECK-START: int Main.DivN1(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstN1:i\d+>> IntConstant -1
- // CHECK-DAG: <<Div:i\d+>> Div [ <<Arg>> <<ConstN1>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:i\d+>> Div [<<Arg>>,<<ConstN1>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
// CHECK-NOT: Div
@@ -122,12 +122,12 @@
// CHECK-START: long Main.Mul1(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const1:j\d+>> LongConstant 1
- // CHECK-DAG: <<Mul:j\d+>> Mul [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:j\d+>> Mul [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
// CHECK-NOT: Mul
@@ -139,13 +139,13 @@
// CHECK-START: int Main.MulN1(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstN1:i\d+>> IntConstant -1
- // CHECK-DAG: <<Mul:i\d+>> Mul [ <<Arg>> <<ConstN1>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:i\d+>> Mul [<<Arg>>,<<ConstN1>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
// CHECK-NOT: Mul
@@ -157,14 +157,14 @@
// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const128:j\d+>> LongConstant 128
- // CHECK-DAG: <<Mul:j\d+>> Mul [ <<Arg>> <<Const128>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:j\d+>> Mul [<<Arg>>,<<Const128>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const7:i\d+>> IntConstant 7
- // CHECK-DAG: <<Shl:j\d+>> Shl [ <<Arg>> <<Const7>> ]
- // CHECK-DAG: Return [ <<Shl>> ]
+ // CHECK-DAG: <<Shl:j\d+>> Shl [<<Arg>>,<<Const7>>]
+ // CHECK-DAG: Return [<<Shl>>]
// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
// CHECK-NOT: Mul
@@ -176,12 +176,12 @@
// CHECK-START: int Main.Or0(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.Or0(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.Or0(int) instruction_simplifier (after)
// CHECK-NOT: Or
@@ -192,12 +192,12 @@
// CHECK-START: long Main.OrSame(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: <<Or:j\d+>> Or [ <<Arg>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Or:j\d+>> Or [<<Arg>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
// CHECK-NOT: Or
@@ -209,12 +209,12 @@
// CHECK-START: int Main.Shl0(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Shl:i\d+>> Shl [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Shl>> ]
+ // CHECK-DAG: <<Shl:i\d+>> Shl [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Shl>>]
// CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
// CHECK-NOT: Shl
@@ -226,13 +226,13 @@
// CHECK-START: int Main.Shl1(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Shl:i\d+>> Shl [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: Return [ <<Shl>> ]
+ // CHECK-DAG: <<Shl:i\d+>> Shl [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: Return [<<Shl>>]
// CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Arg>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Arg>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
// CHECK-NOT: Shl
@@ -244,12 +244,12 @@
// CHECK-START: long Main.Shr0(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Shr:j\d+>> Shr [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Shr>> ]
+ // CHECK-DAG: <<Shr:j\d+>> Shr [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Shr>>]
// CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
// CHECK-NOT: Shr
@@ -261,12 +261,12 @@
// CHECK-START: long Main.Sub0(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<Sub:j\d+>> Sub [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:j\d+>> Sub [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
// CHECK-NOT: Sub
@@ -278,13 +278,13 @@
// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
// CHECK-NOT: Sub
@@ -296,12 +296,12 @@
// CHECK-START: long Main.UShr0(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<UShr:j\d+>> UShr [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<UShr>> ]
+ // CHECK-DAG: <<UShr:j\d+>> UShr [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<UShr>>]
// CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
// CHECK-NOT: UShr
@@ -313,12 +313,12 @@
// CHECK-START: int Main.Xor0(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Xor:i\d+>> Xor [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Xor>> ]
+ // CHECK-DAG: <<Xor:i\d+>> Xor [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Xor>>]
// CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
// CHECK-NOT: Xor
@@ -330,13 +330,13 @@
// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstF:i\d+>> IntConstant -1
- // CHECK-DAG: <<Xor:i\d+>> Xor [ <<Arg>> <<ConstF>> ]
- // CHECK-DAG: Return [ <<Xor>> ]
+ // CHECK-DAG: <<Xor:i\d+>> Xor [<<Arg>>,<<ConstF>>]
+ // CHECK-DAG: Return [<<Xor>>]
// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Not:i\d+>> Not [ <<Arg>> ]
- // CHECK-DAG: Return [ <<Not>> ]
+ // CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>]
+ // CHECK-DAG: Return [<<Not>>]
// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
// CHECK-NOT: Xor
@@ -355,18 +355,18 @@
// CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
// CHECK-NOT: Neg
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Arg1>> <<Arg2>> ]
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Add>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Arg1>>,<<Arg2>>]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Add>>]
+ // CHECK-DAG: Return [<<Neg>>]
public static int AddNegs1(int arg1, int arg2) {
return -arg1 + -arg2;
@@ -386,32 +386,32 @@
// CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add1:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: <<Add2:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Add1>> <<Add2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add1:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: <<Add2:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Add1>>,<<Add2>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add1:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: <<Add2:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add1:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: <<Add2:i\d+>> Add [<<Neg1>>,<<Neg2>>]
// CHECK-NOT: Neg
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Add1>> <<Add2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Add1>>,<<Add2>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.AddNegs2(int, int) GVN (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Add>> <<Add>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Add>>,<<Add>>]
+ // CHECK-DAG: Return [<<Or>>]
public static int AddNegs2(int arg1, int arg2) {
int temp1 = -arg1;
@@ -431,24 +431,24 @@
// -------------- Arguments and initial negation operations.
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:j\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:j\d+>> Neg [ <<Arg2>> ]
+ // CHECK-DAG: <<Neg1:j\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:j\d+>> Neg [<<Arg2>>]
// CHECK: Goto
// -------------- Loop
// CHECK: SuspendCheck
- // CHECK: <<Add:j\d+>> Add [ <<Neg1>> <<Neg2>> ]
+ // CHECK: <<Add:j\d+>> Add [<<Neg1>>,<<Neg2>>]
// CHECK: Goto
// CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (after)
// -------------- Arguments and initial negation operations.
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:j\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Neg2:j\d+>> Neg [ <<Arg2>> ]
+ // CHECK-DAG: <<Neg1:j\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Neg2:j\d+>> Neg [<<Arg2>>]
// CHECK: Goto
// -------------- Loop
// CHECK: SuspendCheck
- // CHECK: <<Add:j\d+>> Add [ <<Neg1>> <<Neg2>> ]
+ // CHECK: <<Add:j\d+>> Add [<<Neg1>>,<<Neg2>>]
// CHECK-NOT: Neg
// CHECK: Goto
@@ -471,15 +471,15 @@
// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Add:j\d+>> Add [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Add:j\d+>> Add [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Sub:j\d+>> Sub [ <<Arg2>> <<Arg1>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:j\d+>> Sub [<<Arg2>>,<<Arg1>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
// CHECK-NOT: Neg
@@ -501,20 +501,20 @@
// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add1:j\d+>> Add [ <<Arg1>> <<Neg>> ]
- // CHECK-DAG: <<Add2:j\d+>> Add [ <<Arg1>> <<Neg>> ]
- // CHECK-DAG: <<Res:j\d+>> Or [ <<Add1>> <<Add2>> ]
- // CHECK-DAG: Return [ <<Res>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add1:j\d+>> Add [<<Arg1>>,<<Neg>>]
+ // CHECK-DAG: <<Add2:j\d+>> Add [<<Arg1>>,<<Neg>>]
+ // CHECK-DAG: <<Res:j\d+>> Or [<<Add1>>,<<Add2>>]
+ // CHECK-DAG: Return [<<Res>>]
// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg2>> ]
- // CHECK-DAG: <<Add1:j\d+>> Add [ <<Arg1>> <<Neg>> ]
- // CHECK-DAG: <<Add2:j\d+>> Add [ <<Arg1>> <<Neg>> ]
- // CHECK-DAG: <<Res:j\d+>> Or [ <<Add1>> <<Add2>> ]
- // CHECK-DAG: Return [ <<Res>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg2>>]
+ // CHECK-DAG: <<Add1:j\d+>> Add [<<Arg1>>,<<Neg>>]
+ // CHECK-DAG: <<Add2:j\d+>> Add [<<Arg1>>,<<Neg>>]
+ // CHECK-DAG: <<Res:j\d+>> Or [<<Add1>>,<<Add2>>]
+ // CHECK-DAG: Return [<<Res>>]
// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
// CHECK-NOT: Sub
@@ -531,13 +531,13 @@
// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:j\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: <<Neg2:j\d+>> Neg [ <<Neg1>> ]
- // CHECK-DAG: Return [ <<Neg2>> ]
+ // CHECK-DAG: <<Neg1:j\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: <<Neg2:j\d+>> Neg [<<Neg1>>]
+ // CHECK-DAG: Return [<<Neg2>>]
// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
// CHECK-NOT: Neg
@@ -555,15 +555,15 @@
// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Neg1>> ]
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Neg1>>]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Arg>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Arg>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
// CHECK-NOT: Neg
@@ -573,7 +573,7 @@
// CHECK: <<Const0:i\d+>> IntConstant 0
// CHECK-NOT: Neg
// CHECK-NOT: Add
- // CHECK: Return [ <<Const0>> ]
+ // CHECK: Return [<<Const0>>]
public static int NegNeg2(int arg) {
int temp = -arg;
@@ -590,13 +590,13 @@
// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<Const0:j\d+>> LongConstant 0
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg>> ]
- // CHECK-DAG: <<Sub:j\d+>> Sub [ <<Const0>> <<Neg>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg>>]
+ // CHECK-DAG: <<Sub:j\d+>> Sub [<<Const0>>,<<Neg>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
// CHECK-NOT: Neg
@@ -615,15 +615,15 @@
// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Arg1>> <<Arg2>> ]
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Sub>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Arg1>>,<<Arg2>>]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Sub>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Arg2>> <<Arg1>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Arg2>>,<<Arg1>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
// CHECK-NOT: Neg
@@ -645,20 +645,20 @@
// CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Arg1>> <<Arg2>> ]
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Sub>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Sub>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Arg1>>,<<Arg2>>]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Sub>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Sub>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Arg1>> <<Arg2>> ]
- // CHECK-DAG: <<Neg1:i\d+>> Neg [ <<Sub>> ]
- // CHECK-DAG: <<Neg2:i\d+>> Neg [ <<Sub>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Neg1>> <<Neg2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Arg1>>,<<Arg2>>]
+ // CHECK-DAG: <<Neg1:i\d+>> Neg [<<Sub>>]
+ // CHECK-DAG: <<Neg2:i\d+>> Neg [<<Sub>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Neg1>>,<<Neg2>>]
+ // CHECK-DAG: Return [<<Or>>]
public static int NegSub2(int arg1, int arg2) {
int temp = arg1 - arg2;
@@ -673,13 +673,13 @@
// CHECK-START: long Main.NotNot1(long) instruction_simplifier (before)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
// CHECK-DAG: <<ConstF1:j\d+>> LongConstant -1
- // CHECK-DAG: <<Xor1:j\d+>> Xor [ <<Arg>> <<ConstF1>> ]
- // CHECK-DAG: <<Xor2:j\d+>> Xor [ <<Xor1>> <<ConstF1>> ]
- // CHECK-DAG: Return [ <<Xor2>> ]
+ // CHECK-DAG: <<Xor1:j\d+>> Xor [<<Arg>>,<<ConstF1>>]
+ // CHECK-DAG: <<Xor2:j\d+>> Xor [<<Xor1>>,<<ConstF1>>]
+ // CHECK-DAG: Return [<<Xor2>>]
// CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
// CHECK-DAG: <<Arg:j\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
// CHECK-NOT: Xor
@@ -691,16 +691,16 @@
// CHECK-START: int Main.NotNot2(int) instruction_simplifier (before)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
// CHECK-DAG: <<ConstF1:i\d+>> IntConstant -1
- // CHECK-DAG: <<Xor1:i\d+>> Xor [ <<Arg>> <<ConstF1>> ]
- // CHECK-DAG: <<Xor2:i\d+>> Xor [ <<Xor1>> <<ConstF1>> ]
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Xor1>> <<Xor2>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Xor1:i\d+>> Xor [<<Arg>>,<<ConstF1>>]
+ // CHECK-DAG: <<Xor2:i\d+>> Xor [<<Xor1>>,<<ConstF1>>]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Xor1>>,<<Xor2>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: <<Not:i\d+>> Not [ <<Arg>> ]
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Not>> <<Arg>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Not:i\d+>> Not [<<Arg>>]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Not>>,<<Arg>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
// CHECK-NOT: Xor
@@ -718,16 +718,16 @@
// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Add:i\d+>> Add [ <<Arg1>> <<Arg2>> ]
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Add>> ]
- // CHECK-DAG: Return [ <<Neg>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<Arg1>>,<<Arg2>>]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Add>>]
+ // CHECK-DAG: Return [<<Neg>>]
// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
// CHECK-NOT: Sub
@@ -749,20 +749,20 @@
// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (before)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Sub1:i\d+>> Sub [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: <<Sub2:i\d+>> Sub [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Sub1>> <<Sub2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Sub1:i\d+>> Sub [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: <<Sub2:i\d+>> Sub [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Sub1>>,<<Sub2>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
// CHECK-DAG: <<Arg1:i\d+>> ParameterValue
// CHECK-DAG: <<Arg2:i\d+>> ParameterValue
- // CHECK-DAG: <<Neg:i\d+>> Neg [ <<Arg1>> ]
- // CHECK-DAG: <<Sub1:i\d+>> Sub [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: <<Sub2:i\d+>> Sub [ <<Neg>> <<Arg2>> ]
- // CHECK-DAG: <<Or:i\d+>> Or [ <<Sub1>> <<Sub2>> ]
- // CHECK-DAG: Return [ <<Or>> ]
+ // CHECK-DAG: <<Neg:i\d+>> Neg [<<Arg1>>]
+ // CHECK-DAG: <<Sub1:i\d+>> Sub [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: <<Sub2:i\d+>> Sub [<<Neg>>,<<Arg2>>]
+ // CHECK-DAG: <<Or:i\d+>> Or [<<Sub1>>,<<Sub2>>]
+ // CHECK-DAG: Return [<<Or>>]
// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
// CHECK-NOT: Add
@@ -783,22 +783,22 @@
// -------------- Arguments and initial negation operation.
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg1>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg1>>]
// CHECK: Goto
// -------------- Loop
// CHECK: SuspendCheck
- // CHECK: <<Sub:j\d+>> Sub [ <<Neg>> <<Arg2>> ]
+ // CHECK: <<Sub:j\d+>> Sub [<<Neg>>,<<Arg2>>]
// CHECK: Goto
// CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (after)
// -------------- Arguments and initial negation operation.
// CHECK-DAG: <<Arg1:j\d+>> ParameterValue
// CHECK-DAG: <<Arg2:j\d+>> ParameterValue
- // CHECK-DAG: <<Neg:j\d+>> Neg [ <<Arg1>> ]
+ // CHECK-DAG: <<Neg:j\d+>> Neg [<<Arg1>>]
// CHECK-DAG: Goto
// -------------- Loop
// CHECK: SuspendCheck
- // CHECK: <<Sub:j\d+>> Sub [ <<Neg>> <<Arg2>> ]
+ // CHECK: <<Sub:j\d+>> Sub [<<Neg>>,<<Arg2>>]
// CHECK-NOT: Neg
// CHECK: Goto
@@ -814,12 +814,12 @@
// CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> Equal [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> Equal [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: If [ <<Arg>> ]
+ // CHECK-DAG: If [<<Arg>>]
public static int EqualTrueRhs(boolean arg) {
return (arg != true) ? 3 : 5;
@@ -828,12 +828,12 @@
// CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> Equal [ <<Const1>> <<Arg>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> Equal [<<Const1>>,<<Arg>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: If [ <<Arg>> ]
+ // CHECK-DAG: If [<<Arg>>]
public static int EqualTrueLhs(boolean arg) {
return (true != arg) ? 3 : 5;
@@ -842,13 +842,13 @@
// CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Cond:z\d+>> Equal [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> Equal [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [ <<Arg>> ]
- // CHECK-DAG: If [ <<NotArg>> ]
+ // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [<<Arg>>]
+ // CHECK-DAG: If [<<NotArg>>]
public static int EqualFalseRhs(boolean arg) {
return (arg != false) ? 3 : 5;
@@ -857,13 +857,13 @@
// CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Cond:z\d+>> Equal [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> Equal [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [ <<Arg>> ]
- // CHECK-DAG: If [ <<NotArg>> ]
+ // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [<<Arg>>]
+ // CHECK-DAG: If [<<NotArg>>]
public static int EqualFalseLhs(boolean arg) {
return (false != arg) ? 3 : 5;
@@ -872,13 +872,13 @@
// CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> NotEqual [ <<Arg>> <<Const1>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Arg>>,<<Const1>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [ <<Arg>> ]
- // CHECK-DAG: If [ <<NotArg>> ]
+ // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [<<Arg>>]
+ // CHECK-DAG: If [<<NotArg>>]
public static int NotEqualTrueRhs(boolean arg) {
return (arg == true) ? 3 : 5;
@@ -887,13 +887,13 @@
// CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> NotEqual [ <<Const1>> <<Arg>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Const1>>,<<Arg>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [ <<Arg>> ]
- // CHECK-DAG: If [ <<NotArg>> ]
+ // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [<<Arg>>]
+ // CHECK-DAG: If [<<NotArg>>]
public static int NotEqualTrueLhs(boolean arg) {
return (true == arg) ? 3 : 5;
@@ -902,12 +902,12 @@
// CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Cond:z\d+>> NotEqual [ <<Arg>> <<Const0>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Arg>>,<<Const0>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: If [ <<Arg>> ]
+ // CHECK-DAG: If [<<Arg>>]
public static int NotEqualFalseRhs(boolean arg) {
return (arg == false) ? 3 : 5;
@@ -916,12 +916,12 @@
// CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<Cond:z\d+>> NotEqual [ <<Const0>> <<Arg>> ]
- // CHECK-DAG: If [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Const0>>,<<Arg>>]
+ // CHECK-DAG: If [<<Cond>>]
// CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: If [ <<Arg>> ]
+ // CHECK-DAG: If [<<Arg>>]
public static int NotEqualFalseLhs(boolean arg) {
return (false == arg) ? 3 : 5;
@@ -935,14 +935,14 @@
// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (before)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [ <<Arg>> ]
- // CHECK-DAG: <<NotNotArg:z\d+>> BooleanNot [ <<NotArg>> ]
- // CHECK-DAG: Return [ <<NotNotArg>> ]
+ // CHECK-DAG: <<NotArg:z\d+>> BooleanNot [<<Arg>>]
+ // CHECK-DAG: <<NotNotArg:z\d+>> BooleanNot [<<NotArg>>]
+ // CHECK-DAG: Return [<<NotNotArg>>]
// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
// CHECK-DAG: <<Arg:z\d+>> ParameterValue
- // CHECK-DAG: BooleanNot [ <<Arg>> ]
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: BooleanNot [<<Arg>>]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
// CHECK: BooleanNot
@@ -959,14 +959,14 @@
// CHECK-START: float Main.Div2(float) instruction_simplifier (before)
// CHECK-DAG: <<Arg:f\d+>> ParameterValue
// CHECK-DAG: <<Const2:f\d+>> FloatConstant 2
- // CHECK-DAG: <<Div:f\d+>> Div [ <<Arg>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:f\d+>> Div [<<Arg>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: float Main.Div2(float) instruction_simplifier (after)
// CHECK-DAG: <<Arg:f\d+>> ParameterValue
// CHECK-DAG: <<ConstP5:f\d+>> FloatConstant 0.5
- // CHECK-DAG: <<Mul:f\d+>> Mul [ <<Arg>> <<ConstP5>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:f\d+>> Mul [<<Arg>>,<<ConstP5>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: float Main.Div2(float) instruction_simplifier (after)
// CHECK-NOT: Div
@@ -978,14 +978,14 @@
// CHECK-START: double Main.Div2(double) instruction_simplifier (before)
// CHECK-DAG: <<Arg:d\d+>> ParameterValue
// CHECK-DAG: <<Const2:d\d+>> DoubleConstant 2
- // CHECK-DAG: <<Div:d\d+>> Div [ <<Arg>> <<Const2>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:d\d+>> Div [<<Arg>>,<<Const2>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: double Main.Div2(double) instruction_simplifier (after)
// CHECK-DAG: <<Arg:d\d+>> ParameterValue
// CHECK-DAG: <<ConstP5:d\d+>> DoubleConstant 0.5
- // CHECK-DAG: <<Mul:d\d+>> Mul [ <<Arg>> <<ConstP5>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:d\d+>> Mul [<<Arg>>,<<ConstP5>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: double Main.Div2(double) instruction_simplifier (after)
// CHECK-NOT: Div
@@ -996,14 +996,14 @@
// CHECK-START: float Main.DivMP25(float) instruction_simplifier (before)
// CHECK-DAG: <<Arg:f\d+>> ParameterValue
// CHECK-DAG: <<ConstMP25:f\d+>> FloatConstant -0.25
- // CHECK-DAG: <<Div:f\d+>> Div [ <<Arg>> <<ConstMP25>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:f\d+>> Div [<<Arg>>,<<ConstMP25>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
// CHECK-DAG: <<Arg:f\d+>> ParameterValue
// CHECK-DAG: <<ConstM4:f\d+>> FloatConstant -4
- // CHECK-DAG: <<Mul:f\d+>> Mul [ <<Arg>> <<ConstM4>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:f\d+>> Mul [<<Arg>>,<<ConstM4>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
// CHECK-NOT: Div
@@ -1015,14 +1015,14 @@
// CHECK-START: double Main.DivMP25(double) instruction_simplifier (before)
// CHECK-DAG: <<Arg:d\d+>> ParameterValue
// CHECK-DAG: <<ConstMP25:d\d+>> DoubleConstant -0.25
- // CHECK-DAG: <<Div:d\d+>> Div [ <<Arg>> <<ConstMP25>> ]
- // CHECK-DAG: Return [ <<Div>> ]
+ // CHECK-DAG: <<Div:d\d+>> Div [<<Arg>>,<<ConstMP25>>]
+ // CHECK-DAG: Return [<<Div>>]
// CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
// CHECK-DAG: <<Arg:d\d+>> ParameterValue
// CHECK-DAG: <<ConstM4:d\d+>> DoubleConstant -4
- // CHECK-DAG: <<Mul:d\d+>> Mul [ <<Arg>> <<ConstM4>> ]
- // CHECK-DAG: Return [ <<Mul>> ]
+ // CHECK-DAG: <<Mul:d\d+>> Mul [<<Arg>>,<<ConstM4>>]
+ // CHECK-DAG: Return [<<Mul>>]
// CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
// CHECK-NOT: Div
diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java
index 5ebf3d1..218c7ce 100644
--- a/test/462-checker-inlining-across-dex-files/src/Main.java
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -34,14 +34,14 @@
// CHECK-START: int Main.inlineReturnIntMethod() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
// CHECK-DAG: <<Const38:i\d+>> IntConstant 38
- // CHECK-DAG: Return [ <<Const38>> ]
+ // CHECK-DAG: Return [<<Const38>>]
public static int inlineReturnIntMethod() {
return OtherDex.returnIntMethod();
@@ -49,11 +49,11 @@
// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
public static int dontInlineOtherDexStatic() {
return OtherDex.returnOtherDexStatic();
@@ -61,14 +61,14 @@
// CHECK-START: int Main.inlineMainStatic() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineMainStatic() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: int Main.inlineMainStatic() inliner (after)
// CHECK-DAG: <<Static:i\d+>> StaticFieldGet
- // CHECK-DAG: Return [ <<Static>> ]
+ // CHECK-DAG: Return [<<Static>>]
public static int inlineMainStatic() {
return OtherDex.returnMainStatic();
@@ -76,11 +76,11 @@
// CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
public static int dontInlineRecursiveCall() {
return OtherDex.recursiveCall();
@@ -88,11 +88,11 @@
// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
public static String dontInlineReturnString() {
return OtherDex.returnString();
@@ -100,11 +100,11 @@
// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
public static Class dontInlineOtherDexClass() {
return OtherDex.returnOtherDexClass();
@@ -112,14 +112,16 @@
// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
- // CHECK-DAG: <<Class:l\d+>> LoadClass
- // CHECK-DAG: Return [ <<Class>> ]
+ // CHECK-DAG: Return [<<Class:l\d+>>]
+ // CHECK-DAG: <<Class>> LoadClass
+ // Note: There are two LoadClass instructions. We obtain the correct
+ // instruction id by matching the Return's input list first.
public static Class inlineMainClass() {
return OtherDex.returnMainClass();
@@ -127,11 +129,11 @@
// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
public static Class dontInlineOtherDexClassStaticCall() {
return OtherDex.returnOtherDexClassStaticCall();
@@ -139,14 +141,16 @@
// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (before)
// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
- // CHECK-DAG: <<Class:l\d+>> LoadClass
- // CHECK-DAG: Return [ <<Class>> ]
+ // CHECK-DAG: Return [<<Class:l\d+>>]
+ // CHECK-DAG: <<Class>> LoadClass
+ // Note: There are two LoadClass instructions. We obtain the correct
+ // instruction id by matching the Return's input list first.
public static Class inlineOtherDexCallingMain() {
return OtherDex.returnOtherDexCallingMain();
diff --git a/test/463-checker-boolean-simplifier/src/Main.java b/test/463-checker-boolean-simplifier/src/Main.java
index 3f3110f..e237448 100644
--- a/test/463-checker-boolean-simplifier/src/Main.java
+++ b/test/463-checker-boolean-simplifier/src/Main.java
@@ -41,9 +41,9 @@
// CHECK-DAG: <<Param:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: If [ <<Param>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const1>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: If [<<Param>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
// CHECK: Goto
@@ -54,8 +54,8 @@
// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
// CHECK-DAG: <<Param:z\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
- // CHECK-DAG: <<NotParam:z\d+>> BooleanNot [ <<Param>> ]
- // CHECK-DAG: Return [ <<NotParam>> ]
+ // CHECK-DAG: <<NotParam:z\d+>> BooleanNot [<<Param>>]
+ // CHECK-DAG: Return [<<NotParam>>]
// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
// CHECK-NOT: If
@@ -79,18 +79,18 @@
// CHECK-DAG: <<ParamY:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> GreaterThan [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: If [ <<Cond>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const0>> <<Const1>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: If [<<Cond>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,<<Const1>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (after)
// CHECK-DAG: <<ParamX:i\d+>> ParameterValue
// CHECK-DAG: <<ParamY:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> GreaterThan [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: Return [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: Return [<<Cond>>]
public static boolean GreaterThan(int x, int y) {
return (x <= y) ? false : true;
@@ -106,18 +106,18 @@
// CHECK-DAG: <<ParamY:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: If [ <<Cond>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const1>> <<Const0>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Cond:z\d+>> GreaterThanOrEqual [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: If [<<Cond>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
// CHECK-DAG: <<ParamX:i\d+>> ParameterValue
// CHECK-DAG: <<ParamY:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<Cond:z\d+>> LessThan [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: Return [ <<Cond>> ]
+ // CHECK-DAG: <<Cond:z\d+>> LessThan [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: Return [<<Cond>>]
// CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
// CHECK-NOT: GreaterThanOrEqual
@@ -137,25 +137,25 @@
// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue
// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
- // CHECK-DAG: <<CondXY:z\d+>> GreaterThan [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: If [ <<CondXY>> ]
- // CHECK-DAG: <<CondYZ:z\d+>> GreaterThan [ <<ParamY>> <<ParamZ>> ]
- // CHECK-DAG: If [ <<CondYZ>> ]
- // CHECK-DAG: <<CondXYZ:z\d+>> NotEqual [ <<PhiXY:i\d+>> <<PhiYZ:i\d+>> ]
- // CHECK-DAG: If [ <<CondXYZ>> ]
- // CHECK-DAG: Return [ <<PhiXYZ:i\d+>> ]
- // CHECK-DAG: <<PhiXY>> Phi [ <<Const1>> <<Const0>> ]
- // CHECK-DAG: <<PhiYZ>> Phi [ <<Const1>> <<Const0>> ]
- // CHECK-DAG: <<PhiXYZ>> Phi [ <<Const1>> <<Const0>> ]
+ // CHECK-DAG: <<CondXY:z\d+>> GreaterThan [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: If [<<CondXY>>]
+ // CHECK-DAG: <<CondYZ:z\d+>> GreaterThan [<<ParamY>>,<<ParamZ>>]
+ // CHECK-DAG: If [<<CondYZ>>]
+ // CHECK-DAG: <<CondXYZ:z\d+>> NotEqual [<<PhiXY:i\d+>>,<<PhiYZ:i\d+>>]
+ // CHECK-DAG: If [<<CondXYZ>>]
+ // CHECK-DAG: Return [<<PhiXYZ:i\d+>>]
+ // CHECK-DAG: <<PhiXY>> Phi [<<Const1>>,<<Const0>>]
+ // CHECK-DAG: <<PhiYZ>> Phi [<<Const1>>,<<Const0>>]
+ // CHECK-DAG: <<PhiXYZ>> Phi [<<Const1>>,<<Const0>>]
// CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (after)
// CHECK-DAG: <<ParamX:i\d+>> ParameterValue
// CHECK-DAG: <<ParamY:i\d+>> ParameterValue
// CHECK-DAG: <<ParamZ:i\d+>> ParameterValue
- // CHECK-DAG: <<CmpXY:z\d+>> LessThanOrEqual [ <<ParamX>> <<ParamY>> ]
- // CHECK-DAG: <<CmpYZ:z\d+>> LessThanOrEqual [ <<ParamY>> <<ParamZ>> ]
- // CHECK-DAG: <<CmpXYZ:z\d+>> Equal [ <<CmpXY>> <<CmpYZ>> ]
- // CHECK-DAG: Return [ <<CmpXYZ>> ]
+ // CHECK-DAG: <<CmpXY:z\d+>> LessThanOrEqual [<<ParamX>>,<<ParamY>>]
+ // CHECK-DAG: <<CmpYZ:z\d+>> LessThanOrEqual [<<ParamY>>,<<ParamZ>>]
+ // CHECK-DAG: <<CmpXYZ:z\d+>> Equal [<<CmpXY>>,<<CmpYZ>>]
+ // CHECK-DAG: Return [<<CmpXYZ>>]
public static boolean ValuesOrdered(int x, int y, int z) {
return (x <= y) == (y <= z);
@@ -165,18 +165,18 @@
// CHECK-DAG: <<Param:z\d+>> ParameterValue
// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
// CHECK-DAG: <<Const43:i\d+>> IntConstant 43
- // CHECK-DAG: <<NotParam:z\d+>> BooleanNot [ <<Param>> ]
- // CHECK-DAG: If [ <<NotParam>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const42>> <<Const43>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<NotParam:z\d+>> BooleanNot [<<Param>>]
+ // CHECK-DAG: If [<<NotParam>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const42>>,<<Const43>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
// CHECK-DAG: <<Param:z\d+>> ParameterValue
// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
// CHECK-DAG: <<Const43:i\d+>> IntConstant 43
- // CHECK-DAG: If [ <<Param>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const42>> <<Const43>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: If [<<Param>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Const42>>,<<Const43>>]
+ // CHECK-DAG: Return [<<Phi>>]
// Note: The fact that branches are swapped is verified by running the test.
diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java
index 626823e..e451f70 100644
--- a/test/464-checker-inline-sharpen-calls/src/Main.java
+++ b/test/464-checker-inline-sharpen-calls/src/Main.java
@@ -32,14 +32,14 @@
// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before)
// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- // CHECK-DAG: Return [ <<Invoke>> ]
+ // CHECK-DAG: Return [<<Invoke>>]
// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
// CHECK-DAG: <<Field:i\d+>> InstanceFieldGet
- // CHECK-DAG: Return [ <<Field>> ]
+ // CHECK-DAG: Return [<<Field>>]
public static int inlineSharpenStringInvoke() {
return "Foo".length();
diff --git a/test/465-checker-clinit-gvn/src/Main.java b/test/465-checker-clinit-gvn/src/Main.java
index b712715..ac2863c 100644
--- a/test/465-checker-clinit-gvn/src/Main.java
+++ b/test/465-checker-clinit-gvn/src/Main.java
@@ -28,13 +28,13 @@
// CHECK-START: int Main.accessTwoStatics() GVN (before)
// CHECK-DAG: <<Class1:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class1>> ]
+ // CHECK-DAG: ClinitCheck [<<Class1>>]
// CHECK-DAG: <<Class2:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class2>> ]
+ // CHECK-DAG: ClinitCheck [<<Class2>>]
// CHECK-START: int Main.accessTwoStatics() GVN (after)
// CHECK-DAG: <<Class:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class>> ]
+ // CHECK-DAG: ClinitCheck [<<Class>>]
// CHECK-NOT: ClinitCheck
public static int accessTwoStatics() {
@@ -43,13 +43,13 @@
// CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (before)
// CHECK-DAG: <<Class1:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class1>> ]
+ // CHECK-DAG: ClinitCheck [<<Class1>>]
// CHECK-DAG: <<Class2:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class2>> ]
+ // CHECK-DAG: ClinitCheck [<<Class2>>]
// CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (after)
// CHECK-DAG: <<Class:l\d+>> LoadClass
- // CHECK-DAG: ClinitCheck [ <<Class>> ]
+ // CHECK-DAG: ClinitCheck [<<Class>>]
// CHECK-NOT: ClinitCheck
public static int accessTwoStaticsCallInBetween() {
diff --git a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
index 0cb5313..33e6dc3 100644
--- a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
+++ b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
@@ -22,14 +22,14 @@
# CHECK-DAG: <<Const0:i\d+>> IntConstant 0
# CHECK-DAG: <<Const1:i\d+>> IntConstant 1
# CHECK-DAG: <<Value:z\d+>> StaticFieldGet
-# CHECK-DAG: If [ <<Value>> ]
-# CHECK-DAG: <<Phi:i\d+>> Phi [ <<Const1>> <<Const0>> ]
-# CHECK-DAG: Return [ <<Phi>> ]
+# CHECK-DAG: If [<<Value>>]
+# CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,<<Const0>>]
+# CHECK-DAG: Return [<<Phi>>]
# CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
# CHECK-DAG: <<Value:z\d+>> StaticFieldGet
-# CHECK-DAG: <<Not:z\d+>> BooleanNot [ <<Value>> ]
-# CHECK-DAG: Return [ <<Not>> ]
+# CHECK-DAG: <<Not:z\d+>> BooleanNot [<<Value>>]
+# CHECK-DAG: Return [<<Not>>]
.method public static testCase()Z
.registers 2
diff --git a/test/474-checker-boolean-input/src/Main.java b/test/474-checker-boolean-input/src/Main.java
index a395ff9..490f7f9 100644
--- a/test/474-checker-boolean-input/src/Main.java
+++ b/test/474-checker-boolean-input/src/Main.java
@@ -29,7 +29,7 @@
// CHECK-START: boolean Main.TestPhiAsBoolean(int) boolean_simplifier (after)
// CHECK-DAG: <<Phi:i\d+>> Phi
- // CHECK-DAG: BooleanNot [ <<Phi>> ]
+ // CHECK-DAG: BooleanNot [<<Phi>>]
public static boolean f1;
public static boolean f2;
@@ -49,7 +49,7 @@
// CHECK-START: boolean Main.TestAndAsBoolean(boolean, boolean) boolean_simplifier (after)
// CHECK-DAG: <<And:i\d+>> And
- // CHECK-DAG: BooleanNot [ <<And>> ]
+ // CHECK-DAG: BooleanNot [<<And>>]
public static boolean InlineAnd(boolean x, boolean y) {
return x & y;
@@ -66,7 +66,7 @@
// CHECK-START: boolean Main.TestOrAsBoolean(boolean, boolean) boolean_simplifier (after)
// CHECK-DAG: <<Or:i\d+>> Or
- // CHECK-DAG: BooleanNot [ <<Or>> ]
+ // CHECK-DAG: BooleanNot [<<Or>>]
public static boolean InlineOr(boolean x, boolean y) {
return x | y;
@@ -83,7 +83,7 @@
// CHECK-START: boolean Main.TestXorAsBoolean(boolean, boolean) boolean_simplifier (after)
// CHECK-DAG: <<Xor:i\d+>> Xor
- // CHECK-DAG: BooleanNot [ <<Xor>> ]
+ // CHECK-DAG: BooleanNot [<<Xor>>]
public static boolean InlineXor(boolean x, boolean y) {
return x ^ y;
diff --git a/test/476-checker-ctor-memory-barrier/src/Main.java b/test/476-checker-ctor-memory-barrier/src/Main.java
index 769ae20..75cb1d7 100644
--- a/test/476-checker-ctor-memory-barrier/src/Main.java
+++ b/test/476-checker-ctor-memory-barrier/src/Main.java
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+// TODO: Add more tests after we can inline functions with calls.
class ClassWithoutFinals {
// CHECK-START: void ClassWithoutFinals.<init>() register (after)
@@ -80,6 +81,20 @@
super(cond);
// should not inline the super constructor
}
+
+ // CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: ReturnVoid
+
+ // CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+ public InheritFromClassWithFinals(int unused) {
+ // Should inline the super constructor and insert a memory barrier.
+
+ // Should inline the new instance call and insert another memory barrier.
+ new InheritFromClassWithFinals();
+ }
}
class HaveFinalsAndInheritFromClassWithFinals extends ClassWithFinals {
@@ -87,14 +102,13 @@
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
// CHECK: MemoryBarrier kind:StoreStore
- // CHECK: MemoryBarrier kind:StoreStore
// CHECK-NOT: {{.*}}
// CHECK: ReturnVoid
// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
// CHECK-NOT: InvokeStaticOrDirect
public HaveFinalsAndInheritFromClassWithFinals() {
- // Should inline the super constructor.
+ // Should inline the super constructor and remove the memory barrier.
y = 0;
}
@@ -108,6 +122,25 @@
// should not inline the super constructor
y = 0;
}
+
+ // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NOT: {{.*}}
+ // CHECK: ReturnVoid
+
+ // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+ public HaveFinalsAndInheritFromClassWithFinals(int unused) {
+ // Should inline the super constructor and keep just one memory barrier.
+ y = 0;
+
+ // Should inline new instance and keep one barrier.
+ new HaveFinalsAndInheritFromClassWithFinals();
+ // Should inline new instance and keep one barrier.
+ new InheritFromClassWithFinals();
+ }
}
public class Main {
@@ -121,27 +154,51 @@
return new ClassWithFinals(false);
}
- // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
+ // CHECK-START: void Main.inlineNew() register (after)
// CHECK: MemoryBarrier kind:StoreStore
// CHECK-NOT: {{.*}}
- // CHECK: Return
+ // CHECK: ReturnVoid
- // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
+ // CHECK-START: void Main.inlineNew() register (after)
// CHECK-NOT: InvokeStaticOrDirect
- public static ClassWithFinals inlineConstructorBarrier() {
- return new ClassWithFinals();
+ public static void inlineNew() {
+ new ClassWithFinals();
}
- // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
+ // CHECK-START: void Main.inlineNew1() register (after)
// CHECK: MemoryBarrier kind:StoreStore
// CHECK-NOT: {{.*}}
- // CHECK: Return
+ // CHECK: ReturnVoid
- // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
+ // CHECK-START: void Main.inlineNew1() register (after)
// CHECK-NOT: InvokeStaticOrDirect
- public static InheritFromClassWithFinals doubleInlineConstructorBarrier() {
- return new InheritFromClassWithFinals();
+ public static void inlineNew1() {
+ new InheritFromClassWithFinals();
}
- public static void main(String[] args) { }
+ // CHECK-START: void Main.inlineNew2() register (after)
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NOT: {{.*}}
+ // CHECK: ReturnVoid
+
+ // CHECK-START: void Main.inlineNew2() register (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+ public static void inlineNew2() {
+ new HaveFinalsAndInheritFromClassWithFinals();
+ }
+
+ // CHECK-START: void Main.inlineNew3() register (after)
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK: MemoryBarrier kind:StoreStore
+ // CHECK-NOT: {{.*}}
+ // CHECK: ReturnVoid
+
+ // CHECK-START: void Main.inlineNew3() register (after)
+ // CHECK-NOT: InvokeStaticOrDirect
+ public static void inlineNew3() {
+ new HaveFinalsAndInheritFromClassWithFinals();
+ new HaveFinalsAndInheritFromClassWithFinals();
+ }
+
+ public static void main(String[] args) {}
}
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index b36b7d6..61199a7 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -25,12 +25,12 @@
// CHECK-START: void Main.invokeStaticInlined() builder (after)
// CHECK-DAG: <<LoadClass:l\d+>> LoadClass
- // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [ <<LoadClass>> ]
- // CHECK-DAG: InvokeStaticOrDirect [ <<ClinitCheck>> ]
+ // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
+ // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
// CHECK-START: void Main.invokeStaticInlined() inliner (after)
// CHECK-DAG: <<LoadClass:l\d+>> LoadClass
- // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [ <<LoadClass>> ]
+ // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
// CHECK-START: void Main.invokeStaticInlined() inliner (after)
// CHECK-NOT: InvokeStaticOrDirect
@@ -68,13 +68,13 @@
// CHECK-START: void Main.invokeStaticNotInlined() builder (after)
// CHECK-DAG: <<LoadClass:l\d+>> LoadClass
- // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [ <<LoadClass>> ]
- // CHECK-DAG: InvokeStaticOrDirect [ <<ClinitCheck>> ]
+ // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
+ // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
// CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
// CHECK-DAG: <<LoadClass:l\d+>> LoadClass
- // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [ <<LoadClass>> ]
- // CHECK-DAG: InvokeStaticOrDirect [ <<ClinitCheck>> ]
+ // CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
+ // CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
// The following checks ensure the clinit check and load class
// instructions added by the builder are pruned by the
diff --git a/test/480-checker-dead-blocks/src/Main.java b/test/480-checker-dead-blocks/src/Main.java
index dda1a43..b76755e 100644
--- a/test/480-checker-dead-blocks/src/Main.java
+++ b/test/480-checker-dead-blocks/src/Main.java
@@ -34,16 +34,16 @@
// CHECK-DAG: <<ArgX:i\d+>> ParameterValue
// CHECK-DAG: <<ArgY:i\d+>> ParameterValue
// CHECK-DAG: If
- // CHECK-DAG: <<Add:i\d+>> Add [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Add>> <<Sub>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
// CHECK-DAG: <<ArgX:i\d+>> ParameterValue
// CHECK-DAG: <<ArgY:i\d+>> ParameterValue
- // CHECK-DAG: <<Add:i\d+>> Add [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: Return [ <<Add>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: Return [<<Add>>]
// CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
// CHECK-NOT: If
@@ -64,16 +64,16 @@
// CHECK-DAG: <<ArgX:i\d+>> ParameterValue
// CHECK-DAG: <<ArgY:i\d+>> ParameterValue
// CHECK-DAG: If
- // CHECK-DAG: <<Add:i\d+>> Add [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: <<Phi:i\d+>> Phi [ <<Add>> <<Sub>> ]
- // CHECK-DAG: Return [ <<Phi>> ]
+ // CHECK-DAG: <<Add:i\d+>> Add [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
+ // CHECK-DAG: Return [<<Phi>>]
// CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
// CHECK-DAG: <<ArgX:i\d+>> ParameterValue
// CHECK-DAG: <<ArgY:i\d+>> ParameterValue
- // CHECK-DAG: <<Sub:i\d+>> Sub [ <<ArgX>> <<ArgY>> ]
- // CHECK-DAG: Return [ <<Sub>> ]
+ // CHECK-DAG: <<Sub:i\d+>> Sub [<<ArgX>>,<<ArgY>>]
+ // CHECK-DAG: Return [<<Sub>>]
// CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
// CHECK-NOT: If
@@ -126,7 +126,7 @@
// CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
// CHECK-NOT: If
@@ -146,7 +146,7 @@
// CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
// CHECK-DAG: <<Arg:i\d+>> ParameterValue
- // CHECK-DAG: Return [ <<Arg>> ]
+ // CHECK-DAG: Return [<<Arg>>]
// CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
// CHECK-NOT: If
diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java
index 334792e..0ed9267 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -18,14 +18,14 @@
public class Main {
// CHECK-START: void Main.loop1(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-22 ] uses:[ 17 22 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,22)} uses:[17,22]
// CHECK: Goto liveness:20
public static void loop1(boolean incoming) {
while (incoming) {}
}
// CHECK-START: void Main.loop2(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-42 ] uses:[ 33 38 42 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,42)} uses:[33,38,42]
// CHECK: Goto liveness:36
// CHECK: Goto liveness:40
public static void loop2(boolean incoming) {
@@ -36,7 +36,7 @@
}
// CHECK-START: void Main.loop3(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-60 ] uses:[ 56 60 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,60)} uses:[56,60]
// CHECK: Goto liveness:58
// CHECK-START: void Main.loop3(boolean) liveness (after)
@@ -50,7 +50,7 @@
}
// CHECK-START: void Main.loop4(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-22 ] uses:[ 22 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,22)} uses:[22]
// CHECK-START: void Main.loop4(boolean) liveness (after)
// CHECK-NOT: Goto liveness:20
@@ -63,7 +63,7 @@
}
// CHECK-START: void Main.loop5(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-50 ] uses:[ 33 42 46 50 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,50)} uses:[33,42,46,50]
// CHECK: Goto liveness:44
// CHECK: Goto liveness:48
public static void loop5(boolean incoming) {
@@ -76,7 +76,7 @@
}
// CHECK-START: void Main.loop6(boolean) liveness (after)
- // CHECK ParameterValue liveness:2 ranges:[ 2-46 ] uses:[ 24 46 ]
+ // CHECK ParameterValue liveness:2 ranges:{[2,46)} uses:[24,46]
// CHECK: Goto liveness:44
// CHECK-START: void Main.loop6(boolean) liveness (after)
@@ -90,7 +90,7 @@
}
// CHECK-START: void Main.loop7(boolean) liveness (after)
- // CHECK: ParameterValue liveness:2 ranges:[ 2-50 ] uses:[ 32 41 46 50 ]
+ // CHECK: ParameterValue liveness:2 ranges:{[2,50)} uses:[32,41,46,50]
// CHECK: Goto liveness:44
// CHECK: Goto liveness:48
public static void loop7(boolean incoming) {
@@ -102,7 +102,7 @@
}
// CHECK-START: void Main.loop8() liveness (after)
- // CHECK: StaticFieldGet liveness:12 ranges:[ 12-44 ] uses:[ 35 40 44 ]
+ // CHECK: StaticFieldGet liveness:12 ranges:{[12,44)} uses:[35,40,44]
// CHECK: Goto liveness:38
// CHECK: Goto liveness:42
public static void loop8() {
@@ -114,7 +114,7 @@
}
// CHECK-START: void Main.loop9() liveness (after)
- // CHECK: StaticFieldGet liveness:22 ranges:[ 22-36 ] uses:[ 31 36 ]
+ // CHECK: StaticFieldGet liveness:22 ranges:{[22,36)} uses:[31,36]
// CHECK: Goto liveness:38
public static void loop9() {
while (Runtime.getRuntime() != null) {
diff --git a/test/485-checker-dce-loop-update/smali/TestCase.smali b/test/485-checker-dce-loop-update/smali/TestCase.smali
index bdc4038..487a5df 100644
--- a/test/485-checker-dce-loop-update/smali/TestCase.smali
+++ b/test/485-checker-dce-loop-update/smali/TestCase.smali
@@ -29,21 +29,21 @@
# CHECK-DAG: <<Cst1:i\d+>> IntConstant 1
# CHECK-DAG: <<Cst5:i\d+>> IntConstant 5
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<Add5:i\d+>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<Cst1>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add5>> Add [ <<PhiX>> <<Cst5>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<Cst1>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add5>> Add [<<PhiX>>,<<Cst5>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: Return [<<PhiX>>] loop:none
# CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (after)
# CHECK-DAG: <<ArgX:i\d+>> ParameterValue
# CHECK-DAG: <<ArgY:z\d+>> ParameterValue
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<AddX:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<AddX>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<AddX:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: <<AddX>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: Return [<<PhiX>>] loop:none
.method public static testSingleExit(IZ)I
.registers 3
@@ -80,24 +80,24 @@
# CHECK-DAG: <<Cst1:i\d+>> IntConstant 1
# CHECK-DAG: <<Cst5:i\d+>> IntConstant 5
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<Add5:i\d+>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgZ>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<Cst1>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add5>> Add [ <<PhiX>> <<Cst5>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<ArgZ>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<Cst1>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add5>> Add [<<PhiX>>,<<Cst5>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: Return [<<PhiX>>] loop:none
# CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (after)
# CHECK-DAG: <<ArgX:i\d+>> ParameterValue
# CHECK-DAG: <<ArgY:z\d+>> ParameterValue
# CHECK-DAG: <<ArgZ:z\d+>> ParameterValue
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgZ>> ] loop:none
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<ArgZ>>] loop:none
+# CHECK-DAG: Return [<<PhiX>>] loop:none
.method public static testMultipleExits(IZZ)I
.registers 4
@@ -137,15 +137,15 @@
# CHECK-DAG: <<Cst5:i\d+>> IntConstant 5
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
# CHECK-DAG: <<Cst9:i\d+>> IntConstant 9
-# CHECK-DAG: <<PhiX1:i\d+>> Phi [ <<ArgX>> <<Add5:i\d+>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgZ>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Mul9:i\d+>> Mul [ <<PhiX1>> <<Cst9>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<PhiX2:i\d+>> Phi [ <<Mul9>> <<PhiX1>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<Cst1>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add5>> Add [ <<PhiX2>> <<Cst5>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX1>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: Return [ <<PhiX2>> ] loop:none
+# CHECK-DAG: <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<ArgZ>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Mul9:i\d+>> Mul [<<PhiX1>>,<<Cst9>>] loop:<<HeaderY>>
+# CHECK-DAG: <<PhiX2:i\d+>> Phi [<<Mul9>>,<<PhiX1>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<Cst1>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add5>> Add [<<PhiX2>>,<<Cst5>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX1>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: Return [<<PhiX2>>] loop:none
# CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (after)
# CHECK-DAG: <<ArgX:i\d+>> ParameterValue
@@ -153,13 +153,13 @@
# CHECK-DAG: <<ArgZ:z\d+>> ParameterValue
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
# CHECK-DAG: <<Cst9:i\d+>> IntConstant 9
-# CHECK-DAG: <<PhiX1:i\d+>> Phi [ <<ArgX>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX1>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgZ>> ] loop:none
-# CHECK-DAG: <<Mul9:i\d+>> Mul [ <<PhiX1>> <<Cst9>> ] loop:none
-# CHECK-DAG: <<PhiX2:i\d+>> Phi [ <<Mul9>> <<PhiX1>> ] loop:none
-# CHECK-DAG: Return [ <<PhiX2>> ] loop:none
+# CHECK-DAG: <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX1>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<ArgZ>>] loop:none
+# CHECK-DAG: <<Mul9:i\d+>> Mul [<<PhiX1>>,<<Cst9>>] loop:none
+# CHECK-DAG: <<PhiX2:i\d+>> Phi [<<Mul9>>,<<PhiX1>>] loop:none
+# CHECK-DAG: Return [<<PhiX2>>] loop:none
.method public static testExitPredecessors(IZZ)I
.registers 4
@@ -205,19 +205,19 @@
# CHECK-DAG: <<Cst5:i\d+>> IntConstant 5
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
#
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<Add5:i\d+>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: <<PhiZ1:i\d+>> Phi [ <<ArgZ>> <<XorZ:i\d+>> <<PhiZ1>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: <<PhiZ1:i\d+>> Phi [<<ArgZ>>,<<XorZ:i\d+>>,<<PhiZ1>>] loop:<<HeaderY>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
#
# ### Inner loop ###
-# CHECK-DAG: <<PhiZ2:i\d+>> Phi [ <<PhiZ1>> <<XorZ>> ] loop:<<HeaderZ:B\d+>>
-# CHECK-DAG: <<XorZ>> Xor [ <<PhiZ2>> <<Cst1>> ] loop:<<HeaderZ>>
-# CHECK-DAG: <<CondZ:z\d+>> Equal [ <<XorZ>> <<Cst0>> ] loop:<<HeaderZ>>
-# CHECK-DAG: If [ <<CondZ>> ] loop:<<HeaderZ>>
+# CHECK-DAG: <<PhiZ2:i\d+>> Phi [<<PhiZ1>>,<<XorZ>>] loop:<<HeaderZ:B\d+>>
+# CHECK-DAG: <<XorZ>> Xor [<<PhiZ2>>,<<Cst1>>] loop:<<HeaderZ>>
+# CHECK-DAG: <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>] loop:<<HeaderZ>>
+# CHECK-DAG: If [<<CondZ>>] loop:<<HeaderZ>>
#
-# CHECK-DAG: <<Add5>> Add [ <<PhiX>> <<Cst5>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: <<Add5>> Add [<<PhiX>>,<<Cst5>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
+# CHECK-DAG: Return [<<PhiX>>] loop:none
# CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (after)
# CHECK-DAG: <<ArgX:i\d+>> ParameterValue
@@ -227,18 +227,17 @@
# CHECK-DAG: <<Cst1:i\d+>> IntConstant 1
# CHECK-DAG: <<Cst7:i\d+>> IntConstant 7
#
-# CHECK-DAG: <<PhiX:i\d+>> Phi [ <<ArgX>> <<Add7:i\d+>> ] loop:<<HeaderY:B\d+>>
-# CHECK-DAG: <<PhiZ1:i\d+>> Phi [ <<ArgZ>> <<PhiZ1>> ] loop:<<HeaderY>>
-# CHECK-DAG: If [ <<ArgY>> ] loop:<<HeaderY>>
-# CHECK-DAG: <<Add7>> Add [ <<PhiX>> <<Cst7>> ] loop:<<HeaderY>>
+# CHECK-DAG: <<PhiX:i\d+>> Phi [<<ArgX>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+# CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>>
+# CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>>
#
# ### Inner loop ###
-# CHECK-DAG: <<PhiZ2:i\d+>> Phi [ <<PhiZ1>> <<XorZ:i\d+>> ] loop:<<HeaderZ:B\d+>>
-# CHECK-DAG: <<XorZ>> Xor [ <<PhiZ2>> <<Cst1>> ] loop:<<HeaderZ>>
-# CHECK-DAG: <<CondZ:z\d+>> Equal [ <<XorZ>> <<Cst0>> ] loop:<<HeaderZ>>
-# CHECK-DAG: If [ <<CondZ>> ] loop:<<HeaderZ>>
+# CHECK-DAG: <<PhiZ:i\d+>> Phi [<<ArgZ>>,<<XorZ:i\d+>>] loop:<<HeaderZ:B\d+>>
+# CHECK-DAG: <<XorZ>> Xor [<<PhiZ>>,<<Cst1>>] loop:<<HeaderZ>>
+# CHECK-DAG: <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>] loop:<<HeaderZ>>
+# CHECK-DAG: If [<<CondZ>>] loop:<<HeaderZ>>
#
-# CHECK-DAG: Return [ <<PhiX>> ] loop:none
+# CHECK-DAG: Return [<<PhiX>>] loop:none
.method public static testInnerLoop(IZZ)I
.registers 4
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
new file mode 100644
index 0000000..1dc8452
--- /dev/null
+++ b/test/701-easy-div-rem/build
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# Stop if something fails.
+set -e
+
+# Write out the source file.
+mkdir src
+python ./genMain.py
+
+# Increase the file size limitation for classes.lst as the machine generated
+# source file contains a lot of methods and is quite large.
+ulimit -S 4096
+
+./default-build
diff --git a/test/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py
index 80eac34..75eee17 100644
--- a/test/701-easy-div-rem/genMain.py
+++ b/test/701-easy-div-rem/genMain.py
@@ -12,15 +12,28 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+upper_bound_int_pow2 = 31
+upper_bound_long_pow2 = 63
+upper_bound_constant = 100
all_tests = [
({'@INT@': 'int', '@SUFFIX@':''},
- [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(31)]),
- ('CheckDiv', 'idiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
- ('CheckRem', 'irem_by_pow2_', [2**i for i in range(31)])]),
+ [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+ ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+ ('CheckDiv', 'idiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+ ('CheckDiv', 'idiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+ ('CheckRem', 'irem_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+ ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+ ('CheckRem', 'irem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+ ('CheckRem', 'irem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]),
({'@INT@': 'long', '@SUFFIX@': 'l'},
- [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(63)]),
- ('CheckDiv', 'ldiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
- ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(63)])])
+ [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+ ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+ ('CheckDiv', 'ldiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+ ('CheckDiv', 'ldiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+ ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+ ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+ ('CheckRem', 'lrem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+ ('CheckRem', 'lrem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])])
]
def subst_vars(variables, text):
diff --git a/test/701-easy-div-rem/src/Main.java b/test/701-easy-div-rem/src/Main.java
deleted file mode 100644
index f995f61..0000000
--- a/test/701-easy-div-rem/src/Main.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2014 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 Main {
- public static int num_errors = 0;
-
- public static void reportError(String message) {
- if (num_errors == 10) {
- System.out.println("Omitting other error messages...");
- } else if (num_errors < 10) {
- System.out.println(message);
- }
- num_errors += 1;
- }
-
- public static void intCheckDiv(String desc, int result, int dividend, int divisor) {
- int correct_result = dividend / divisor;
- if (result != correct_result) {
- reportError(desc + "(" + dividend + ") == " + result +
- " should be " + correct_result);
- }
- }
- public static void intCheckRem(String desc, int result, int dividend, int divisor) {
- int correct_result = dividend % divisor;
- if (result != correct_result) {
- reportError(desc + "(" + dividend + ") == " + result +
- " should be " + correct_result);
- }
- }
- public static void longCheckDiv(String desc, long result, long dividend, long divisor) {
- long correct_result = dividend / divisor;
- if (result != correct_result) {
- reportError(desc + "(" + dividend + ") == " + result +
- " should be " + correct_result);
- }
- }
- public static void longCheckRem(String desc, long result, long dividend, long divisor) {
- long correct_result = dividend % divisor;
- if (result != correct_result) {
- reportError(desc + "(" + dividend + ") == " + result +
- " should be " + correct_result);
- }
- }
-
- public static int idiv_by_pow2_0(int x) {return x / 1;}
- public static int idiv_by_pow2_1(int x) {return x / 2;}
- public static int idiv_by_pow2_2(int x) {return x / 4;}
- public static int idiv_by_pow2_3(int x) {return x / 8;}
- public static int idiv_by_pow2_4(int x) {return x / 16;}
- public static int idiv_by_pow2_5(int x) {return x / 32;}
- public static int idiv_by_pow2_6(int x) {return x / 64;}
- public static int idiv_by_pow2_7(int x) {return x / 128;}
- public static int idiv_by_pow2_8(int x) {return x / 256;}
- public static int idiv_by_pow2_9(int x) {return x / 512;}
- public static int idiv_by_pow2_10(int x) {return x / 1024;}
- public static int idiv_by_pow2_11(int x) {return x / 2048;}
- public static int idiv_by_pow2_12(int x) {return x / 4096;}
- public static int idiv_by_pow2_13(int x) {return x / 8192;}
- public static int idiv_by_pow2_14(int x) {return x / 16384;}
- public static int idiv_by_pow2_15(int x) {return x / 32768;}
- public static int idiv_by_pow2_16(int x) {return x / 65536;}
- public static int idiv_by_pow2_17(int x) {return x / 131072;}
- public static int idiv_by_pow2_18(int x) {return x / 262144;}
- public static int idiv_by_pow2_19(int x) {return x / 524288;}
- public static int idiv_by_pow2_20(int x) {return x / 1048576;}
- public static int idiv_by_pow2_21(int x) {return x / 2097152;}
- public static int idiv_by_pow2_22(int x) {return x / 4194304;}
- public static int idiv_by_pow2_23(int x) {return x / 8388608;}
- public static int idiv_by_pow2_24(int x) {return x / 16777216;}
- public static int idiv_by_pow2_25(int x) {return x / 33554432;}
- public static int idiv_by_pow2_26(int x) {return x / 67108864;}
- public static int idiv_by_pow2_27(int x) {return x / 134217728;}
- public static int idiv_by_pow2_28(int x) {return x / 268435456;}
- public static int idiv_by_pow2_29(int x) {return x / 536870912;}
- public static int idiv_by_pow2_30(int x) {return x / 1073741824;}
- public static int idiv_by_small_0(int x) {return x / 3;}
- public static int idiv_by_small_1(int x) {return x / 5;}
- public static int idiv_by_small_2(int x) {return x / 6;}
- public static int idiv_by_small_3(int x) {return x / 7;}
- public static int idiv_by_small_4(int x) {return x / 9;}
- public static int idiv_by_small_5(int x) {return x / 10;}
- public static int idiv_by_small_6(int x) {return x / 11;}
- public static int idiv_by_small_7(int x) {return x / 12;}
- public static int idiv_by_small_8(int x) {return x / 13;}
- public static int idiv_by_small_9(int x) {return x / 14;}
- public static int idiv_by_small_10(int x) {return x / 15;}
- public static int irem_by_pow2_0(int x) {return x % 1;}
- public static int irem_by_pow2_1(int x) {return x % 2;}
- public static int irem_by_pow2_2(int x) {return x % 4;}
- public static int irem_by_pow2_3(int x) {return x % 8;}
- public static int irem_by_pow2_4(int x) {return x % 16;}
- public static int irem_by_pow2_5(int x) {return x % 32;}
- public static int irem_by_pow2_6(int x) {return x % 64;}
- public static int irem_by_pow2_7(int x) {return x % 128;}
- public static int irem_by_pow2_8(int x) {return x % 256;}
- public static int irem_by_pow2_9(int x) {return x % 512;}
- public static int irem_by_pow2_10(int x) {return x % 1024;}
- public static int irem_by_pow2_11(int x) {return x % 2048;}
- public static int irem_by_pow2_12(int x) {return x % 4096;}
- public static int irem_by_pow2_13(int x) {return x % 8192;}
- public static int irem_by_pow2_14(int x) {return x % 16384;}
- public static int irem_by_pow2_15(int x) {return x % 32768;}
- public static int irem_by_pow2_16(int x) {return x % 65536;}
- public static int irem_by_pow2_17(int x) {return x % 131072;}
- public static int irem_by_pow2_18(int x) {return x % 262144;}
- public static int irem_by_pow2_19(int x) {return x % 524288;}
- public static int irem_by_pow2_20(int x) {return x % 1048576;}
- public static int irem_by_pow2_21(int x) {return x % 2097152;}
- public static int irem_by_pow2_22(int x) {return x % 4194304;}
- public static int irem_by_pow2_23(int x) {return x % 8388608;}
- public static int irem_by_pow2_24(int x) {return x % 16777216;}
- public static int irem_by_pow2_25(int x) {return x % 33554432;}
- public static int irem_by_pow2_26(int x) {return x % 67108864;}
- public static int irem_by_pow2_27(int x) {return x % 134217728;}
- public static int irem_by_pow2_28(int x) {return x % 268435456;}
- public static int irem_by_pow2_29(int x) {return x % 536870912;}
- public static int irem_by_pow2_30(int x) {return x % 1073741824;}
- public static long ldiv_by_pow2_0(long x) {return x / 1l;}
- public static long ldiv_by_pow2_1(long x) {return x / 2l;}
- public static long ldiv_by_pow2_2(long x) {return x / 4l;}
- public static long ldiv_by_pow2_3(long x) {return x / 8l;}
- public static long ldiv_by_pow2_4(long x) {return x / 16l;}
- public static long ldiv_by_pow2_5(long x) {return x / 32l;}
- public static long ldiv_by_pow2_6(long x) {return x / 64l;}
- public static long ldiv_by_pow2_7(long x) {return x / 128l;}
- public static long ldiv_by_pow2_8(long x) {return x / 256l;}
- public static long ldiv_by_pow2_9(long x) {return x / 512l;}
- public static long ldiv_by_pow2_10(long x) {return x / 1024l;}
- public static long ldiv_by_pow2_11(long x) {return x / 2048l;}
- public static long ldiv_by_pow2_12(long x) {return x / 4096l;}
- public static long ldiv_by_pow2_13(long x) {return x / 8192l;}
- public static long ldiv_by_pow2_14(long x) {return x / 16384l;}
- public static long ldiv_by_pow2_15(long x) {return x / 32768l;}
- public static long ldiv_by_pow2_16(long x) {return x / 65536l;}
- public static long ldiv_by_pow2_17(long x) {return x / 131072l;}
- public static long ldiv_by_pow2_18(long x) {return x / 262144l;}
- public static long ldiv_by_pow2_19(long x) {return x / 524288l;}
- public static long ldiv_by_pow2_20(long x) {return x / 1048576l;}
- public static long ldiv_by_pow2_21(long x) {return x / 2097152l;}
- public static long ldiv_by_pow2_22(long x) {return x / 4194304l;}
- public static long ldiv_by_pow2_23(long x) {return x / 8388608l;}
- public static long ldiv_by_pow2_24(long x) {return x / 16777216l;}
- public static long ldiv_by_pow2_25(long x) {return x / 33554432l;}
- public static long ldiv_by_pow2_26(long x) {return x / 67108864l;}
- public static long ldiv_by_pow2_27(long x) {return x / 134217728l;}
- public static long ldiv_by_pow2_28(long x) {return x / 268435456l;}
- public static long ldiv_by_pow2_29(long x) {return x / 536870912l;}
- public static long ldiv_by_pow2_30(long x) {return x / 1073741824l;}
- public static long ldiv_by_pow2_31(long x) {return x / 2147483648l;}
- public static long ldiv_by_pow2_32(long x) {return x / 4294967296l;}
- public static long ldiv_by_pow2_33(long x) {return x / 8589934592l;}
- public static long ldiv_by_pow2_34(long x) {return x / 17179869184l;}
- public static long ldiv_by_pow2_35(long x) {return x / 34359738368l;}
- public static long ldiv_by_pow2_36(long x) {return x / 68719476736l;}
- public static long ldiv_by_pow2_37(long x) {return x / 137438953472l;}
- public static long ldiv_by_pow2_38(long x) {return x / 274877906944l;}
- public static long ldiv_by_pow2_39(long x) {return x / 549755813888l;}
- public static long ldiv_by_pow2_40(long x) {return x / 1099511627776l;}
- public static long ldiv_by_pow2_41(long x) {return x / 2199023255552l;}
- public static long ldiv_by_pow2_42(long x) {return x / 4398046511104l;}
- public static long ldiv_by_pow2_43(long x) {return x / 8796093022208l;}
- public static long ldiv_by_pow2_44(long x) {return x / 17592186044416l;}
- public static long ldiv_by_pow2_45(long x) {return x / 35184372088832l;}
- public static long ldiv_by_pow2_46(long x) {return x / 70368744177664l;}
- public static long ldiv_by_pow2_47(long x) {return x / 140737488355328l;}
- public static long ldiv_by_pow2_48(long x) {return x / 281474976710656l;}
- public static long ldiv_by_pow2_49(long x) {return x / 562949953421312l;}
- public static long ldiv_by_pow2_50(long x) {return x / 1125899906842624l;}
- public static long ldiv_by_pow2_51(long x) {return x / 2251799813685248l;}
- public static long ldiv_by_pow2_52(long x) {return x / 4503599627370496l;}
- public static long ldiv_by_pow2_53(long x) {return x / 9007199254740992l;}
- public static long ldiv_by_pow2_54(long x) {return x / 18014398509481984l;}
- public static long ldiv_by_pow2_55(long x) {return x / 36028797018963968l;}
- public static long ldiv_by_pow2_56(long x) {return x / 72057594037927936l;}
- public static long ldiv_by_pow2_57(long x) {return x / 144115188075855872l;}
- public static long ldiv_by_pow2_58(long x) {return x / 288230376151711744l;}
- public static long ldiv_by_pow2_59(long x) {return x / 576460752303423488l;}
- public static long ldiv_by_pow2_60(long x) {return x / 1152921504606846976l;}
- public static long ldiv_by_pow2_61(long x) {return x / 2305843009213693952l;}
- public static long ldiv_by_pow2_62(long x) {return x / 4611686018427387904l;}
- public static long ldiv_by_small_0(long x) {return x / 3l;}
- public static long ldiv_by_small_1(long x) {return x / 5l;}
- public static long ldiv_by_small_2(long x) {return x / 6l;}
- public static long ldiv_by_small_3(long x) {return x / 7l;}
- public static long ldiv_by_small_4(long x) {return x / 9l;}
- public static long ldiv_by_small_5(long x) {return x / 10l;}
- public static long ldiv_by_small_6(long x) {return x / 11l;}
- public static long ldiv_by_small_7(long x) {return x / 12l;}
- public static long ldiv_by_small_8(long x) {return x / 13l;}
- public static long ldiv_by_small_9(long x) {return x / 14l;}
- public static long ldiv_by_small_10(long x) {return x / 15l;}
- public static long lrem_by_pow2_0(long x) {return x % 1l;}
- public static long lrem_by_pow2_1(long x) {return x % 2l;}
- public static long lrem_by_pow2_2(long x) {return x % 4l;}
- public static long lrem_by_pow2_3(long x) {return x % 8l;}
- public static long lrem_by_pow2_4(long x) {return x % 16l;}
- public static long lrem_by_pow2_5(long x) {return x % 32l;}
- public static long lrem_by_pow2_6(long x) {return x % 64l;}
- public static long lrem_by_pow2_7(long x) {return x % 128l;}
- public static long lrem_by_pow2_8(long x) {return x % 256l;}
- public static long lrem_by_pow2_9(long x) {return x % 512l;}
- public static long lrem_by_pow2_10(long x) {return x % 1024l;}
- public static long lrem_by_pow2_11(long x) {return x % 2048l;}
- public static long lrem_by_pow2_12(long x) {return x % 4096l;}
- public static long lrem_by_pow2_13(long x) {return x % 8192l;}
- public static long lrem_by_pow2_14(long x) {return x % 16384l;}
- public static long lrem_by_pow2_15(long x) {return x % 32768l;}
- public static long lrem_by_pow2_16(long x) {return x % 65536l;}
- public static long lrem_by_pow2_17(long x) {return x % 131072l;}
- public static long lrem_by_pow2_18(long x) {return x % 262144l;}
- public static long lrem_by_pow2_19(long x) {return x % 524288l;}
- public static long lrem_by_pow2_20(long x) {return x % 1048576l;}
- public static long lrem_by_pow2_21(long x) {return x % 2097152l;}
- public static long lrem_by_pow2_22(long x) {return x % 4194304l;}
- public static long lrem_by_pow2_23(long x) {return x % 8388608l;}
- public static long lrem_by_pow2_24(long x) {return x % 16777216l;}
- public static long lrem_by_pow2_25(long x) {return x % 33554432l;}
- public static long lrem_by_pow2_26(long x) {return x % 67108864l;}
- public static long lrem_by_pow2_27(long x) {return x % 134217728l;}
- public static long lrem_by_pow2_28(long x) {return x % 268435456l;}
- public static long lrem_by_pow2_29(long x) {return x % 536870912l;}
- public static long lrem_by_pow2_30(long x) {return x % 1073741824l;}
- public static long lrem_by_pow2_31(long x) {return x % 2147483648l;}
- public static long lrem_by_pow2_32(long x) {return x % 4294967296l;}
- public static long lrem_by_pow2_33(long x) {return x % 8589934592l;}
- public static long lrem_by_pow2_34(long x) {return x % 17179869184l;}
- public static long lrem_by_pow2_35(long x) {return x % 34359738368l;}
- public static long lrem_by_pow2_36(long x) {return x % 68719476736l;}
- public static long lrem_by_pow2_37(long x) {return x % 137438953472l;}
- public static long lrem_by_pow2_38(long x) {return x % 274877906944l;}
- public static long lrem_by_pow2_39(long x) {return x % 549755813888l;}
- public static long lrem_by_pow2_40(long x) {return x % 1099511627776l;}
- public static long lrem_by_pow2_41(long x) {return x % 2199023255552l;}
- public static long lrem_by_pow2_42(long x) {return x % 4398046511104l;}
- public static long lrem_by_pow2_43(long x) {return x % 8796093022208l;}
- public static long lrem_by_pow2_44(long x) {return x % 17592186044416l;}
- public static long lrem_by_pow2_45(long x) {return x % 35184372088832l;}
- public static long lrem_by_pow2_46(long x) {return x % 70368744177664l;}
- public static long lrem_by_pow2_47(long x) {return x % 140737488355328l;}
- public static long lrem_by_pow2_48(long x) {return x % 281474976710656l;}
- public static long lrem_by_pow2_49(long x) {return x % 562949953421312l;}
- public static long lrem_by_pow2_50(long x) {return x % 1125899906842624l;}
- public static long lrem_by_pow2_51(long x) {return x % 2251799813685248l;}
- public static long lrem_by_pow2_52(long x) {return x % 4503599627370496l;}
- public static long lrem_by_pow2_53(long x) {return x % 9007199254740992l;}
- public static long lrem_by_pow2_54(long x) {return x % 18014398509481984l;}
- public static long lrem_by_pow2_55(long x) {return x % 36028797018963968l;}
- public static long lrem_by_pow2_56(long x) {return x % 72057594037927936l;}
- public static long lrem_by_pow2_57(long x) {return x % 144115188075855872l;}
- public static long lrem_by_pow2_58(long x) {return x % 288230376151711744l;}
- public static long lrem_by_pow2_59(long x) {return x % 576460752303423488l;}
- public static long lrem_by_pow2_60(long x) {return x % 1152921504606846976l;}
- public static long lrem_by_pow2_61(long x) {return x % 2305843009213693952l;}
- public static long lrem_by_pow2_62(long x) {return x % 4611686018427387904l;}
-
- public static void intCheckAll(int x) {
- intCheckDiv("idiv_by_pow2_0", idiv_by_pow2_0(x), x, 1);
- intCheckDiv("idiv_by_pow2_1", idiv_by_pow2_1(x), x, 2);
- intCheckDiv("idiv_by_pow2_2", idiv_by_pow2_2(x), x, 4);
- intCheckDiv("idiv_by_pow2_3", idiv_by_pow2_3(x), x, 8);
- intCheckDiv("idiv_by_pow2_4", idiv_by_pow2_4(x), x, 16);
- intCheckDiv("idiv_by_pow2_5", idiv_by_pow2_5(x), x, 32);
- intCheckDiv("idiv_by_pow2_6", idiv_by_pow2_6(x), x, 64);
- intCheckDiv("idiv_by_pow2_7", idiv_by_pow2_7(x), x, 128);
- intCheckDiv("idiv_by_pow2_8", idiv_by_pow2_8(x), x, 256);
- intCheckDiv("idiv_by_pow2_9", idiv_by_pow2_9(x), x, 512);
- intCheckDiv("idiv_by_pow2_10", idiv_by_pow2_10(x), x, 1024);
- intCheckDiv("idiv_by_pow2_11", idiv_by_pow2_11(x), x, 2048);
- intCheckDiv("idiv_by_pow2_12", idiv_by_pow2_12(x), x, 4096);
- intCheckDiv("idiv_by_pow2_13", idiv_by_pow2_13(x), x, 8192);
- intCheckDiv("idiv_by_pow2_14", idiv_by_pow2_14(x), x, 16384);
- intCheckDiv("idiv_by_pow2_15", idiv_by_pow2_15(x), x, 32768);
- intCheckDiv("idiv_by_pow2_16", idiv_by_pow2_16(x), x, 65536);
- intCheckDiv("idiv_by_pow2_17", idiv_by_pow2_17(x), x, 131072);
- intCheckDiv("idiv_by_pow2_18", idiv_by_pow2_18(x), x, 262144);
- intCheckDiv("idiv_by_pow2_19", idiv_by_pow2_19(x), x, 524288);
- intCheckDiv("idiv_by_pow2_20", idiv_by_pow2_20(x), x, 1048576);
- intCheckDiv("idiv_by_pow2_21", idiv_by_pow2_21(x), x, 2097152);
- intCheckDiv("idiv_by_pow2_22", idiv_by_pow2_22(x), x, 4194304);
- intCheckDiv("idiv_by_pow2_23", idiv_by_pow2_23(x), x, 8388608);
- intCheckDiv("idiv_by_pow2_24", idiv_by_pow2_24(x), x, 16777216);
- intCheckDiv("idiv_by_pow2_25", idiv_by_pow2_25(x), x, 33554432);
- intCheckDiv("idiv_by_pow2_26", idiv_by_pow2_26(x), x, 67108864);
- intCheckDiv("idiv_by_pow2_27", idiv_by_pow2_27(x), x, 134217728);
- intCheckDiv("idiv_by_pow2_28", idiv_by_pow2_28(x), x, 268435456);
- intCheckDiv("idiv_by_pow2_29", idiv_by_pow2_29(x), x, 536870912);
- intCheckDiv("idiv_by_pow2_30", idiv_by_pow2_30(x), x, 1073741824);
- intCheckDiv("idiv_by_small_0", idiv_by_small_0(x), x, 3);
- intCheckDiv("idiv_by_small_1", idiv_by_small_1(x), x, 5);
- intCheckDiv("idiv_by_small_2", idiv_by_small_2(x), x, 6);
- intCheckDiv("idiv_by_small_3", idiv_by_small_3(x), x, 7);
- intCheckDiv("idiv_by_small_4", idiv_by_small_4(x), x, 9);
- intCheckDiv("idiv_by_small_5", idiv_by_small_5(x), x, 10);
- intCheckDiv("idiv_by_small_6", idiv_by_small_6(x), x, 11);
- intCheckDiv("idiv_by_small_7", idiv_by_small_7(x), x, 12);
- intCheckDiv("idiv_by_small_8", idiv_by_small_8(x), x, 13);
- intCheckDiv("idiv_by_small_9", idiv_by_small_9(x), x, 14);
- intCheckDiv("idiv_by_small_10", idiv_by_small_10(x), x, 15);
- intCheckRem("irem_by_pow2_0", irem_by_pow2_0(x), x, 1);
- intCheckRem("irem_by_pow2_1", irem_by_pow2_1(x), x, 2);
- intCheckRem("irem_by_pow2_2", irem_by_pow2_2(x), x, 4);
- intCheckRem("irem_by_pow2_3", irem_by_pow2_3(x), x, 8);
- intCheckRem("irem_by_pow2_4", irem_by_pow2_4(x), x, 16);
- intCheckRem("irem_by_pow2_5", irem_by_pow2_5(x), x, 32);
- intCheckRem("irem_by_pow2_6", irem_by_pow2_6(x), x, 64);
- intCheckRem("irem_by_pow2_7", irem_by_pow2_7(x), x, 128);
- intCheckRem("irem_by_pow2_8", irem_by_pow2_8(x), x, 256);
- intCheckRem("irem_by_pow2_9", irem_by_pow2_9(x), x, 512);
- intCheckRem("irem_by_pow2_10", irem_by_pow2_10(x), x, 1024);
- intCheckRem("irem_by_pow2_11", irem_by_pow2_11(x), x, 2048);
- intCheckRem("irem_by_pow2_12", irem_by_pow2_12(x), x, 4096);
- intCheckRem("irem_by_pow2_13", irem_by_pow2_13(x), x, 8192);
- intCheckRem("irem_by_pow2_14", irem_by_pow2_14(x), x, 16384);
- intCheckRem("irem_by_pow2_15", irem_by_pow2_15(x), x, 32768);
- intCheckRem("irem_by_pow2_16", irem_by_pow2_16(x), x, 65536);
- intCheckRem("irem_by_pow2_17", irem_by_pow2_17(x), x, 131072);
- intCheckRem("irem_by_pow2_18", irem_by_pow2_18(x), x, 262144);
- intCheckRem("irem_by_pow2_19", irem_by_pow2_19(x), x, 524288);
- intCheckRem("irem_by_pow2_20", irem_by_pow2_20(x), x, 1048576);
- intCheckRem("irem_by_pow2_21", irem_by_pow2_21(x), x, 2097152);
- intCheckRem("irem_by_pow2_22", irem_by_pow2_22(x), x, 4194304);
- intCheckRem("irem_by_pow2_23", irem_by_pow2_23(x), x, 8388608);
- intCheckRem("irem_by_pow2_24", irem_by_pow2_24(x), x, 16777216);
- intCheckRem("irem_by_pow2_25", irem_by_pow2_25(x), x, 33554432);
- intCheckRem("irem_by_pow2_26", irem_by_pow2_26(x), x, 67108864);
- intCheckRem("irem_by_pow2_27", irem_by_pow2_27(x), x, 134217728);
- intCheckRem("irem_by_pow2_28", irem_by_pow2_28(x), x, 268435456);
- intCheckRem("irem_by_pow2_29", irem_by_pow2_29(x), x, 536870912);
- intCheckRem("irem_by_pow2_30", irem_by_pow2_30(x), x, 1073741824);
- }
-
- public static void longCheckAll(long x) {
- longCheckDiv("ldiv_by_pow2_0", ldiv_by_pow2_0(x), x, 1l);
- longCheckDiv("ldiv_by_pow2_1", ldiv_by_pow2_1(x), x, 2l);
- longCheckDiv("ldiv_by_pow2_2", ldiv_by_pow2_2(x), x, 4l);
- longCheckDiv("ldiv_by_pow2_3", ldiv_by_pow2_3(x), x, 8l);
- longCheckDiv("ldiv_by_pow2_4", ldiv_by_pow2_4(x), x, 16l);
- longCheckDiv("ldiv_by_pow2_5", ldiv_by_pow2_5(x), x, 32l);
- longCheckDiv("ldiv_by_pow2_6", ldiv_by_pow2_6(x), x, 64l);
- longCheckDiv("ldiv_by_pow2_7", ldiv_by_pow2_7(x), x, 128l);
- longCheckDiv("ldiv_by_pow2_8", ldiv_by_pow2_8(x), x, 256l);
- longCheckDiv("ldiv_by_pow2_9", ldiv_by_pow2_9(x), x, 512l);
- longCheckDiv("ldiv_by_pow2_10", ldiv_by_pow2_10(x), x, 1024l);
- longCheckDiv("ldiv_by_pow2_11", ldiv_by_pow2_11(x), x, 2048l);
- longCheckDiv("ldiv_by_pow2_12", ldiv_by_pow2_12(x), x, 4096l);
- longCheckDiv("ldiv_by_pow2_13", ldiv_by_pow2_13(x), x, 8192l);
- longCheckDiv("ldiv_by_pow2_14", ldiv_by_pow2_14(x), x, 16384l);
- longCheckDiv("ldiv_by_pow2_15", ldiv_by_pow2_15(x), x, 32768l);
- longCheckDiv("ldiv_by_pow2_16", ldiv_by_pow2_16(x), x, 65536l);
- longCheckDiv("ldiv_by_pow2_17", ldiv_by_pow2_17(x), x, 131072l);
- longCheckDiv("ldiv_by_pow2_18", ldiv_by_pow2_18(x), x, 262144l);
- longCheckDiv("ldiv_by_pow2_19", ldiv_by_pow2_19(x), x, 524288l);
- longCheckDiv("ldiv_by_pow2_20", ldiv_by_pow2_20(x), x, 1048576l);
- longCheckDiv("ldiv_by_pow2_21", ldiv_by_pow2_21(x), x, 2097152l);
- longCheckDiv("ldiv_by_pow2_22", ldiv_by_pow2_22(x), x, 4194304l);
- longCheckDiv("ldiv_by_pow2_23", ldiv_by_pow2_23(x), x, 8388608l);
- longCheckDiv("ldiv_by_pow2_24", ldiv_by_pow2_24(x), x, 16777216l);
- longCheckDiv("ldiv_by_pow2_25", ldiv_by_pow2_25(x), x, 33554432l);
- longCheckDiv("ldiv_by_pow2_26", ldiv_by_pow2_26(x), x, 67108864l);
- longCheckDiv("ldiv_by_pow2_27", ldiv_by_pow2_27(x), x, 134217728l);
- longCheckDiv("ldiv_by_pow2_28", ldiv_by_pow2_28(x), x, 268435456l);
- longCheckDiv("ldiv_by_pow2_29", ldiv_by_pow2_29(x), x, 536870912l);
- longCheckDiv("ldiv_by_pow2_30", ldiv_by_pow2_30(x), x, 1073741824l);
- longCheckDiv("ldiv_by_pow2_31", ldiv_by_pow2_31(x), x, 2147483648l);
- longCheckDiv("ldiv_by_pow2_32", ldiv_by_pow2_32(x), x, 4294967296l);
- longCheckDiv("ldiv_by_pow2_33", ldiv_by_pow2_33(x), x, 8589934592l);
- longCheckDiv("ldiv_by_pow2_34", ldiv_by_pow2_34(x), x, 17179869184l);
- longCheckDiv("ldiv_by_pow2_35", ldiv_by_pow2_35(x), x, 34359738368l);
- longCheckDiv("ldiv_by_pow2_36", ldiv_by_pow2_36(x), x, 68719476736l);
- longCheckDiv("ldiv_by_pow2_37", ldiv_by_pow2_37(x), x, 137438953472l);
- longCheckDiv("ldiv_by_pow2_38", ldiv_by_pow2_38(x), x, 274877906944l);
- longCheckDiv("ldiv_by_pow2_39", ldiv_by_pow2_39(x), x, 549755813888l);
- longCheckDiv("ldiv_by_pow2_40", ldiv_by_pow2_40(x), x, 1099511627776l);
- longCheckDiv("ldiv_by_pow2_41", ldiv_by_pow2_41(x), x, 2199023255552l);
- longCheckDiv("ldiv_by_pow2_42", ldiv_by_pow2_42(x), x, 4398046511104l);
- longCheckDiv("ldiv_by_pow2_43", ldiv_by_pow2_43(x), x, 8796093022208l);
- longCheckDiv("ldiv_by_pow2_44", ldiv_by_pow2_44(x), x, 17592186044416l);
- longCheckDiv("ldiv_by_pow2_45", ldiv_by_pow2_45(x), x, 35184372088832l);
- longCheckDiv("ldiv_by_pow2_46", ldiv_by_pow2_46(x), x, 70368744177664l);
- longCheckDiv("ldiv_by_pow2_47", ldiv_by_pow2_47(x), x, 140737488355328l);
- longCheckDiv("ldiv_by_pow2_48", ldiv_by_pow2_48(x), x, 281474976710656l);
- longCheckDiv("ldiv_by_pow2_49", ldiv_by_pow2_49(x), x, 562949953421312l);
- longCheckDiv("ldiv_by_pow2_50", ldiv_by_pow2_50(x), x, 1125899906842624l);
- longCheckDiv("ldiv_by_pow2_51", ldiv_by_pow2_51(x), x, 2251799813685248l);
- longCheckDiv("ldiv_by_pow2_52", ldiv_by_pow2_52(x), x, 4503599627370496l);
- longCheckDiv("ldiv_by_pow2_53", ldiv_by_pow2_53(x), x, 9007199254740992l);
- longCheckDiv("ldiv_by_pow2_54", ldiv_by_pow2_54(x), x, 18014398509481984l);
- longCheckDiv("ldiv_by_pow2_55", ldiv_by_pow2_55(x), x, 36028797018963968l);
- longCheckDiv("ldiv_by_pow2_56", ldiv_by_pow2_56(x), x, 72057594037927936l);
- longCheckDiv("ldiv_by_pow2_57", ldiv_by_pow2_57(x), x, 144115188075855872l);
- longCheckDiv("ldiv_by_pow2_58", ldiv_by_pow2_58(x), x, 288230376151711744l);
- longCheckDiv("ldiv_by_pow2_59", ldiv_by_pow2_59(x), x, 576460752303423488l);
- longCheckDiv("ldiv_by_pow2_60", ldiv_by_pow2_60(x), x, 1152921504606846976l);
- longCheckDiv("ldiv_by_pow2_61", ldiv_by_pow2_61(x), x, 2305843009213693952l);
- longCheckDiv("ldiv_by_pow2_62", ldiv_by_pow2_62(x), x, 4611686018427387904l);
- longCheckDiv("ldiv_by_small_0", ldiv_by_small_0(x), x, 3l);
- longCheckDiv("ldiv_by_small_1", ldiv_by_small_1(x), x, 5l);
- longCheckDiv("ldiv_by_small_2", ldiv_by_small_2(x), x, 6l);
- longCheckDiv("ldiv_by_small_3", ldiv_by_small_3(x), x, 7l);
- longCheckDiv("ldiv_by_small_4", ldiv_by_small_4(x), x, 9l);
- longCheckDiv("ldiv_by_small_5", ldiv_by_small_5(x), x, 10l);
- longCheckDiv("ldiv_by_small_6", ldiv_by_small_6(x), x, 11l);
- longCheckDiv("ldiv_by_small_7", ldiv_by_small_7(x), x, 12l);
- longCheckDiv("ldiv_by_small_8", ldiv_by_small_8(x), x, 13l);
- longCheckDiv("ldiv_by_small_9", ldiv_by_small_9(x), x, 14l);
- longCheckDiv("ldiv_by_small_10", ldiv_by_small_10(x), x, 15l);
- longCheckRem("lrem_by_pow2_0", lrem_by_pow2_0(x), x, 1l);
- longCheckRem("lrem_by_pow2_1", lrem_by_pow2_1(x), x, 2l);
- longCheckRem("lrem_by_pow2_2", lrem_by_pow2_2(x), x, 4l);
- longCheckRem("lrem_by_pow2_3", lrem_by_pow2_3(x), x, 8l);
- longCheckRem("lrem_by_pow2_4", lrem_by_pow2_4(x), x, 16l);
- longCheckRem("lrem_by_pow2_5", lrem_by_pow2_5(x), x, 32l);
- longCheckRem("lrem_by_pow2_6", lrem_by_pow2_6(x), x, 64l);
- longCheckRem("lrem_by_pow2_7", lrem_by_pow2_7(x), x, 128l);
- longCheckRem("lrem_by_pow2_8", lrem_by_pow2_8(x), x, 256l);
- longCheckRem("lrem_by_pow2_9", lrem_by_pow2_9(x), x, 512l);
- longCheckRem("lrem_by_pow2_10", lrem_by_pow2_10(x), x, 1024l);
- longCheckRem("lrem_by_pow2_11", lrem_by_pow2_11(x), x, 2048l);
- longCheckRem("lrem_by_pow2_12", lrem_by_pow2_12(x), x, 4096l);
- longCheckRem("lrem_by_pow2_13", lrem_by_pow2_13(x), x, 8192l);
- longCheckRem("lrem_by_pow2_14", lrem_by_pow2_14(x), x, 16384l);
- longCheckRem("lrem_by_pow2_15", lrem_by_pow2_15(x), x, 32768l);
- longCheckRem("lrem_by_pow2_16", lrem_by_pow2_16(x), x, 65536l);
- longCheckRem("lrem_by_pow2_17", lrem_by_pow2_17(x), x, 131072l);
- longCheckRem("lrem_by_pow2_18", lrem_by_pow2_18(x), x, 262144l);
- longCheckRem("lrem_by_pow2_19", lrem_by_pow2_19(x), x, 524288l);
- longCheckRem("lrem_by_pow2_20", lrem_by_pow2_20(x), x, 1048576l);
- longCheckRem("lrem_by_pow2_21", lrem_by_pow2_21(x), x, 2097152l);
- longCheckRem("lrem_by_pow2_22", lrem_by_pow2_22(x), x, 4194304l);
- longCheckRem("lrem_by_pow2_23", lrem_by_pow2_23(x), x, 8388608l);
- longCheckRem("lrem_by_pow2_24", lrem_by_pow2_24(x), x, 16777216l);
- longCheckRem("lrem_by_pow2_25", lrem_by_pow2_25(x), x, 33554432l);
- longCheckRem("lrem_by_pow2_26", lrem_by_pow2_26(x), x, 67108864l);
- longCheckRem("lrem_by_pow2_27", lrem_by_pow2_27(x), x, 134217728l);
- longCheckRem("lrem_by_pow2_28", lrem_by_pow2_28(x), x, 268435456l);
- longCheckRem("lrem_by_pow2_29", lrem_by_pow2_29(x), x, 536870912l);
- longCheckRem("lrem_by_pow2_30", lrem_by_pow2_30(x), x, 1073741824l);
- longCheckRem("lrem_by_pow2_31", lrem_by_pow2_31(x), x, 2147483648l);
- longCheckRem("lrem_by_pow2_32", lrem_by_pow2_32(x), x, 4294967296l);
- longCheckRem("lrem_by_pow2_33", lrem_by_pow2_33(x), x, 8589934592l);
- longCheckRem("lrem_by_pow2_34", lrem_by_pow2_34(x), x, 17179869184l);
- longCheckRem("lrem_by_pow2_35", lrem_by_pow2_35(x), x, 34359738368l);
- longCheckRem("lrem_by_pow2_36", lrem_by_pow2_36(x), x, 68719476736l);
- longCheckRem("lrem_by_pow2_37", lrem_by_pow2_37(x), x, 137438953472l);
- longCheckRem("lrem_by_pow2_38", lrem_by_pow2_38(x), x, 274877906944l);
- longCheckRem("lrem_by_pow2_39", lrem_by_pow2_39(x), x, 549755813888l);
- longCheckRem("lrem_by_pow2_40", lrem_by_pow2_40(x), x, 1099511627776l);
- longCheckRem("lrem_by_pow2_41", lrem_by_pow2_41(x), x, 2199023255552l);
- longCheckRem("lrem_by_pow2_42", lrem_by_pow2_42(x), x, 4398046511104l);
- longCheckRem("lrem_by_pow2_43", lrem_by_pow2_43(x), x, 8796093022208l);
- longCheckRem("lrem_by_pow2_44", lrem_by_pow2_44(x), x, 17592186044416l);
- longCheckRem("lrem_by_pow2_45", lrem_by_pow2_45(x), x, 35184372088832l);
- longCheckRem("lrem_by_pow2_46", lrem_by_pow2_46(x), x, 70368744177664l);
- longCheckRem("lrem_by_pow2_47", lrem_by_pow2_47(x), x, 140737488355328l);
- longCheckRem("lrem_by_pow2_48", lrem_by_pow2_48(x), x, 281474976710656l);
- longCheckRem("lrem_by_pow2_49", lrem_by_pow2_49(x), x, 562949953421312l);
- longCheckRem("lrem_by_pow2_50", lrem_by_pow2_50(x), x, 1125899906842624l);
- longCheckRem("lrem_by_pow2_51", lrem_by_pow2_51(x), x, 2251799813685248l);
- longCheckRem("lrem_by_pow2_52", lrem_by_pow2_52(x), x, 4503599627370496l);
- longCheckRem("lrem_by_pow2_53", lrem_by_pow2_53(x), x, 9007199254740992l);
- longCheckRem("lrem_by_pow2_54", lrem_by_pow2_54(x), x, 18014398509481984l);
- longCheckRem("lrem_by_pow2_55", lrem_by_pow2_55(x), x, 36028797018963968l);
- longCheckRem("lrem_by_pow2_56", lrem_by_pow2_56(x), x, 72057594037927936l);
- longCheckRem("lrem_by_pow2_57", lrem_by_pow2_57(x), x, 144115188075855872l);
- longCheckRem("lrem_by_pow2_58", lrem_by_pow2_58(x), x, 288230376151711744l);
- longCheckRem("lrem_by_pow2_59", lrem_by_pow2_59(x), x, 576460752303423488l);
- longCheckRem("lrem_by_pow2_60", lrem_by_pow2_60(x), x, 1152921504606846976l);
- longCheckRem("lrem_by_pow2_61", lrem_by_pow2_61(x), x, 2305843009213693952l);
- longCheckRem("lrem_by_pow2_62", lrem_by_pow2_62(x), x, 4611686018427387904l);
- }
-
- public static void main(String[] args) {
- int i;
- long l;
-
- System.out.println("Begin");
-
- System.out.println("Int: checking some equally spaced dividends...");
- for (i = -1000; i < 1000; i += 300) {
- intCheckAll(i);
- intCheckAll(-i);
- }
-
- System.out.println("Int: checking small dividends...");
- for (i = 1; i < 100; i += 1) {
- intCheckAll(i);
- intCheckAll(-i);
- }
-
- System.out.println("Int: checking big dividends...");
- for (i = 0; i < 100; i += 1) {
- intCheckAll(Integer.MAX_VALUE - i);
- intCheckAll(Integer.MIN_VALUE + i);
- }
-
- System.out.println("Long: checking some equally spaced dividends...");
- for (l = 0l; l < 1000000000000l; l += 300000000000l) {
- longCheckAll(l);
- longCheckAll(-l);
- }
-
- System.out.println("Long: checking small dividends...");
- for (l = 1l; l < 100l; l += 1l) {
- longCheckAll(l);
- longCheckAll(-l);
- }
-
- System.out.println("Long: checking big dividends...");
- for (l = 0l; l < 100l; l += 1l) {
- longCheckAll(Long.MAX_VALUE - l);
- longCheckAll(Long.MIN_VALUE + l);
- }
-
- System.out.println("End");
- }
-}
diff --git a/test/702-LargeBranchOffset/build b/test/702-LargeBranchOffset/build
index eacf730..20030fa 100644
--- a/test/702-LargeBranchOffset/build
+++ b/test/702-LargeBranchOffset/build
@@ -17,11 +17,7 @@
# Stop if something fails.
set -e
-# Write out a bunch of source files.
+# Write out the source file.
cpp -P src/Main.java.in src/Main.java
-mkdir classes
-${JAVAC} -d classes src/*.java
-
-${DX} --debug --dex --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+./default-build
diff --git a/test/MultiDexModifiedSecondary/Main.java b/test/MultiDexModifiedSecondary/Main.java
new file mode 100644
index 0000000..659dba9
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/Main.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+class Main {
+ public static void main(String args[]) {
+ Second second = new Second();
+ System.out.println(second.getSecond());
+ }
+}
diff --git a/test/MultiDexModifiedSecondary/README.txt b/test/MultiDexModifiedSecondary/README.txt
new file mode 100644
index 0000000..4cf3a56
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/README.txt
@@ -0,0 +1,4 @@
+MultiDexModifiedSecondary is designed to result in a multidex file that has
+the same classes.dex file as MultiDex, but a different classes2.dex.
+
+This is used in the OatFileAssistantTest.MultiDexSecondaryOutOfDate gtest.
diff --git a/test/MultiDexModifiedSecondary/Second.java b/test/MultiDexModifiedSecondary/Second.java
new file mode 100644
index 0000000..3555a7f
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/Second.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+class Second {
+ public String getThird() {
+ return "I Third That.";
+ }
+
+ public String getSecond() {
+ return "I Second That.";
+ }
+}
diff --git a/test/MultiDexModifiedSecondary/main.jpp b/test/MultiDexModifiedSecondary/main.jpp
new file mode 100644
index 0000000..a5d7a6c
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/main.jpp
@@ -0,0 +1,3 @@
+main:
+ @@com.android.jack.annotations.ForceInMainDex
+ class Main
diff --git a/test/MultiDexModifiedSecondary/main.list b/test/MultiDexModifiedSecondary/main.list
new file mode 100644
index 0000000..44ba78e
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/main.list
@@ -0,0 +1 @@
+Main.class
diff --git a/test/run-test b/test/run-test
index 239681f..54c6bbd 100755
--- a/test/run-test
+++ b/test/run-test
@@ -501,14 +501,20 @@
if [ '!' -r "$build" ]; then
cp "${progdir}/etc/default-build" build
+else
+ cp "${progdir}/etc/default-build" .
fi
if [ '!' -r "$run" ]; then
cp "${progdir}/etc/default-run" run
+else
+ cp "${progdir}/etc/default-run" .
fi
if [ '!' -r "$check_cmd" ]; then
cp "${progdir}/etc/default-check" check
+else
+ cp "${progdir}/etc/default-check" .
fi
chmod 755 "$build"
diff --git a/tools/checker/README b/tools/checker/README
index 2763948..858a773 100644
--- a/tools/checker/README
+++ b/tools/checker/README
@@ -47,7 +47,7 @@
// CHECK-START: int MyClass.MyMethod() constant_folding (after)
// CHECK: <<ID:i\d+>> IntConstant {{11|22}}
- // CHECK: Return [ <<ID>> ]
+ // CHECK: Return [<<ID>>]
The engine will attempt to match the check lines against the output of the
group named on the first line. Together they verify that the CFG after
diff --git a/tools/checker/common/immutables.py b/tools/checker/common/immutables.py
new file mode 100644
index 0000000..e016867
--- /dev/null
+++ b/tools/checker/common/immutables.py
@@ -0,0 +1,25 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class ImmutableDict(dict):
+ def __setitem__(self, key, value):
+ raise RuntimeError("Cannot modify ImmutableDict")
+
+ def __delitem__(self, key):
+ raise RuntimeError("Cannot modify ImmutableDict")
+
+ def copyWith(self, key, value):
+ newDict = ImmutableDict(self)
+ dict.__setitem__(newDict, key, value)
+ return newDict
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index 2ed4aa7..116fe9a 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from common.immutables import ImmutableDict
from common.logger import Logger
from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
from file_format.checker.struct import CheckerFile, TestCase, TestAssertion
@@ -112,7 +113,7 @@
responsible for running the checks in the right order and scope, and
for propagating the variable state between the check lines.
"""
- varState = {}
+ varState = ImmutableDict()
checkLines = checkGroup.assertions
outputLines = outputGroup.body
startLineNo = outputGroup.startLineNo
diff --git a/tools/checker/match/line.py b/tools/checker/match/line.py
index f0253c3..711d814 100644
--- a/tools/checker/match/line.py
+++ b/tools/checker/match/line.py
@@ -13,77 +13,84 @@
# limitations under the License.
from common.logger import Logger
-from file_format.checker.struct import TestAssertion, RegexExpression
+from file_format.checker.struct import RegexExpression
import re
-def __isMatchAtStart(match):
- """ Tests if the given Match occurred at the beginning of the line. """
- return (match is not None) and (match.start() == 0)
+def headAndTail(list):
+ return list[0], list[1:]
-def __generatePattern(checkLine, linePart, varState):
- """ Returns the regex pattern to be matched in the output line. Variable
- references are substituted with their current values provided in the
- 'varState' argument.
+def splitAtSeparators(expressions):
+ """ Splits a list of RegexExpressions at separators. """
+ splitExpressions = []
+ wordStart = 0
+ for index, expression in enumerate(expressions):
+ if expression.variant == RegexExpression.Variant.Separator:
+ splitExpressions.append(expressions[wordStart:index])
+ wordStart = index + 1
+ splitExpressions.append(expressions[wordStart:])
+ return splitExpressions
- An exception is raised if a referenced variable is undefined.
+def matchWords(checkerWord, stringWord, variables, pos):
+ """ Attempts to match a list of RegexExpressions against a string.
+ Returns updated variable dictionary if successful and None otherwise.
"""
- if linePart.variant == RegexExpression.Variant.VarRef:
- try:
- return re.escape(varState[linePart.name])
- except KeyError:
- Logger.testFailed("Use of undefined variable \"" + linePart.name + "\"",
- checkLine.fileName, checkLine.lineNo)
- else:
- return linePart.pattern
-
-def __isSeparated(outputLine, matchStart):
- return (matchStart == 0) or (outputLine[matchStart - 1:matchStart].isspace())
-
-def MatchLines(checkLine, outputLine, initialVarState):
- """ Attempts to match the check line against a line from the output file with
- the given initial variable values. It returns the new variable state if
- successful and None otherwise.
- """
- # Do the full matching on a shadow copy of the variable state. If the
- # matching fails half-way, we will not need to revert the state.
- varState = dict(initialVarState)
-
- matchStart = 0
- isAfterSeparator = True
-
- # Now try to parse all of the parts of the check line in the right order.
- # Variable values are updated on-the-fly, meaning that a variable can
- # be referenced immediately after its definition.
- for part in checkLine.expressions:
- if part.variant == RegexExpression.Variant.Separator:
- isAfterSeparator = True
- continue
-
- # Find the earliest match for this line part.
- pattern = __generatePattern(checkLine, part, varState)
- while True:
- match = re.search(pattern, outputLine[matchStart:])
- if (match is None) or (not isAfterSeparator and not __isMatchAtStart(match)):
- return None
- matchEnd = matchStart + match.end()
- matchStart += match.start()
-
- # Check if this is a valid match if we expect a whitespace separator
- # before the matched text. Otherwise loop and look for another match.
- if not isAfterSeparator or __isSeparated(outputLine, matchStart):
- break
+ for expression in checkerWord:
+ # If `expression` is a variable reference, replace it with the value.
+ if expression.variant == RegexExpression.Variant.VarRef:
+ if expression.name in variables:
+ pattern = re.escape(variables[expression.name])
else:
- matchStart += 1
+ Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
+ pos.fileName, pos.lineNo)
+ else:
+ pattern = expression.pattern
- if part.variant == RegexExpression.Variant.VarDef:
- if part.name in varState:
- Logger.testFailed("Multiple definitions of variable \"" + part.name + "\"",
- checkLine.fileName, checkLine.lineNo)
- varState[part.name] = outputLine[matchStart:matchEnd]
+ # Match the expression's regex pattern against the remainder of the word.
+ # Note: re.match will succeed only if matched from the beginning.
+ match = re.match(pattern, stringWord)
+ if not match:
+ return None
- matchStart = matchEnd
- isAfterSeparator = False
+ # If `expression` was a variable definition, set the variable's value.
+ if expression.variant == RegexExpression.Variant.VarDef:
+ if expression.name not in variables:
+ variables = variables.copyWith(expression.name, stringWord[:match.end()])
+ else:
+ Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
+ pos.fileName, pos.lineNo)
- # All parts were successfully matched. Return the new variable state.
- return varState
+ # Move cursor by deleting the matched characters.
+ stringWord = stringWord[match.end():]
+
+ # Make sure the entire word matched, i.e. `stringWord` is empty.
+ if stringWord:
+ return None
+
+ return variables
+
+def MatchLines(checkerLine, stringLine, variables):
+ """ Attempts to match a CHECK line against a string. Returns variable state
+ after the match if successful and None otherwise.
+ """
+ checkerWords = splitAtSeparators(checkerLine.expressions)
+ stringWords = stringLine.split()
+
+ while checkerWords:
+ # Get the next run of RegexExpressions which must match one string word.
+ checkerWord, checkerWords = headAndTail(checkerWords)
+
+ # Keep reading words until a match is found.
+ wordMatched = False
+ while stringWords:
+ stringWord, stringWords = headAndTail(stringWords)
+ newVariables = matchWords(checkerWord, stringWord, variables, checkerLine)
+ if newVariables is not None:
+ wordMatched = True
+ variables = newVariables
+ break
+ if not wordMatched:
+ return None
+
+ # All RegexExpressions matched. Return new variable state.
+ return variables
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
index bb3b1af..97725ad 100644
--- a/tools/checker/match/test.py
+++ b/tools/checker/match/test.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from common.immutables import ImmutableDict
from common.testing import ToUnicode
from file_format.c1visualizer.parser import ParseC1visualizerStream
from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
@@ -33,7 +34,9 @@
return ParseCheckerAssertion(testCase, checkerString, TestAssertion.Variant.InOrder, 0)
def tryMatch(self, checkerString, c1String, varState={}):
- return MatchLines(self.createTestAssertion(checkerString), ToUnicode(c1String), varState)
+ return MatchLines(self.createTestAssertion(checkerString),
+ ToUnicode(c1String),
+ ImmutableDict(varState))
def matches(self, checkerString, c1String, varState={}):
return self.tryMatch(checkerString, c1String, varState) is not None
@@ -137,8 +140,8 @@
// CHECK: abc<<X>>def
""",
"""
- foo bar
- abc def
+ foo0bar
+ abc0def
"""))
self.assertTrue(self.matches(
"""
@@ -161,6 +164,12 @@
abc1235def
"""))
+ def test_WholeWordMustMatch(self):
+ self.assertTrue(self.matches( "// CHECK: b{{.}}r", "abc bar def"))
+ self.assertFalse(self.matches( "// CHECK: b{{.}}r", "abc Xbar def"))
+ self.assertFalse(self.matches( "// CHECK: b{{.}}r", "abc barX def"))
+ self.assertFalse(self.matches( "// CHECK: b{{.}}r", "abc b r def"))
+
def test_InOrderAssertions(self):
self.assertTrue(self.matches(
"""
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 8ce19dd..a8bc4e1 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -109,12 +109,6 @@
bug: 19165288
},
{
- description: "Needs to be run as root",
- result: EXEC_FAILED,
- modes: [host],
- names: ["libcore.io.OsTest#test_PacketSocketAddress"]
-},
-{
description: "Needs kernel updates on host/device",
result: EXEC_FAILED,
names: ["libcore.io.OsTest#test_socketPing"]