diff options
Diffstat (limited to 'compiler')
22 files changed, 311 insertions, 159 deletions
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h index f7501d2dda..5e345dbf61 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 @@ class CFITest : public dwarf::DwarfTest { // 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 61a44cdabc..3b570e572a 100644 --- a/compiler/dwarf/dwarf_constants.h +++ b/compiler/dwarf/dwarf_constants.h @@ -680,6 +680,14 @@ enum ExceptionHeaderValueApplication : uint8_t { 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 edba00aeaa..4971f0ef10 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 @@ TEST_F(DwarfTest, DebugFrame) { 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 @@ TEST_F(DwarfTest, x86_64_RegisterMapping) { 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 230ebe3a79..3afb5eae56 100644 --- a/compiler/dwarf/dwarf_test.h +++ b/compiler/dwarf/dwarf_test.h @@ -69,7 +69,7 @@ class DwarfTest : public CommonRuntimeTest { 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 @@ class DwarfTest : public CommonRuntimeTest { 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 @@ class DwarfTest : public CommonRuntimeTest { } // 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 9f64766e18..ad315ee351 100644 --- a/compiler/dwarf/headers.h +++ b/compiler/dwarf/headers.h @@ -35,17 +35,18 @@ namespace dwarf { // 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 @@ void WriteEhFrameCIE(bool is64bit, 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_writer_debug.cc b/compiler/elf_writer_debug.cc index 5e9cf76788..a1aabc3605 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 @@ static void WriteEhFrameCIE(InstructionSet isa, } } 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 @@ static void WriteEhFrameCIE(InstructionSet isa, } } 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 @@ static void WriteEhFrameCIE(InstructionSet isa, } } 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 @@ static void WriteEhFrameCIE(InstructionSet isa, } } 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 @@ static void WriteEhFrameCIE(InstructionSet isa, } } 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 @@ static void WriteEhFrameCIE(InstructionSet isa, 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 28d0e2cae5..69f7e0d811 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 79f9955647..96dd7ca62d 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 @@ bool ElfWriterQuick<ElfTypes>::Write( 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 @@ bool ElfWriterQuick<ElfTypes>::Write( 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/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 672e55ea0b..7b37f74847 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -3037,7 +3037,8 @@ void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldI } 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(); @@ -3126,7 +3127,8 @@ void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction, 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) { @@ -3253,7 +3255,7 @@ void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) } void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { - HandleFieldSet(instruction, instruction->GetFieldInfo()); + HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); } void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { @@ -3277,7 +3279,7 @@ void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { } void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { - HandleFieldSet(instruction, instruction->GetFieldInfo()); + HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); } void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { @@ -3547,7 +3549,7 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 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); @@ -3652,13 +3654,21 @@ void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { __ 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 2edbcf8ad7..071bbee534 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -181,7 +181,9 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { 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); @@ -274,7 +276,7 @@ class CodeGeneratorARM : public CodeGenerator { 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 34720e258a..b6d99abca0 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -701,16 +701,20 @@ Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const { 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 { @@ -1265,7 +1269,8 @@ void LocationsBuilderARM64::HandleFieldSet(HInstruction* instruction) { } 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()); @@ -1291,7 +1296,7 @@ void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction, } if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { - codegen_->MarkGCCard(obj, Register(value)); + codegen_->MarkGCCard(obj, Register(value), value_can_be_null); } } @@ -1517,7 +1522,7 @@ void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { codegen_->MaybeRecordImplicitNullCheck(instruction); } if (CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue())) { - codegen_->MarkGCCard(obj, value.W()); + codegen_->MarkGCCard(obj, value.W(), instruction->GetValueCanBeNull()); } } } @@ -2089,7 +2094,7 @@ void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction } void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { - HandleFieldSet(instruction, instruction->GetFieldInfo()); + HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); } void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) { @@ -2832,7 +2837,7 @@ void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) { } 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 702bcd45f3..b56ca10874 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -157,7 +157,9 @@ class InstructionCodeGeneratorARM64 : public HGraphVisitor { 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); @@ -267,7 +269,7 @@ class CodeGeneratorARM64 : public CodeGenerator { 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. diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 0212da106b..a6f01dad38 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -3227,16 +3227,24 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, 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 LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldI } 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 @@ void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction, 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 LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) { } 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 LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) } void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { - HandleFieldSet(instruction, instruction->GetFieldInfo()); + HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); } void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { @@ -3817,7 +3826,8 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { 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 5a5a37b3fe..28766d85ea 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -170,7 +170,9 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { 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 @@ class CodeGeneratorX86 : public CodeGenerator { 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 63d68465d0..f49c26db2b 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -3249,7 +3249,8 @@ void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction, } 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 @@ void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction, 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 LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instructio } 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 LocationsBuilderX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) { } 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 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) { 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 InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) 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 480ea6b9c9..d7bd525243 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -174,7 +174,9 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { 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 @@ class CodeGeneratorX86_64 : public CodeGenerator { } // 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/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 46fad17b8f..0adb931158 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -45,6 +45,8 @@ class InstructionSimplifierVisitor : public HGraphVisitor { 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; @@ -78,6 +80,8 @@ void InstructionSimplifier::Run() { } 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 @@ -199,6 +203,20 @@ void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) { } } +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 +312,10 @@ void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) { 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 dccfe9a0ca..e785bf9036 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -657,7 +657,8 @@ static void GenUnsafePut(LocationSummary* locations, 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 @@ static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGenerat 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 2c4fab0465..53497b6732 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -797,7 +797,8 @@ static void GenUnsafePut(LocationSummary* locations, } 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 @@ static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGenerat // 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 28b7a07cf9..d2ca42de00 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -1503,10 +1503,12 @@ static void GenUnsafePut(LocationSummary* locations, } 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 @@ static void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86* code 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 0efa714a23..2ccecfe936 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -1374,10 +1374,12 @@ static void GenUnsafePut(LocationSummary* locations, Primitive::Type type, bool } 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 @@ static void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86_64* c // 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 0291992cab..2850368f11 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3173,7 +3173,8 @@ class HInstanceFieldSet : public HTemplateInstruction<2> { 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); } @@ -3187,11 +3188,14 @@ class HInstanceFieldSet : public HTemplateInstruction<2> { 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); }; @@ -3240,7 +3244,8 @@ class HArraySet : public HTemplateInstruction<3> { : 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); @@ -3262,6 +3267,11 @@ class HArraySet : public HTemplateInstruction<3> { 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_; } @@ -3287,6 +3297,7 @@ class HArraySet : public HTemplateInstruction<3> { 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); }; @@ -3587,7 +3598,8 @@ class HStaticFieldSet : public HTemplateInstruction<2> { 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); } @@ -3598,11 +3610,14 @@ class HStaticFieldSet : public HTemplateInstruction<2> { 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); }; |