diff options
-rw-r--r-- | compiler/optimizing/code_generator.cc | 166 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_stream.h | 221 | ||||
-rw-r--r-- | compiler/optimizing/stack_map_test.cc | 74 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 8 | ||||
-rw-r--r-- | runtime/check_reference_map_visitor.h | 6 | ||||
-rw-r--r-- | runtime/stack.cc | 27 | ||||
-rw-r--r-- | runtime/stack_map.h | 137 |
8 files changed, 403 insertions, 238 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index a6ab208..9ebf887 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -577,142 +577,42 @@ void CodeGenerator::RecordPcInfo(HInstruction* instruction, uint32_t dex_pc) { pc_info.native_pc = GetAssembler()->CodeSize(); pc_infos_.Add(pc_info); - // Populate stack map information. - + uint32_t inlining_depth = 0; if (instruction == nullptr) { // For stack overflow checks. - stack_map_stream_.AddStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, 0); - return; - } - - LocationSummary* locations = instruction->GetLocations(); - HEnvironment* environment = instruction->GetEnvironment(); - - size_t environment_size = instruction->EnvironmentSize(); - - size_t inlining_depth = 0; - uint32_t register_mask = locations->GetRegisterMask(); - if (locations->OnlyCallsOnSlowPath()) { - // In case of slow path, we currently set the location of caller-save registers - // to register (instead of their stack location when pushed before the slow-path - // call). Therefore register_mask contains both callee-save and caller-save - // registers that hold objects. We must remove the caller-save from the mask, since - // they will be overwritten by the callee. - register_mask &= core_callee_save_mask_; - } - // The register mask must be a subset of callee-save registers. - DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask); - stack_map_stream_.AddStackMapEntry( - dex_pc, pc_info.native_pc, register_mask, - locations->GetStackMask(), environment_size, inlining_depth); - - // Walk over the environment, and record the location of dex registers. - for (size_t i = 0; i < environment_size; ++i) { - HInstruction* current = environment->GetInstructionAt(i); - if (current == nullptr) { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0); - continue; - } - - Location location = locations->GetEnvironmentAt(i); - switch (location.GetKind()) { - case Location::kConstant: { - DCHECK_EQ(current, location.GetConstant()); - if (current->IsLongConstant()) { - int64_t value = current->AsLongConstant()->GetValue(); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, - Low32Bits(value)); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, - High32Bits(value)); - ++i; - DCHECK_LT(i, environment_size); - } else if (current->IsDoubleConstant()) { - int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue()); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, - Low32Bits(value)); - stack_map_stream_.AddDexRegisterEntry(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(DexRegisterLocation::Kind::kConstant, value); - } else if (current->IsNullConstant()) { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0); - } else { - DCHECK(current->IsFloatConstant()); - int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue()); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value); - } - break; - } - - case Location::kStackSlot: { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, - location.GetStackIndex()); - break; - } - - case Location::kDoubleStackSlot: { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, - location.GetStackIndex()); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, - location.GetHighStackIndex(kVRegSize)); - ++i; - DCHECK_LT(i, environment_size); - break; - } - - case Location::kRegister : { - int id = location.reg(); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id); - if (current->GetType() == Primitive::kPrimLong) { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id); - ++i; - DCHECK_LT(i, environment_size); - } - break; - } - - case Location::kFpuRegister : { - int id = location.reg(); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id); - if (current->GetType() == Primitive::kPrimDouble) { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id); - ++i; - DCHECK_LT(i, environment_size); - } - break; - } - - case Location::kFpuRegisterPair : { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, - location.low()); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, - location.high()); - ++i; - DCHECK_LT(i, environment_size); - break; - } - - case Location::kRegisterPair : { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, - location.low()); - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, - location.high()); - ++i; - DCHECK_LT(i, environment_size); - break; - } - - case Location::kInvalid: { - stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0); - break; - } - - default: - LOG(FATAL) << "Unexpected kind " << location.GetKind(); + stack_map_stream_.RecordEnvironment( + /* environment */ nullptr, + /* environment_size */ 0, + /* locations */ nullptr, + dex_pc, + pc_info.native_pc, + /* register_mask */ 0, + inlining_depth); + } else { + LocationSummary* locations = instruction->GetLocations(); + HEnvironment* environment = instruction->GetEnvironment(); + size_t environment_size = instruction->EnvironmentSize(); + + uint32_t register_mask = locations->GetRegisterMask(); + if (locations->OnlyCallsOnSlowPath()) { + // In case of slow path, we currently set the location of caller-save registers + // to register (instead of their stack location when pushed before the slow-path + // call). Therefore register_mask contains both callee-save and caller-save + // registers that hold objects. We must remove the caller-save from the mask, since + // they will be overwritten by the callee. + register_mask &= core_callee_save_mask_; } + // The register mask must be a subset of callee-save registers. + DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask); + + // Populate stack map information. + stack_map_stream_.RecordEnvironment(environment, + environment_size, + locations, + dex_pc, + pc_info.native_pc, + register_mask, + inlining_depth); } } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index b8f4572..b574148 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -29,8 +29,6 @@ namespace art { -static size_t constexpr kVRegSize = 4; - // Binary encoding of 2^32 for type double. static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000); // Binary encoding of 2^31 for type double. diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index 863bab2..3168801 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -20,6 +20,7 @@ #include "base/bit_vector.h" #include "base/value_object.h" #include "memory_region.h" +#include "nodes.h" #include "stack_map.h" #include "utils/growable_array.h" @@ -32,8 +33,9 @@ namespace art { class StackMapStream : public ValueObject { public: explicit StackMapStream(ArenaAllocator* allocator) - : stack_maps_(allocator, 10), - dex_register_maps_(allocator, 10 * 4), + : allocator_(allocator), + stack_maps_(allocator, 10), + dex_register_locations_(allocator, 10 * 4), inline_infos_(allocator, 2), stack_mask_max_(-1), number_of_stack_maps_with_inline_info_(0) {} @@ -52,8 +54,9 @@ class StackMapStream : public ValueObject { BitVector* sp_mask; uint32_t num_dex_registers; uint8_t inlining_depth; - size_t dex_register_maps_start_index; + size_t dex_register_locations_start_index; size_t inline_infos_start_index; + BitVector* live_dex_registers_mask; }; struct InlineInfoEntry { @@ -65,7 +68,8 @@ class StackMapStream : public ValueObject { uint32_t register_mask, BitVector* sp_mask, uint32_t num_dex_registers, - uint8_t inlining_depth) { + uint8_t inlining_depth, + BitVector* live_dex_registers_mask) { StackMapEntry entry; entry.dex_pc = dex_pc; entry.native_pc_offset = native_pc_offset; @@ -73,8 +77,9 @@ class StackMapStream : public ValueObject { entry.sp_mask = sp_mask; entry.num_dex_registers = num_dex_registers; entry.inlining_depth = inlining_depth; - entry.dex_register_maps_start_index = dex_register_maps_.Size(); + entry.dex_register_locations_start_index = dex_register_locations_.Size(); entry.inline_infos_start_index = inline_infos_.Size(); + entry.live_dex_registers_mask = live_dex_registers_mask; stack_maps_.Add(entry); if (sp_mask != nullptr) { @@ -85,11 +90,146 @@ class StackMapStream : public ValueObject { } } - void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) { - // Ensure we only use non-compressed location kind at this stage. - DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) - << DexRegisterLocation::PrettyDescriptor(kind); - dex_register_maps_.Add(DexRegisterLocation(kind, value)); + void RecordEnvironment(HEnvironment* environment, + size_t environment_size, + LocationSummary* locations, + uint32_t dex_pc, + uint32_t native_pc, + uint32_t register_mask, + uint32_t inlining_depth) { + if (environment == nullptr) { + // For stack overflow checks. + AddStackMapEntry(dex_pc, native_pc, 0, 0, 0, inlining_depth, nullptr); + return; + } + + BitVector* live_dex_registers_mask = new (allocator_) ArenaBitVector(allocator_, 0, true); + + AddStackMapEntry( + dex_pc, native_pc, register_mask, + locations->GetStackMask(), environment_size, inlining_depth, live_dex_registers_mask); + + // Walk over the environment, and record the location of dex registers. + for (size_t i = 0; i < environment_size; ++i) { + HInstruction* current = environment->GetInstructionAt(i); + if (current == nullptr) { + // No need to store anything, the `live_dex_registers_mask` will hold the + // information that this register is not live. + continue; + } + + Location location = locations->GetEnvironmentAt(i); + switch (location.GetKind()) { + case Location::kConstant: { + DCHECK_EQ(current, location.GetConstant()); + if (current->IsLongConstant()) { + // TODO: Consider moving setting the bit in AddDexRegisterEntry to avoid + // doing it manually here. + live_dex_registers_mask->SetBit(i); + live_dex_registers_mask->SetBit(i + 1); + int64_t value = current->AsLongConstant()->GetValue(); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value)); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value)); + ++i; + DCHECK_LT(i, environment_size); + } else if (current->IsDoubleConstant()) { + live_dex_registers_mask->SetBit(i); + live_dex_registers_mask->SetBit(i + 1); + int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue()); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value)); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value)); + ++i; + DCHECK_LT(i, environment_size); + } else if (current->IsIntConstant()) { + live_dex_registers_mask->SetBit(i); + int32_t value = current->AsIntConstant()->GetValue(); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value); + } else if (current->IsNullConstant()) { + live_dex_registers_mask->SetBit(i); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0); + } else { + DCHECK(current->IsFloatConstant()) << current->DebugName(); + live_dex_registers_mask->SetBit(i); + int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue()); + AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value); + } + break; + } + + case Location::kStackSlot: { + live_dex_registers_mask->SetBit(i); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, + location.GetStackIndex()); + break; + } + + case Location::kDoubleStackSlot: { + live_dex_registers_mask->SetBit(i); + live_dex_registers_mask->SetBit(i + 1); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, location.GetStackIndex()); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, + location.GetHighStackIndex(kVRegSize)); + ++i; + DCHECK_LT(i, environment_size); + break; + } + + case Location::kRegister : { + live_dex_registers_mask->SetBit(i); + int id = location.reg(); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id); + if (current->GetType() == Primitive::kPrimLong) { + live_dex_registers_mask->SetBit(i + 1); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id); + ++i; + DCHECK_LT(i, environment_size); + } + break; + } + + case Location::kFpuRegister : { + live_dex_registers_mask->SetBit(i); + int id = location.reg(); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id); + if (current->GetType() == Primitive::kPrimDouble) { + live_dex_registers_mask->SetBit(i + 1); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id); + ++i; + DCHECK_LT(i, environment_size); + } + break; + } + + case Location::kFpuRegisterPair : { + live_dex_registers_mask->SetBit(i); + live_dex_registers_mask->SetBit(i + 1); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.low()); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.high()); + ++i; + DCHECK_LT(i, environment_size); + break; + } + + case Location::kRegisterPair : { + live_dex_registers_mask->SetBit(i); + live_dex_registers_mask->SetBit(i + 1); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.low()); + AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.high()); + ++i; + DCHECK_LT(i, environment_size); + break; + } + + case Location::kInvalid: { + // No need to store anything, the `live_dex_registers_mask` will hold the + // information that this register is not live. + break; + } + + default: + LOG(FATAL) << "Unexpected kind " << location.GetKind(); + } + } } void AddInlineInfoEntry(uint32_t method_index) { @@ -118,22 +258,26 @@ class StackMapStream : public ValueObject { // Compute the size of the Dex register map of `entry`. size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const { size_t size = DexRegisterMap::kFixedSize; - for (size_t j = 0; j < entry.num_dex_registers; ++j) { - DexRegisterLocation dex_register_location = - dex_register_maps_.Get(entry.dex_register_maps_start_index + j); - size += DexRegisterMap::EntrySize(dex_register_location); + // Add the bit mask for the dex register liveness. + size += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers); + 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)) { + DexRegisterLocation dex_register_location = dex_register_locations_.Get( + entry.dex_register_locations_start_index + index_in_dex_register_locations); + size += DexRegisterMap::EntrySize(dex_register_location); + index_in_dex_register_locations++; + } } return size; } // Compute the size of all the Dex register maps. size_t ComputeDexRegisterMapsSize() const { - size_t size = stack_maps_.Size() * DexRegisterMap::kFixedSize; - // The size of each register location depends on the type of - // the entry. - for (size_t i = 0, e = dex_register_maps_.Size(); i < e; ++i) { - DexRegisterLocation entry = dex_register_maps_.Get(i); - size += DexRegisterMap::EntrySize(entry); + size_t size = 0; + for (size_t i = 0; i < stack_maps_.Size(); ++i) { + size += ComputeDexRegisterMapSize(stack_maps_.Get(i)); } return size; } @@ -161,7 +305,7 @@ class StackMapStream : public ValueObject { size_t stack_mask_size = ComputeStackMaskSize(); uint8_t* memory_start = region.start(); - MemoryRegion dex_register_maps_region = region.Subregion( + MemoryRegion dex_register_locations_region = region.Subregion( ComputeDexRegisterMapsStart(), ComputeDexRegisterMapsSize()); @@ -189,7 +333,7 @@ class StackMapStream : public ValueObject { if (entry.num_dex_registers != 0) { // Set the Dex register map. MemoryRegion register_region = - dex_register_maps_region.Subregion( + dex_register_locations_region.Subregion( next_dex_register_map_offset, ComputeDexRegisterMapSize(entry)); next_dex_register_map_offset += register_region.size(); @@ -198,11 +342,20 @@ class StackMapStream : public ValueObject { // Offset in `dex_register_map` where to store the next register entry. size_t offset = DexRegisterMap::kFixedSize; - for (size_t j = 0; j < entry.num_dex_registers; ++j) { - DexRegisterLocation dex_register_location = - dex_register_maps_.Get(entry.dex_register_maps_start_index + j); - dex_register_map.SetRegisterInfo(offset, dex_register_location); - offset += DexRegisterMap::EntrySize(dex_register_location); + dex_register_map.SetLiveBitMask(offset, + entry.num_dex_registers, + *entry.live_dex_registers_mask); + offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers); + 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)) { + DexRegisterLocation dex_register_location = dex_register_locations_.Get( + entry.dex_register_locations_start_index + index_in_dex_register_locations); + dex_register_map.SetRegisterInfo(offset, dex_register_location); + offset += DexRegisterMap::EntrySize(dex_register_location); + ++index_in_dex_register_locations; + } } // Ensure we reached the end of the Dex registers region. DCHECK_EQ(offset, register_region.size()); @@ -232,12 +385,24 @@ class StackMapStream : public ValueObject { } private: + void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) { + // Ensure we only use non-compressed location kind at this stage. + DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) + << DexRegisterLocation::PrettyDescriptor(kind); + dex_register_locations_.Add(DexRegisterLocation(kind, value)); + } + + ArenaAllocator* allocator_; GrowableArray<StackMapEntry> stack_maps_; - GrowableArray<DexRegisterLocation> dex_register_maps_; + GrowableArray<DexRegisterLocation> dex_register_locations_; GrowableArray<InlineInfoEntry> inline_infos_; int stack_mask_max_; size_t number_of_stack_maps_with_inline_info_; + ART_FRIEND_TEST(StackMapTest, Test1); + ART_FRIEND_TEST(StackMapTest, Test2); + ART_FRIEND_TEST(StackMapTest, TestNonLiveDexRegisters); + DISALLOW_COPY_AND_ASSIGN(StackMapStream); }; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 3a5f806..4606bd6 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -31,19 +31,17 @@ static bool SameBits(MemoryRegion region, const BitVector& bit_vector) { return true; } -static size_t ComputeDexRegisterMapSize(const DexRegisterMap& dex_registers, - size_t number_of_dex_registers) { - return dex_registers.FindLocationOffset(number_of_dex_registers); -} - TEST(StackMapTest, Test1) { ArenaPool pool; ArenaAllocator arena(&pool); StackMapStream stream(&arena); ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector live_registers_mask(&arena, 0, true); + live_registers_mask.SetBit(0); + live_registers_mask.SetBit(1); size_t number_of_dex_registers = 2; - stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0); + stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0, &live_registers_mask); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, 0); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2); @@ -68,10 +66,9 @@ TEST(StackMapTest, Test1) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); - ASSERT_EQ(6u, dex_registers.Size()); - ASSERT_EQ(6u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers)); - DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0); - DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1); + ASSERT_EQ(7u, dex_registers.Size()); + DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0, number_of_dex_registers); + DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1, number_of_dex_registers); ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kConstant, location1.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetInternalKind()); @@ -91,7 +88,10 @@ TEST(StackMapTest, Test2) { sp_mask1.SetBit(2); sp_mask1.SetBit(4); size_t number_of_dex_registers = 2; - stream.AddStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2); + ArenaBitVector live_registers_mask1(&arena, 0, true); + live_registers_mask1.SetBit(0); + live_registers_mask1.SetBit(1); + stream.AddStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2, &live_registers_mask1); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, 0); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2); stream.AddInlineInfoEntry(42); @@ -100,7 +100,10 @@ TEST(StackMapTest, Test2) { ArenaBitVector sp_mask2(&arena, 0, true); sp_mask2.SetBit(3); sp_mask1.SetBit(8); - stream.AddStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0); + ArenaBitVector live_registers_mask2(&arena, 0, true); + live_registers_mask2.SetBit(0); + live_registers_mask2.SetBit(1); + stream.AddStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0, &live_registers_mask2); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, 18); stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, 3); @@ -128,10 +131,11 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); - ASSERT_EQ(6u, dex_registers.Size()); - ASSERT_EQ(6u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers)); - DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0); - DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1); + ASSERT_EQ(7u, dex_registers.Size()); + DexRegisterLocation location0 = + dex_registers.GetLocationKindAndValue(0, number_of_dex_registers); + DexRegisterLocation location1 = + dex_registers.GetLocationKindAndValue(1, number_of_dex_registers); ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kConstant, location1.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kInStack, location0.GetInternalKind()); @@ -161,10 +165,11 @@ TEST(StackMapTest, Test2) { ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); - ASSERT_EQ(2u, dex_registers.Size()); - ASSERT_EQ(2u, ComputeDexRegisterMapSize(dex_registers, number_of_dex_registers)); - DexRegisterLocation location0 = dex_registers.GetLocationKindAndValue(0); - DexRegisterLocation location1 = dex_registers.GetLocationKindAndValue(1); + ASSERT_EQ(3u, dex_registers.Size()); + DexRegisterLocation location0 = + dex_registers.GetLocationKindAndValue(0, number_of_dex_registers); + DexRegisterLocation location1 = + dex_registers.GetLocationKindAndValue(1, number_of_dex_registers); ASSERT_EQ(DexRegisterLocation::Kind::kInRegister, location0.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kInFpuRegister, location1.GetKind()); ASSERT_EQ(DexRegisterLocation::Kind::kInRegister, location0.GetInternalKind()); @@ -176,4 +181,33 @@ TEST(StackMapTest, Test2) { } } +TEST(StackMapTest, TestNonLiveDexRegisters) { + ArenaPool pool; + ArenaAllocator arena(&pool); + StackMapStream stream(&arena); + + ArenaBitVector sp_mask(&arena, 0, false); + ArenaBitVector live_registers_mask(&arena, 0, true); + live_registers_mask.SetBit(1); + uint32_t number_of_dex_registers = 2; + stream.AddStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0, &live_registers_mask); + stream.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, -2); + + size_t size = stream.ComputeNeededSize(); + void* memory = arena.Alloc(size, kArenaAllocMisc); + MemoryRegion region(memory, size); + stream.FillIn(region); + + CodeInfo code_info(region); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); + DexRegisterMap dex_registers = code_info.GetDexRegisterMapOf(stack_map, 2); + ASSERT_EQ(DexRegisterLocation::Kind::kNone, + dex_registers.GetLocationKind(0, number_of_dex_registers)); + ASSERT_EQ(DexRegisterLocation::Kind::kConstant, + dex_registers.GetLocationKind(1, number_of_dex_registers)); + ASSERT_EQ(-2, dex_registers.GetConstant(1, number_of_dex_registers)); + ASSERT_FALSE(stack_map.HasInlineInfo()); +} + } // namespace art diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 9512376..344d2b5 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1084,9 +1084,13 @@ class OatDumper { if (stack_map.HasDexRegisterMap()) { DexRegisterMap dex_register_map = code_info.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) { - DexRegisterLocation location = dex_register_map.GetLocationKindAndValue(j); - DumpRegisterMapping(os, j, location.GetInternalKind(), location.GetValue()); + if (dex_register_map.IsDexRegisterLive(j)) { + DexRegisterLocation location = + dex_register_map.GetLocationKindAndValue(j, number_of_dex_registers); + DumpRegisterMapping(os, j, location.GetInternalKind(), location.GetValue()); + } } } } diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index 893ab11..0ec0295 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -66,14 +66,16 @@ class CheckReferenceMapVisitor : public StackVisitor { mirror::ArtMethod* m = GetMethod(); CodeInfo code_info = m->GetOptimizedCodeInfo(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); + uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_; DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, m->GetCodeItem()->registers_size_); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); MemoryRegion stack_mask = stack_map.GetStackMask(); uint32_t register_mask = stack_map.GetRegisterMask(); for (int i = 0; i < number_of_references; ++i) { int reg = registers[i]; CHECK(reg < m->GetCodeItem()->registers_size_); - DexRegisterLocation location = dex_register_map.GetLocationKindAndValue(reg); + DexRegisterLocation location = + dex_register_map.GetLocationKindAndValue(reg, number_of_dex_registers); switch (location.GetKind()) { case DexRegisterLocation::Kind::kNone: // Not set, should not be a reference. diff --git a/runtime/stack.cc b/runtime/stack.cc index 47b85ad..2d688ee 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -202,30 +202,33 @@ bool StackVisitor::GetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, 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, code_item->registers_size_); - DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); + DexRegisterLocation::Kind location_kind = + dex_register_map.GetLocationKind(vreg, number_of_dex_registers); switch (location_kind) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg); + const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers); const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; *val = *reinterpret_cast<const uint32_t*>(addr); return true; } case DexRegisterLocation::Kind::kInRegister: case DexRegisterLocation::Kind::kInFpuRegister: { - uint32_t reg = dex_register_map.GetMachineRegister(vreg); + uint32_t reg = dex_register_map.GetMachineRegister(vreg, number_of_dex_registers); return GetRegisterIfAccessible(reg, kind, val); } case DexRegisterLocation::Kind::kConstant: - *val = dex_register_map.GetConstant(vreg); + *val = dex_register_map.GetConstant(vreg, number_of_dex_registers); return true; case DexRegisterLocation::Kind::kNone: return false; default: LOG(FATAL) << "Unexpected location kind" - << DexRegisterLocation::PrettyDescriptor(dex_register_map.GetLocationInternalKind(vreg)); + << DexRegisterLocation::PrettyDescriptor( + dex_register_map.GetLocationInternalKind(vreg, number_of_dex_registers)); UNREACHABLE(); } } @@ -388,21 +391,23 @@ bool StackVisitor::SetVRegFromOptimizedCode(mirror::ArtMethod* m, uint16_t vreg, 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_; + DCHECK_LT(vreg, number_of_dex_registers); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, code_item->registers_size_); - DexRegisterLocation::Kind location_kind = dex_register_map.GetLocationKind(vreg); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); + DexRegisterLocation::Kind location_kind = + dex_register_map.GetLocationKind(vreg, number_of_dex_registers); uint32_t dex_pc = m->ToDexPc(cur_quick_frame_pc_, false); switch (location_kind) { case DexRegisterLocation::Kind::kInStack: { - const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg); + const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers); uint8_t* addr = reinterpret_cast<uint8_t*>(cur_quick_frame_) + offset; *reinterpret_cast<uint32_t*>(addr) = new_value; return true; } case DexRegisterLocation::Kind::kInRegister: case DexRegisterLocation::Kind::kInFpuRegister: { - uint32_t reg = dex_register_map.GetMachineRegister(vreg); + uint32_t reg = dex_register_map.GetMachineRegister(vreg, number_of_dex_registers); return SetRegisterIfAccessible(reg, new_value, kind); } case DexRegisterLocation::Kind::kConstant: diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 8ebafc5..0db589f 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -31,6 +31,9 @@ static ssize_t constexpr kFrameSlotSize = 4; // Word alignment required on ARM, in bytes. static constexpr size_t kWordAlignment = 4; +// Size of Dex virtual registers. +static size_t constexpr kVRegSize = 4; + /** * Classes in the following file are wrapper on stack map information backed * by a MemoryRegion. As such they read and write to the region, they don't have @@ -191,6 +194,10 @@ class DexRegisterLocation { DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {} + static DexRegisterLocation None() { + return DexRegisterLocation(Kind::kNone, 0); + } + // Get the "surface" kind of the location, i.e., the one that doesn't // include any value with a "large" qualifier. Kind GetKind() const { @@ -211,8 +218,8 @@ class DexRegisterLocation { /** * Information on dex register values for a specific PC. The information is * of the form: - * [location_kind, register_value]+. - * either on 1 or 5 bytes (see art::DexRegisterLocation::Kind). + * [live_bit_mask, DexRegisterLocation+]. + * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind). */ class DexRegisterMap { public: @@ -221,6 +228,18 @@ class DexRegisterMap { // Short (compressed) location, fitting on one byte. typedef uint8_t ShortLocation; + static size_t LiveBitMaskSize(uint16_t number_of_dex_registers) { + return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte; + } + + void SetLiveBitMask(size_t offset, + uint16_t number_of_dex_registers, + const BitVector& live_dex_registers_mask) { + for (uint16_t i = 0; i < number_of_dex_registers; i++) { + region_.StoreBit(offset + i, live_dex_registers_mask.IsBitSet(i)); + } + } + void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) { DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location); int32_t value = dex_register_location.GetValue(); @@ -256,39 +275,63 @@ class DexRegisterMap { } } - // Find the offset of the Dex register location number `dex_register_index`. - size_t FindLocationOffset(uint16_t dex_register_index) const { + bool IsDexRegisterLive(uint16_t dex_register_index) const { size_t offset = kFixedSize; + return region_.LoadBit(offset + dex_register_index); + } + + static constexpr size_t kNoDexRegisterLocationOffset = -1; + + static size_t GetDexRegisterMapLocationsOffset(uint16_t number_of_dex_registers) { + return kLiveBitMaskOffset + LiveBitMaskSize(number_of_dex_registers); + } + + // Find the offset of the Dex register location number `dex_register_index`. + size_t FindLocationOffset(uint16_t dex_register_index, uint16_t number_of_dex_registers) const { + if (!IsDexRegisterLive(dex_register_index)) return kNoDexRegisterLocationOffset; + size_t offset = GetDexRegisterMapLocationsOffset(number_of_dex_registers); // Skip the first `dex_register_index - 1` entries. for (uint16_t i = 0; i < dex_register_index; ++i) { - // Read the first next byte and inspect its first 3 bits to decide - // whether it is a short or a large location. - DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Skip the current byte. - offset += SingleShortEntrySize(); - } else { - // Large location. Skip the 5 next bytes. - offset += SingleLargeEntrySize(); + if (IsDexRegisterLive(i)) { + // Read the first next byte and inspect its first 3 bits to decide + // whether it is a short or a large location. + DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset); + if (DexRegisterLocation::IsShortLocationKind(kind)) { + // Short location. Skip the current byte. + offset += SingleShortEntrySize(); + } else { + // Large location. Skip the 5 next bytes. + offset += SingleLargeEntrySize(); + } } } return offset; } // Get the surface kind. - DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index) const { - return DexRegisterLocation::ConvertToSurfaceKind(GetLocationInternalKind(dex_register_index)); + DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index, + uint16_t number_of_dex_registers) const { + return IsDexRegisterLive(dex_register_index) + ? DexRegisterLocation::ConvertToSurfaceKind( + GetLocationInternalKind(dex_register_index, number_of_dex_registers)) + : DexRegisterLocation::Kind::kNone; } // Get the internal kind. - DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index) const { - size_t offset = FindLocationOffset(dex_register_index); - return ExtractKindAtOffset(offset); + DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index, + uint16_t number_of_dex_registers) const { + return IsDexRegisterLive(dex_register_index) + ? ExtractKindAtOffset(FindLocationOffset(dex_register_index, number_of_dex_registers)) + : DexRegisterLocation::Kind::kNone; } // TODO: Rename as GetDexRegisterLocation? - DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index) const { - size_t offset = FindLocationOffset(dex_register_index); + DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index, + uint16_t number_of_dex_registers) const { + if (!IsDexRegisterLive(dex_register_index)) { + return DexRegisterLocation::None(); + } + size_t offset = FindLocationOffset(dex_register_index, number_of_dex_registers); // Read the first byte and inspect its first 3 bits to get the location. ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset); DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte); @@ -311,21 +354,25 @@ class DexRegisterMap { } } - int32_t GetStackOffsetInBytes(uint16_t dex_register_index) const { - DexRegisterLocation location = GetLocationKindAndValue(dex_register_index); + int32_t GetStackOffsetInBytes(uint16_t dex_register_index, + uint16_t number_of_dex_registers) const { + DexRegisterLocation location = + GetLocationKindAndValue(dex_register_index, number_of_dex_registers); DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack); // GetLocationKindAndValue returns the offset in bytes. return location.GetValue(); } - int32_t GetConstant(uint16_t dex_register_index) const { - DexRegisterLocation location = GetLocationKindAndValue(dex_register_index); + int32_t GetConstant(uint16_t dex_register_index, uint16_t number_of_dex_registers) const { + DexRegisterLocation location = + GetLocationKindAndValue(dex_register_index, number_of_dex_registers); DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant); return location.GetValue(); } - int32_t GetMachineRegister(uint16_t dex_register_index) const { - DexRegisterLocation location = GetLocationKindAndValue(dex_register_index); + int32_t GetMachineRegister(uint16_t dex_register_index, uint16_t number_of_dex_registers) const { + DexRegisterLocation location = + GetLocationKindAndValue(dex_register_index, number_of_dex_registers); DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister) << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind()); @@ -405,7 +452,8 @@ class DexRegisterMap { return region_.size(); } - static constexpr int kFixedSize = 0; + static constexpr int kLiveBitMaskOffset = 0; + static constexpr int kFixedSize = kLiveBitMaskOffset; private: // Width of the kind "field" in a short location, in bits. @@ -428,6 +476,8 @@ class DexRegisterMap { static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) { uint8_t kind = (location >> kKindOffset) & kKindMask; DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind)); + // We do not encode kNone locations in the stack map. + DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone)); return static_cast<DexRegisterLocation::Kind>(kind); } @@ -678,21 +728,28 @@ class CodeInfo { // TODO: Ideally, we would like to use art::DexRegisterMap::Size or // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not // yet built. Try to factor common code. - size_t offset = origin + DexRegisterMap::kFixedSize; + size_t offset = + origin + DexRegisterMap::GetDexRegisterMapLocationsOffset(number_of_dex_registers); + + // Create a temporary DexRegisterMap to be able to call DexRegisterMap.IsDexRegisterLive. + DexRegisterMap only_live_mask(MemoryRegion(region_.Subregion(origin, offset - origin))); + // Skip the first `number_of_dex_registers - 1` entries. for (uint16_t i = 0; i < number_of_dex_registers; ++i) { - // Read the first next byte and inspect its first 3 bits to decide - // whether it is a short or a large location. - DexRegisterMap::ShortLocation first_byte = - region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset); - DexRegisterLocation::Kind kind = - DexRegisterMap::ExtractKindFromShortLocation(first_byte); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Skip the current byte. - offset += DexRegisterMap::SingleShortEntrySize(); - } else { - // Large location. Skip the 5 next bytes. - offset += DexRegisterMap::SingleLargeEntrySize(); + if (only_live_mask.IsDexRegisterLive(i)) { + // Read the first next byte and inspect its first 3 bits to decide + // whether it is a short or a large location. + DexRegisterMap::ShortLocation first_byte = + region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset); + DexRegisterLocation::Kind kind = + DexRegisterMap::ExtractKindFromShortLocation(first_byte); + if (DexRegisterLocation::IsShortLocationKind(kind)) { + // Short location. Skip the current byte. + offset += DexRegisterMap::SingleShortEntrySize(); + } else { + // Large location. Skip the 5 next bytes. + offset += DexRegisterMap::SingleLargeEntrySize(); + } } } size_t size = offset - origin; |