diff options
author | 2017-01-19 14:48:48 -0800 | |
---|---|---|
committer | 2017-01-20 15:47:06 -0800 | |
commit | a2f526f889be06f96ea59624c9dfb1223b3839f3 (patch) | |
tree | 769f517e6664de0e89abeadf07a39d5410fcee42 | |
parent | 64e50021845b1ad9d8851596e8aaddf18be217c2 (diff) |
Compressed native PC for stack maps
Compress native PC based on instruction alignment. This reduces the
size of stack maps, boot.oat is 0.4% smaller for arm64.
Test: test-art-host, test-art-target, N6P booting
Change-Id: I2b70eecabda88b06fa80a85688fd992070d54278
-rw-r--r-- | compiler/debug/elf_debug_line_writer.h | 7 | ||||
-rw-r--r-- | compiler/debug/elf_debug_loc_writer.h | 8 | ||||
-rw-r--r-- | compiler/exception_test.cc | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 7 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_stream.cc | 18 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_stream.h | 13 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_test.cc | 50 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 38 | ||||
-rw-r--r-- | runtime/arch/code_offset.h | 92 | ||||
-rw-r--r-- | runtime/arch/instruction_set.h | 19 | ||||
-rw-r--r-- | runtime/arch/instruction_set_test.cc | 9 | ||||
-rw-r--r-- | runtime/jit/jit.cc | 2 | ||||
-rw-r--r-- | runtime/oat.h | 2 | ||||
-rw-r--r-- | runtime/oat_quick_method_header.cc | 2 | ||||
-rw-r--r-- | runtime/stack_map.cc | 10 | ||||
-rw-r--r-- | runtime/stack_map.h | 29 |
20 files changed, 244 insertions, 75 deletions
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h index 3db73064ff..18a9165854 100644 --- a/compiler/debug/elf_debug_line_writer.h +++ b/compiler/debug/elf_debug_line_writer.h @@ -53,7 +53,8 @@ class ElfDebugLineWriter { // Write line table for given set of methods. // Returns the number of bytes written. size_t WriteCompilationUnit(ElfCompilationUnit& compilation_unit) { - const bool is64bit = Is64BitInstructionSet(builder_->GetIsa()); + const InstructionSet isa = builder_->GetIsa(); + const bool is64bit = Is64BitInstructionSet(isa); const Elf_Addr base_address = compilation_unit.is_code_address_text_relative ? builder_->GetText()->GetAddress() : 0; @@ -66,7 +67,7 @@ class ElfDebugLineWriter { std::unordered_map<std::string, size_t> directories_map; int code_factor_bits_ = 0; int dwarf_isa = -1; - switch (builder_->GetIsa()) { + switch (isa) { case kArm: // arm actually means thumb2. case kThumb2: code_factor_bits_ = 1; // 16-bit instuctions @@ -103,7 +104,7 @@ class ElfDebugLineWriter { for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); s++) { StackMap stack_map = code_info.GetStackMapAt(s, encoding); DCHECK(stack_map.IsValid()); - const uint32_t pc = stack_map.GetNativePcOffset(encoding.stack_map_encoding); + const uint32_t pc = stack_map.GetNativePcOffset(encoding.stack_map_encoding, isa); const int32_t dex = stack_map.GetDexPc(encoding.stack_map_encoding); pc2dex_map.push_back({pc, dex}); if (stack_map.HasDexRegisterMap(encoding.stack_map_encoding)) { diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index 9645643edd..bce538743b 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -92,7 +92,8 @@ std::vector<VariableLocation> GetVariableLocations( bool is64bitValue, uint64_t compilation_unit_code_address, uint32_t dex_pc_low, - uint32_t dex_pc_high) { + uint32_t dex_pc_high, + InstructionSet isa) { std::vector<VariableLocation> variable_locations; // Get stack maps sorted by pc (they might not be sorted internally). @@ -111,7 +112,7 @@ std::vector<VariableLocation> GetVariableLocations( // The main reason for this is to save space by avoiding undefined gaps. continue; } - const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding.stack_map_encoding); + const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding.stack_map_encoding, isa); DCHECK_LE(pc_offset, method_info->code_size); DCHECK_LE(compilation_unit_code_address, method_info->code_address); const uint32_t low_pc = dchecked_integral_cast<uint32_t>( @@ -196,7 +197,8 @@ static void WriteDebugLocEntry(const MethodDebugInfo* method_info, is64bitValue, compilation_unit_code_address, dex_pc_low, - dex_pc_high); + dex_pc_high, + isa); // Write .debug_loc entries. dwarf::Writer<> debug_loc(debug_loc_buffer); diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index f9e5cb9cb7..eac46e5909 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -61,7 +61,7 @@ class ExceptionTest : public CommonRuntimeTest { ArenaPool pool; ArenaAllocator allocator(&pool); - StackMapStream stack_maps(&allocator); + StackMapStream stack_maps(&allocator, kRuntimeISA); stack_maps.BeginStackMapEntry(/* dex_pc */ 3u, /* native_pc_offset */ 3u, /* register_mask */ 0u, diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 70c2738010..99427f05da 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -839,8 +839,8 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, // last emitted is different than the native pc of the stack map just emitted. size_t number_of_stack_maps = stack_map_stream_.GetNumberOfStackMaps(); if (number_of_stack_maps > 1) { - DCHECK_NE(stack_map_stream_.GetStackMap(number_of_stack_maps - 1).native_pc_offset, - stack_map_stream_.GetStackMap(number_of_stack_maps - 2).native_pc_offset); + DCHECK_NE(stack_map_stream_.GetStackMap(number_of_stack_maps - 1).native_pc_code_offset, + stack_map_stream_.GetStackMap(number_of_stack_maps - 2).native_pc_code_offset); } } } @@ -848,7 +848,8 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, bool CodeGenerator::HasStackMapAtCurrentPc() { uint32_t pc = GetAssembler()->CodeSize(); size_t count = stack_map_stream_.GetNumberOfStackMaps(); - return count > 0 && stack_map_stream_.GetStackMap(count - 1).native_pc_offset == pc; + CodeOffset native_pc_offset = stack_map_stream_.GetStackMap(count - 1).native_pc_code_offset; + return (count > 0) && (native_pc_offset.Uint32Value(GetInstructionSet()) == pc); } void CodeGenerator::MaybeRecordNativeDebugInfo(HInstruction* instruction, diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 38d532e1e9..2d129aff22 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -608,7 +608,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { number_of_register_pairs_(number_of_register_pairs), core_callee_save_mask_(core_callee_save_mask), fpu_callee_save_mask_(fpu_callee_save_mask), - stack_map_stream_(graph->GetArena()), + stack_map_stream_(graph->GetArena(), graph->GetInstructionSet()), block_order_(nullptr), jit_string_roots_(StringReferenceValueComparator(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 9c9c604dca..b566334725 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1239,7 +1239,8 @@ void CodeGeneratorARM::Finalize(CodeAllocator* allocator) { // Adjust native pc offsets in stack maps. for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) { - uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset; + uint32_t old_position = + stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kThumb2); uint32_t new_position = __ GetAdjustedPosition(old_position); stack_map_stream_.SetStackMapNativePcOffset(i, new_position); } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index a0383826d3..76be74e921 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -496,7 +496,8 @@ void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) { // Adjust native pc offsets in stack maps. for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) { - uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset; + uint32_t old_position = + stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kMips); uint32_t new_position = __ GetAdjustedPosition(old_position); DCHECK_GE(new_position, old_position); stack_map_stream_.SetStackMapNativePcOffset(i, new_position); diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 446dea659e..192b4a5050 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -450,7 +450,8 @@ void CodeGeneratorMIPS64::Finalize(CodeAllocator* allocator) { // Adjust native pc offsets in stack maps. for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) { - uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset; + uint32_t old_position = + stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kMips64); uint32_t new_position = __ GetAdjustedPosition(old_position); DCHECK_GE(new_position, old_position); stack_map_stream_.SetStackMapNativePcOffset(i, new_position); diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 6087e36507..a9a1e6f592 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -31,7 +31,7 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; DCHECK_NE(dex_pc, static_cast<uint32_t>(-1)) << "invalid dex_pc"; current_entry_.dex_pc = dex_pc; - current_entry_.native_pc_offset = native_pc_offset; + current_entry_.native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_); current_entry_.register_mask = register_mask; current_entry_.sp_mask = sp_mask; current_entry_.num_dex_registers = num_dex_registers; @@ -144,10 +144,10 @@ void StackMapStream::EndInlineInfoEntry() { current_inline_info_ = InlineInfoEntry(); } -uint32_t StackMapStream::ComputeMaxNativePcOffset() const { - uint32_t max_native_pc_offset = 0u; +CodeOffset StackMapStream::ComputeMaxNativePcCodeOffset() const { + CodeOffset max_native_pc_offset; for (const StackMapEntry& entry : stack_maps_) { - max_native_pc_offset = std::max(max_native_pc_offset, entry.native_pc_offset); + max_native_pc_offset = std::max(max_native_pc_offset, entry.native_pc_code_offset); } return max_native_pc_offset; } @@ -157,8 +157,9 @@ size_t StackMapStream::PrepareForFillIn() { dex_register_maps_size_ = ComputeDexRegisterMapsSize(); ComputeInlineInfoEncoding(); // needs dex_register_maps_size_. inline_info_size_ = inline_infos_.size() * inline_info_encoding_.GetEntrySize(); - uint32_t max_native_pc_offset = ComputeMaxNativePcOffset(); - size_t stack_map_size = stack_map_encoding_.SetFromSizes(max_native_pc_offset, + CodeOffset max_native_pc_offset = ComputeMaxNativePcCodeOffset(); + // The stack map contains compressed native offsets. + size_t stack_map_size = stack_map_encoding_.SetFromSizes(max_native_pc_offset.CompressedValue(), dex_pc_max_, dex_register_maps_size_, inline_info_size_, @@ -319,7 +320,7 @@ void StackMapStream::FillIn(MemoryRegion region) { StackMapEntry entry = stack_maps_[i]; stack_map.SetDexPc(stack_map_encoding_, entry.dex_pc); - stack_map.SetNativePcOffset(stack_map_encoding_, entry.native_pc_offset); + stack_map.SetNativePcCodeOffset(stack_map_encoding_, entry.native_pc_code_offset); stack_map.SetRegisterMask(stack_map_encoding_, entry.register_mask); size_t number_of_stack_mask_bits = stack_map.GetNumberOfStackMaskBits(stack_map_encoding_); if (entry.sp_mask != nullptr) { @@ -546,7 +547,8 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const { StackMapEntry entry = stack_maps_[s]; // Check main stack map fields. - DCHECK_EQ(stack_map.GetNativePcOffset(stack_map_encoding), entry.native_pc_offset); + DCHECK_EQ(stack_map.GetNativePcOffset(stack_map_encoding, instruction_set_), + entry.native_pc_code_offset.Uint32Value(instruction_set_)); DCHECK_EQ(stack_map.GetDexPc(stack_map_encoding), entry.dex_pc); DCHECK_EQ(stack_map.GetRegisterMask(stack_map_encoding), entry.register_mask); size_t num_stack_mask_bits = stack_map.GetNumberOfStackMaskBits(stack_map_encoding); diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index d6f42b373c..8fec472437 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -59,8 +59,10 @@ class DexRegisterLocationHashFn { */ class StackMapStream : public ValueObject { public: - explicit StackMapStream(ArenaAllocator* allocator) + explicit StackMapStream(ArenaAllocator* allocator, + InstructionSet instruction_set) : allocator_(allocator), + instruction_set_(instruction_set), stack_maps_(allocator->Adapter(kArenaAllocStackMapStream)), location_catalog_entries_(allocator->Adapter(kArenaAllocStackMapStream)), location_catalog_entries_indices_(allocator->Adapter(kArenaAllocStackMapStream)), @@ -95,7 +97,7 @@ class StackMapStream : public ValueObject { // See runtime/stack_map.h to know what these fields contain. struct StackMapEntry { uint32_t dex_pc; - uint32_t native_pc_offset; + CodeOffset native_pc_code_offset; uint32_t register_mask; BitVector* sp_mask; uint32_t num_dex_registers; @@ -141,11 +143,9 @@ class StackMapStream : public ValueObject { } void SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) { - stack_maps_[i].native_pc_offset = native_pc_offset; + stack_maps_[i].native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_); } - uint32_t ComputeMaxNativePcOffset() const; - // Prepares the stream to fill in a memory region. Must be called before FillIn. // Returns the size (in bytes) needed to store this stream. size_t PrepareForFillIn(); @@ -158,6 +158,8 @@ class StackMapStream : public ValueObject { size_t ComputeDexRegisterMapsSize() const; void ComputeInlineInfoEncoding(); + CodeOffset ComputeMaxNativePcCodeOffset() const; + // Returns the index of an entry with the same dex register map as the current_entry, // or kNoSameDexMapFound if no such entry exists. size_t FindEntryWithTheSameDexMap(); @@ -175,6 +177,7 @@ class StackMapStream : public ValueObject { void CheckCodeInfo(MemoryRegion region) const; ArenaAllocator* allocator_; + const InstructionSet instruction_set_; ArenaVector<StackMapEntry> stack_maps_; // A catalog of unique [location_kind, register_value] pairs (per method). diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 22810ea4f7..f68695bcbc 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -47,7 +47,7 @@ using Kind = DexRegisterLocation::Kind; TEST(StackMapTest, Test1) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArenaBitVector sp_mask(&arena, 0, false); size_t number_of_dex_registers = 2; @@ -78,7 +78,7 @@ TEST(StackMapTest, Test1) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(CheckStackMask(stack_map, encoding.stack_map_encoding, sp_mask)); @@ -128,7 +128,7 @@ TEST(StackMapTest, Test1) { TEST(StackMapTest, Test2) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArtMethod art_method; ArenaBitVector sp_mask1(&arena, 0, true); @@ -193,7 +193,7 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(CheckStackMask(stack_map, encoding.stack_map_encoding, sp_mask1)); @@ -252,7 +252,7 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u, encoding))); ASSERT_EQ(1u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(128u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(128u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0xFFu, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(CheckStackMask(stack_map, encoding.stack_map_encoding, sp_mask2)); @@ -306,7 +306,7 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u, encoding))); ASSERT_EQ(2u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(192u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(192u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0xABu, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(CheckStackMask(stack_map, encoding.stack_map_encoding, sp_mask3)); @@ -360,7 +360,7 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u, encoding))); ASSERT_EQ(3u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(256u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(256u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0xCDu, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(CheckStackMask(stack_map, encoding.stack_map_encoding, sp_mask4)); @@ -412,7 +412,7 @@ TEST(StackMapTest, Test2) { TEST(StackMapTest, TestNonLiveDexRegisters) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArenaBitVector sp_mask(&arena, 0, false); uint32_t number_of_dex_registers = 2; @@ -442,7 +442,7 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map_encoding)); @@ -491,7 +491,7 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { TEST(StackMapTest, DexRegisterMapOffsetOverflow) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArenaBitVector sp_mask(&arena, 0, false); uint32_t number_of_dex_registers = 1024; @@ -554,7 +554,7 @@ TEST(StackMapTest, DexRegisterMapOffsetOverflow) { TEST(StackMapTest, TestShareDexRegisterMap) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArenaBitVector sp_mask(&arena, 0, false); uint32_t number_of_dex_registers = 2; @@ -612,7 +612,7 @@ TEST(StackMapTest, TestShareDexRegisterMap) { TEST(StackMapTest, TestNoDexRegisterMap) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArenaBitVector sp_mask(&arena, 0, false); uint32_t number_of_dex_registers = 0; @@ -620,7 +620,7 @@ TEST(StackMapTest, TestNoDexRegisterMap) { stream.EndStackMapEntry(); number_of_dex_registers = 1; - stream.BeginStackMapEntry(1, 67, 0x4, &sp_mask, number_of_dex_registers, 0); + stream.BeginStackMapEntry(1, 68, 0x4, &sp_mask, number_of_dex_registers, 0); stream.EndStackMapEntry(); size_t size = stream.PrepareForFillIn(); @@ -641,7 +641,7 @@ TEST(StackMapTest, TestNoDexRegisterMap) { ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_FALSE(stack_map.HasDexRegisterMap(encoding.stack_map_encoding)); @@ -649,9 +649,9 @@ TEST(StackMapTest, TestNoDexRegisterMap) { stack_map = code_info.GetStackMapAt(1, encoding); ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(67, encoding))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68, encoding))); ASSERT_EQ(1u, stack_map.GetDexPc(encoding.stack_map_encoding)); - ASSERT_EQ(67u, stack_map.GetNativePcOffset(encoding.stack_map_encoding)); + ASSERT_EQ(68u, stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA)); ASSERT_EQ(0x4u, stack_map.GetRegisterMask(encoding.stack_map_encoding)); ASSERT_FALSE(stack_map.HasDexRegisterMap(encoding.stack_map_encoding)); @@ -661,7 +661,7 @@ TEST(StackMapTest, TestNoDexRegisterMap) { TEST(StackMapTest, InlineTest) { ArenaPool pool; ArenaAllocator arena(&pool); - StackMapStream stream(&arena); + StackMapStream stream(&arena, kRuntimeISA); ArtMethod art_method; ArenaBitVector sp_mask1(&arena, 0, true); @@ -823,4 +823,20 @@ TEST(StackMapTest, InlineTest) { } } +TEST(StackMapTest, CodeOffsetTest) { + // Test minimum alignments, encoding, and decoding. + CodeOffset offset_thumb2 = CodeOffset::FromOffset(kThumb2InstructionAlignment, kThumb2); + CodeOffset offset_arm64 = CodeOffset::FromOffset(kArm64InstructionAlignment, kArm64); + CodeOffset offset_x86 = CodeOffset::FromOffset(kX86InstructionAlignment, kX86); + CodeOffset offset_x86_64 = CodeOffset::FromOffset(kX86_64InstructionAlignment, kX86_64); + CodeOffset offset_mips = CodeOffset::FromOffset(kMipsInstructionAlignment, kMips); + CodeOffset offset_mips64 = CodeOffset::FromOffset(kMips64InstructionAlignment, kMips64); + EXPECT_EQ(offset_thumb2.Uint32Value(kThumb2), kThumb2InstructionAlignment); + EXPECT_EQ(offset_arm64.Uint32Value(kArm64), kArm64InstructionAlignment); + EXPECT_EQ(offset_x86.Uint32Value(kX86), kX86InstructionAlignment); + EXPECT_EQ(offset_x86_64.Uint32Value(kX86_64), kX86_64InstructionAlignment); + EXPECT_EQ(offset_mips.Uint32Value(kMips), kMipsInstructionAlignment); + EXPECT_EQ(offset_mips64.Uint32Value(kMips64), kMips64InstructionAlignment); +} + } // namespace art diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 148ee88669..3cf900ed44 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1223,7 +1223,8 @@ class OatDumper { code_info.Dump(vios, oat_method.GetCodeOffset(), code_item.registers_size_, - options_.dump_code_info_stack_maps_); + options_.dump_code_info_stack_maps_, + instruction_set_); } void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method, @@ -1329,21 +1330,22 @@ class OatDumper { // For identical native PCs, the order from the CodeInfo is preserved. class StackMapsHelper { public: - explicit StackMapsHelper(const uint8_t* raw_code_info) + explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set) : code_info_(raw_code_info), encoding_(code_info_.ExtractEncoding()), number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)), indexes_(), - offset_(static_cast<size_t>(-1)), - stack_map_index_(0u) { + offset_(static_cast<uint32_t>(-1)), + stack_map_index_(0u), + instruction_set_(instruction_set) { if (number_of_stack_maps_ != 0u) { // Check if native PCs are ordered. bool ordered = true; StackMap last = code_info_.GetStackMapAt(0u, encoding_); for (size_t i = 1; i != number_of_stack_maps_; ++i) { StackMap current = code_info_.GetStackMapAt(i, encoding_); - if (last.GetNativePcOffset(encoding_.stack_map_encoding) > - current.GetNativePcOffset(encoding_.stack_map_encoding)) { + if (last.GetNativePcOffset(encoding_.stack_map_encoding, instruction_set) > + current.GetNativePcOffset(encoding_.stack_map_encoding, instruction_set)) { ordered = false; break; } @@ -1359,14 +1361,17 @@ class OatDumper { indexes_.end(), [this](size_t lhs, size_t rhs) { StackMap left = code_info_.GetStackMapAt(lhs, encoding_); - uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map_encoding); + uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map_encoding, + instruction_set_); StackMap right = code_info_.GetStackMapAt(rhs, encoding_); - uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map_encoding); + uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map_encoding, + instruction_set_); // If the PCs are the same, compare indexes to preserve the original order. return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs); }); } - offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map_encoding); + offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map_encoding, + instruction_set_); } } @@ -1378,7 +1383,7 @@ class OatDumper { return encoding_; } - size_t GetOffset() const { + uint32_t GetOffset() const { return offset_; } @@ -1389,8 +1394,9 @@ class OatDumper { void Next() { ++stack_map_index_; offset_ = (stack_map_index_ == number_of_stack_maps_) - ? static_cast<size_t>(-1) - : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map_encoding); + ? static_cast<uint32_t>(-1) + : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map_encoding, + instruction_set_); } private: @@ -1406,8 +1412,9 @@ class OatDumper { const CodeInfoEncoding encoding_; const size_t number_of_stack_maps_; dchecked_vector<size_t> indexes_; // Used if stack map native PCs are not ordered. - size_t offset_; + uint32_t offset_; size_t stack_map_index_; + const InstructionSet instruction_set_; }; void DumpCode(VariableIndentationOutputStream* vios, @@ -1423,7 +1430,7 @@ class OatDumper { return; } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) { // The optimizing compiler outputs its CodeInfo data in the vmap table. - StackMapsHelper helper(oat_method.GetVmapTable()); + StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_); const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); size_t offset = 0; while (offset < code_size) { @@ -1436,7 +1443,8 @@ class OatDumper { helper.GetCodeInfo(), helper.GetEncoding(), oat_method.GetCodeOffset(), - code_item->registers_size_); + code_item->registers_size_, + instruction_set_); do { helper.Next(); // There may be multiple stack maps at a given PC. We display only the first one. diff --git a/runtime/arch/code_offset.h b/runtime/arch/code_offset.h new file mode 100644 index 0000000000..ab04b1eaa7 --- /dev/null +++ b/runtime/arch/code_offset.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_ARCH_CODE_OFFSET_H_ +#define ART_RUNTIME_ARCH_CODE_OFFSET_H_ + +#include <iosfwd> + +#include "base/bit_utils.h" +#include "base/logging.h" +#include "instruction_set.h" + +namespace art { + +// CodeOffset is a holder for compressed code offsets. Since some architectures have alignment +// requirements it is possible to compress code offsets to reduce stack map sizes. +class CodeOffset { + public: + ALWAYS_INLINE static CodeOffset FromOffset(uint32_t offset, InstructionSet isa = kRuntimeISA) { + return CodeOffset(offset / GetInstructionSetInstructionAlignment(isa)); + } + + ALWAYS_INLINE static CodeOffset FromCompressedOffset(uint32_t offset) { + return CodeOffset(offset); + } + + ALWAYS_INLINE uint32_t Uint32Value(InstructionSet isa = kRuntimeISA) const { + uint32_t decoded = value_ * GetInstructionSetInstructionAlignment(isa); + DCHECK_GE(decoded, value_) << "Integer overflow"; + return decoded; + } + + // Return compressed internal value. + ALWAYS_INLINE uint32_t CompressedValue() const { + return value_; + } + + ALWAYS_INLINE CodeOffset() = default; + ALWAYS_INLINE CodeOffset(const CodeOffset&) = default; + ALWAYS_INLINE CodeOffset& operator=(const CodeOffset&) = default; + ALWAYS_INLINE CodeOffset& operator=(CodeOffset&&) = default; + + private: + ALWAYS_INLINE explicit CodeOffset(uint32_t value) : value_(value) {} + + uint32_t value_ = 0u; +}; + +inline bool operator==(const CodeOffset& a, const CodeOffset& b) { + return a.CompressedValue() == b.CompressedValue(); +} + +inline bool operator!=(const CodeOffset& a, const CodeOffset& b) { + return !(a == b); +} + +inline bool operator<(const CodeOffset& a, const CodeOffset& b) { + return a.CompressedValue() < b.CompressedValue(); +} + +inline bool operator<=(const CodeOffset& a, const CodeOffset& b) { + return a.CompressedValue() <= b.CompressedValue(); +} + +inline bool operator>(const CodeOffset& a, const CodeOffset& b) { + return a.CompressedValue() > b.CompressedValue(); +} + +inline bool operator>=(const CodeOffset& a, const CodeOffset& b) { + return a.CompressedValue() >= b.CompressedValue(); +} + +inline std::ostream& operator<<(std::ostream& os, const CodeOffset& offset) { + return os << offset.Uint32Value(); +} + +} // namespace art + +#endif // ART_RUNTIME_ARCH_CODE_OFFSET_H_ diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h index 4a8bea45e5..99aea62468 100644 --- a/runtime/arch/instruction_set.h +++ b/runtime/arch/instruction_set.h @@ -75,6 +75,14 @@ static constexpr size_t kMipsAlignment = 8; // X86 instruction alignment. This is the recommended alignment for maximum performance. static constexpr size_t kX86Alignment = 16; +// Different than code alignment since code alignment is only first instruction of method. +static constexpr size_t kThumb2InstructionAlignment = 2; +static constexpr size_t kArm64InstructionAlignment = 4; +static constexpr size_t kX86InstructionAlignment = 1; +static constexpr size_t kX86_64InstructionAlignment = 1; +static constexpr size_t kMipsInstructionAlignment = 2; +static constexpr size_t kMips64InstructionAlignment = 2; + const char* GetInstructionSetString(InstructionSet isa); // Note: Returns kNone when the string cannot be parsed to a known value. @@ -106,6 +114,17 @@ static inline PointerSize GetInstructionSetPointerSize(InstructionSet isa) { } } +ALWAYS_INLINE static inline constexpr size_t GetInstructionSetInstructionAlignment( + InstructionSet isa) { + return (isa == kThumb2 || isa == kArm) ? kThumb2InstructionAlignment : + (isa == kArm64) ? kArm64InstructionAlignment : + (isa == kX86) ? kX86InstructionAlignment : + (isa == kX86_64) ? kX86_64InstructionAlignment : + (isa == kMips) ? kMipsInstructionAlignment : + (isa == kMips64) ? kMips64InstructionAlignment : + 0; // Invalid case, but constexpr doesn't support asserts. +} + static inline bool IsValidInstructionSet(InstructionSet isa) { switch (isa) { case kArm: diff --git a/runtime/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc index 5aae93acc5..b251b57c99 100644 --- a/runtime/arch/instruction_set_test.cc +++ b/runtime/arch/instruction_set_test.cc @@ -44,6 +44,15 @@ TEST(InstructionSetTest, GetInstructionSetString) { EXPECT_STREQ("none", GetInstructionSetString(kNone)); } +TEST(InstructionSetTest, GetInstructionSetInstructionAlignment) { + EXPECT_EQ(GetInstructionSetInstructionAlignment(kThumb2), kThumb2InstructionAlignment); + EXPECT_EQ(GetInstructionSetInstructionAlignment(kArm64), kArm64InstructionAlignment); + EXPECT_EQ(GetInstructionSetInstructionAlignment(kX86), kX86InstructionAlignment); + EXPECT_EQ(GetInstructionSetInstructionAlignment(kX86_64), kX86_64InstructionAlignment); + EXPECT_EQ(GetInstructionSetInstructionAlignment(kMips), kMipsInstructionAlignment); + EXPECT_EQ(GetInstructionSetInstructionAlignment(kMips64), kMips64InstructionAlignment); +} + TEST(InstructionSetTest, TestRoundTrip) { EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA))); } diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 2bb8819cb3..6deb03dc41 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -514,7 +514,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, } } - native_pc = stack_map.GetNativePcOffset(encoding.stack_map_encoding) + + native_pc = stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA) + osr_method->GetEntryPoint(); VLOG(jit) << "Jumping to " << method_name diff --git a/runtime/oat.h b/runtime/oat.h index 953b445e4e..29821a2eea 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,7 +32,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '1', '0', '2', '\0' }; // Enabling CC + static constexpr uint8_t kOatVersion[] = { '1', '0', '3', '\0' }; // Native pc change static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc index 9c2378d42d..fd84426bb8 100644 --- a/runtime/oat_quick_method_header.cc +++ b/runtime/oat_quick_method_header.cc @@ -80,7 +80,7 @@ uintptr_t OatQuickMethodHeader::ToNativeQuickPc(ArtMethod* method, : code_info.GetStackMapForDexPc(dex_pc, encoding); if (stack_map.IsValid()) { return reinterpret_cast<uintptr_t>(entry_point) + - stack_map.GetNativePcOffset(encoding.stack_map_encoding); + stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA); } if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 9ebf9a7bdd..3c92b86208 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -116,7 +116,8 @@ void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const { void CodeInfo::Dump(VariableIndentationOutputStream* vios, uint32_t code_offset, uint16_t number_of_dex_registers, - bool dump_stack_maps) const { + bool dump_stack_maps, + InstructionSet instruction_set) const { CodeInfoEncoding encoding = ExtractEncoding(); size_t number_of_stack_maps = GetNumberOfStackMaps(encoding); vios->Stream() @@ -139,6 +140,7 @@ void CodeInfo::Dump(VariableIndentationOutputStream* vios, encoding, code_offset, number_of_dex_registers, + instruction_set, " " + std::to_string(i)); } } @@ -188,14 +190,16 @@ void StackMap::Dump(VariableIndentationOutputStream* vios, const CodeInfoEncoding& encoding, uint32_t code_offset, uint16_t number_of_dex_registers, + InstructionSet instruction_set, const std::string& header_suffix) const { StackMapEncoding stack_map_encoding = encoding.stack_map_encoding; + const uint32_t pc_offset = GetNativePcOffset(stack_map_encoding, instruction_set); vios->Stream() << "StackMap" << header_suffix << std::hex - << " [native_pc=0x" << code_offset + GetNativePcOffset(stack_map_encoding) << "]" + << " [native_pc=0x" << code_offset + pc_offset << "]" << " (dex_pc=0x" << GetDexPc(stack_map_encoding) - << ", native_pc_offset=0x" << GetNativePcOffset(stack_map_encoding) + << ", native_pc_offset=0x" << pc_offset << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding) << ", inline_info_offset=0x" << GetInlineDescriptorOffset(stack_map_encoding) << ", register_mask=0x" << GetRegisterMask(stack_map_encoding) diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 13886f2109..28c4b88fb0 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_STACK_MAP_H_ #define ART_RUNTIME_STACK_MAP_H_ +#include "arch/code_offset.h" #include "base/bit_vector.h" #include "base/bit_utils.h" #include "dex_file.h" @@ -805,12 +806,16 @@ class StackMap { encoding.GetDexPcEncoding().Store(region_, dex_pc); } - ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const { - return encoding.GetNativePcEncoding().Load(region_); + ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding, + InstructionSet instruction_set) const { + CodeOffset offset( + CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); + return offset.Uint32Value(instruction_set); } - ALWAYS_INLINE void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) { - encoding.GetNativePcEncoding().Store(region_, native_pc_offset); + ALWAYS_INLINE void SetNativePcCodeOffset(const StackMapEncoding& encoding, + CodeOffset native_pc_offset) { + encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); } ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const { @@ -866,6 +871,7 @@ class StackMap { const CodeInfoEncoding& encoding, uint32_t code_offset, uint16_t number_of_dex_registers, + InstructionSet instruction_set, const std::string& header_suffix = "") const; // Special (invalid) offset for the DexRegisterMapOffset field meaning @@ -1234,15 +1240,16 @@ class CodeInfo { if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) { StackMap other = GetStackMapAt(i + 1, encoding); if (other.GetDexPc(stack_map_encoding) == dex_pc && - other.GetNativePcOffset(stack_map_encoding) == - stack_map.GetNativePcOffset(stack_map_encoding)) { + other.GetNativePcOffset(stack_map_encoding, kRuntimeISA) == + stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA)) { DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding), stack_map.GetDexRegisterMapOffset(stack_map_encoding)); DCHECK(!stack_map.HasInlineInfo(stack_map_encoding)); if (i < e - 2) { // Make sure there are not three identical stack maps following each other. - DCHECK_NE(stack_map.GetNativePcOffset(stack_map_encoding), - GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding)); + DCHECK_NE( + stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA), + GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding, kRuntimeISA)); } return stack_map; } @@ -1258,7 +1265,8 @@ class CodeInfo { // we could do binary search. for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { StackMap stack_map = GetStackMapAt(i, encoding); - if (stack_map.GetNativePcOffset(encoding.stack_map_encoding) == native_pc_offset) { + if (stack_map.GetNativePcOffset(encoding.stack_map_encoding, kRuntimeISA) == + native_pc_offset) { return stack_map; } } @@ -1273,7 +1281,8 @@ class CodeInfo { void Dump(VariableIndentationOutputStream* vios, uint32_t code_offset, uint16_t number_of_dex_registers, - bool dump_stack_maps) const; + bool dump_stack_maps, + InstructionSet instruction_set) const; // Check that the code info has valid stack map and abort if it does not. void AssertValidStackMap(const CodeInfoEncoding& encoding) const { |