blob: a73c8d77f3fd7d0bef70b85882ce30054d31ff44 [file] [log] [blame]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
18#define ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
19
Calin Juravle6ae70962015-03-18 16:31:28 +000020#include "base/arena_containers.h"
21#include "base/bit_vector-inl.h"
Ian Rogers0279ebb2014-10-08 17:27:48 -070022#include "base/value_object.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010023#include "memory_region.h"
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000024#include "nodes.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010025#include "stack_map.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010026#include "utils/growable_array.h"
27
28namespace art {
29
Roland Levillaina552e1c2015-03-26 15:01:03 +000030// Helper to build art::StackMapStream::LocationCatalogEntriesIndices.
31class LocationCatalogEntriesIndicesEmptyFn {
32 public:
33 void MakeEmpty(std::pair<DexRegisterLocation, size_t>& item) const {
34 item.first = DexRegisterLocation::None();
35 }
36 bool IsEmpty(const std::pair<DexRegisterLocation, size_t>& item) const {
37 return item.first == DexRegisterLocation::None();
38 }
39};
40
41// Hash function for art::StackMapStream::LocationCatalogEntriesIndices.
42// This hash function does not create collisions.
43class DexRegisterLocationHashFn {
44 public:
45 size_t operator()(DexRegisterLocation key) const {
46 // Concatenate `key`s fields to create a 64-bit value to be hashed.
47 int64_t kind_and_value =
48 (static_cast<int64_t>(key.kind_) << 32) | static_cast<int64_t>(key.value_);
49 return inner_hash_fn_(kind_and_value);
50 }
51 private:
52 std::hash<int64_t> inner_hash_fn_;
53};
54
55
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010056/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010057 * Collects and builds stack maps for a method. All the stack maps
58 * for a method are placed in a CodeInfo object.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010059 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010060class StackMapStream : public ValueObject {
61 public:
62 explicit StackMapStream(ArenaAllocator* allocator)
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000063 : allocator_(allocator),
64 stack_maps_(allocator, 10),
Roland Levillaina552e1c2015-03-26 15:01:03 +000065 location_catalog_entries_(allocator, 4),
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000066 dex_register_locations_(allocator, 10 * 4),
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010067 inline_infos_(allocator, 2),
Andreas Gampe8eddd2a2014-07-28 14:53:22 -070068 stack_mask_max_(-1),
Nicolas Geoffray004c2302015-03-20 10:06:38 +000069 dex_pc_max_(0),
70 native_pc_offset_max_(0),
Nicolas Geoffray896f8f72015-03-30 15:44:25 +010071 register_mask_max_(0),
Calin Juravle6ae70962015-03-18 16:31:28 +000072 number_of_stack_maps_with_inline_info_(0),
73 dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010074
75 // Compute bytes needed to encode a mask with the given maximum element.
76 static uint32_t StackMaskEncodingSize(int max_element) {
77 int number_of_bits = max_element + 1; // Need room for max element too.
78 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
79 }
80
81 // See runtime/stack_map.h to know what these fields contain.
82 struct StackMapEntry {
83 uint32_t dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010084 uint32_t native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010085 uint32_t register_mask;
86 BitVector* sp_mask;
87 uint32_t num_dex_registers;
88 uint8_t inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000089 size_t dex_register_locations_start_index;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010090 size_t inline_infos_start_index;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000091 BitVector* live_dex_registers_mask;
Calin Juravle6ae70962015-03-18 16:31:28 +000092 uint32_t dex_register_map_hash;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010093 };
94
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010095 struct InlineInfoEntry {
96 uint32_t method_index;
97 };
98
99 void AddStackMapEntry(uint32_t dex_pc,
Nicolas Geoffray39468442014-09-02 15:17:15 +0100100 uint32_t native_pc_offset,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100101 uint32_t register_mask,
102 BitVector* sp_mask,
103 uint32_t num_dex_registers,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000104 uint8_t inlining_depth) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100105 StackMapEntry entry;
106 entry.dex_pc = dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100107 entry.native_pc_offset = native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100108 entry.register_mask = register_mask;
109 entry.sp_mask = sp_mask;
110 entry.num_dex_registers = num_dex_registers;
111 entry.inlining_depth = inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000112 entry.dex_register_locations_start_index = dex_register_locations_.Size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100113 entry.inline_infos_start_index = inline_infos_.Size();
Calin Juravle6ae70962015-03-18 16:31:28 +0000114 entry.dex_register_map_hash = 0;
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000115 if (num_dex_registers != 0) {
116 entry.live_dex_registers_mask =
117 new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
118 } else {
119 entry.live_dex_registers_mask = nullptr;
120 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100121 stack_maps_.Add(entry);
122
Nicolas Geoffray39468442014-09-02 15:17:15 +0100123 if (sp_mask != nullptr) {
124 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
125 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100126 if (inlining_depth > 0) {
127 number_of_stack_maps_with_inline_info_++;
128 }
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000129
130 dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
131 native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100132 register_mask_max_ = std::max(register_mask_max_, register_mask);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100133 }
134
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100135 void AddInlineInfoEntry(uint32_t method_index) {
136 InlineInfoEntry entry;
137 entry.method_index = method_index;
138 inline_infos_.Add(entry);
139 }
140
Calin Juravle6ae70962015-03-18 16:31:28 +0000141 size_t ComputeNeededSize() {
Roland Levillainede7bf82015-03-13 12:23:04 +0000142 size_t size = CodeInfo::kFixedSize
Roland Levillaina552e1c2015-03-26 15:01:03 +0000143 + ComputeDexRegisterLocationCatalogSize()
Roland Levillain29ba1b02015-03-13 11:45:07 +0000144 + ComputeStackMapsSize()
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000145 + ComputeDexRegisterMapsSize()
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100146 + ComputeInlineInfoSize();
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000147 // Note: use RoundUp to word-size here if you want CodeInfo objects to be word aligned.
148 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100149 }
150
Roland Levillain29ba1b02015-03-13 11:45:07 +0000151 size_t ComputeStackMaskSize() const {
152 return StackMaskEncodingSize(stack_mask_max_);
153 }
154
Calin Juravle6ae70962015-03-18 16:31:28 +0000155 size_t ComputeStackMapsSize() {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000156 return stack_maps_.Size() * StackMap::ComputeStackMapSize(
157 ComputeStackMaskSize(),
158 ComputeInlineInfoSize(),
159 ComputeDexRegisterMapsSize(),
160 dex_pc_max_,
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100161 native_pc_offset_max_,
162 register_mask_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100163 }
164
Roland Levillaina552e1c2015-03-26 15:01:03 +0000165 // Compute the size of the Dex register location catalog of `entry`.
166 size_t ComputeDexRegisterLocationCatalogSize() const {
167 size_t size = DexRegisterLocationCatalog::kFixedSize;
168 for (size_t location_catalog_entry_index = 0;
169 location_catalog_entry_index < location_catalog_entries_.Size();
170 ++location_catalog_entry_index) {
171 DexRegisterLocation dex_register_location =
172 location_catalog_entries_.Get(location_catalog_entry_index);
173 size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
174 }
175 return size;
176 }
177
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000178 size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000179 // Size of the map in bytes.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000180 size_t size = DexRegisterMap::kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000181 // Add the live bit mask for the Dex register liveness.
182 size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
183 // Compute the size of the set of live Dex register entries.
184 size_t number_of_live_dex_registers = 0;
185 for (size_t dex_register_number = 0;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000186 dex_register_number < entry.num_dex_registers;
187 ++dex_register_number) {
188 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000189 ++number_of_live_dex_registers;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000190 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000191 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000192 size_t map_entries_size_in_bits =
193 DexRegisterMap::SingleEntrySizeInBits(location_catalog_entries_.Size())
194 * number_of_live_dex_registers;
195 size_t map_entries_size_in_bytes =
196 RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
197 size += map_entries_size_in_bytes;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000198 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100199 }
200
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000201 // Compute the size of all the Dex register maps.
Calin Juravle6ae70962015-03-18 16:31:28 +0000202 size_t ComputeDexRegisterMapsSize() {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000203 size_t size = 0;
204 for (size_t i = 0; i < stack_maps_.Size(); ++i) {
Calin Juravle6ae70962015-03-18 16:31:28 +0000205 if (FindEntryWithTheSameDexMap(i) == kNoSameDexMapFound) {
206 // Entries with the same dex map will have the same offset.
207 size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
208 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000209 }
Roland Levillainede7bf82015-03-13 12:23:04 +0000210 return size;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000211 }
212
213 // Compute the size of all the inline information pieces.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100214 size_t ComputeInlineInfoSize() const {
215 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
216 // For encoding the depth.
217 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
218 }
219
Roland Levillaina552e1c2015-03-26 15:01:03 +0000220 size_t ComputeDexRegisterLocationCatalogStart() const {
221 return CodeInfo::kFixedSize;
222 }
223
224 size_t ComputeStackMapsStart() const {
225 return ComputeDexRegisterLocationCatalogStart() + ComputeDexRegisterLocationCatalogSize();
226 }
227
Calin Juravle6ae70962015-03-18 16:31:28 +0000228 size_t ComputeDexRegisterMapsStart() {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000229 return ComputeStackMapsStart() + ComputeStackMapsSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100230 }
231
Calin Juravle6ae70962015-03-18 16:31:28 +0000232 size_t ComputeInlineInfoStart() {
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000233 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000234 }
235
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100236 void FillIn(MemoryRegion region) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100237 CodeInfo code_info(region);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000238 DCHECK_EQ(region.size(), ComputeNeededSize());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100239 code_info.SetOverallSize(region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100240
Roland Levillain29ba1b02015-03-13 11:45:07 +0000241 size_t stack_mask_size = ComputeStackMaskSize();
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000242
243 size_t dex_register_map_size = ComputeDexRegisterMapsSize();
244 size_t inline_info_size = ComputeInlineInfoSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100245
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000246 MemoryRegion dex_register_locations_region = region.Subregion(
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000247 ComputeDexRegisterMapsStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000248 dex_register_map_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100249
250 MemoryRegion inline_infos_region = region.Subregion(
251 ComputeInlineInfoStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000252 inline_info_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100253
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100254 code_info.SetEncoding(inline_info_size,
255 dex_register_map_size,
256 dex_pc_max_,
257 native_pc_offset_max_,
258 register_mask_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100259 code_info.SetNumberOfStackMaps(stack_maps_.Size());
260 code_info.SetStackMaskSize(stack_mask_size);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000261 DCHECK_EQ(code_info.GetStackMapsSize(), ComputeStackMapsSize());
262
263 // Set the Dex register location catalog.
264 code_info.SetNumberOfDexRegisterLocationCatalogEntries(
265 location_catalog_entries_.Size());
266 MemoryRegion dex_register_location_catalog_region = region.Subregion(
267 ComputeDexRegisterLocationCatalogStart(),
268 ComputeDexRegisterLocationCatalogSize());
269 DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
270 // Offset in `dex_register_location_catalog` where to store the next
271 // register location.
272 size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
273 for (size_t i = 0, e = location_catalog_entries_.Size(); i < e; ++i) {
274 DexRegisterLocation dex_register_location = location_catalog_entries_.Get(i);
275 dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
276 location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
277 }
278 // Ensure we reached the end of the Dex registers location_catalog.
279 DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100280
281 uintptr_t next_dex_register_map_offset = 0;
282 uintptr_t next_inline_info_offset = 0;
283 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100284 StackMap stack_map = code_info.GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100285 StackMapEntry entry = stack_maps_.Get(i);
286
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000287 stack_map.SetDexPc(code_info, entry.dex_pc);
288 stack_map.SetNativePcOffset(code_info, entry.native_pc_offset);
289 stack_map.SetRegisterMask(code_info, entry.register_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100290 if (entry.sp_mask != nullptr) {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000291 stack_map.SetStackMask(code_info, *entry.sp_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100292 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100293
Calin Juravle6ae70962015-03-18 16:31:28 +0000294 if (entry.num_dex_registers == 0) {
295 // No dex map available.
296 stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
297 } else {
298 // Search for an entry with the same dex map.
299 size_t entry_with_same_map = FindEntryWithTheSameDexMap(i);
300 if (entry_with_same_map != kNoSameDexMapFound) {
301 // If we have a hit reuse the offset.
302 stack_map.SetDexRegisterMapOffset(code_info,
303 code_info.GetStackMapAt(entry_with_same_map).GetDexRegisterMapOffset(code_info));
304 } else {
305 // New dex registers maps should be added to the stack map.
306 MemoryRegion register_region =
307 dex_register_locations_region.Subregion(
308 next_dex_register_map_offset,
309 ComputeDexRegisterMapSize(entry));
310 next_dex_register_map_offset += register_region.size();
311 DexRegisterMap dex_register_map(register_region);
312 stack_map.SetDexRegisterMapOffset(
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000313 code_info, register_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100314
Roland Levillaina552e1c2015-03-26 15:01:03 +0000315 // Set the live bit mask.
316 dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
317
318 // Set the dex register location mapping data.
Calin Juravle6ae70962015-03-18 16:31:28 +0000319 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
320 dex_register_number < entry.num_dex_registers;
321 ++dex_register_number) {
322 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000323 size_t location_catalog_entry_index =
324 dex_register_locations_.Get(entry.dex_register_locations_start_index
325 + index_in_dex_register_locations);
326 dex_register_map.SetLocationCatalogEntryIndex(
327 index_in_dex_register_locations,
328 location_catalog_entry_index,
329 entry.num_dex_registers,
330 location_catalog_entries_.Size());
Calin Juravle6ae70962015-03-18 16:31:28 +0000331 ++index_in_dex_register_locations;
332 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000333 }
Roland Levillain442b46a2015-02-18 16:54:21 +0000334 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100335 }
336
337 // Set the inlining info.
338 if (entry.inlining_depth != 0) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800339 MemoryRegion inline_region = inline_infos_region.Subregion(
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100340 next_inline_info_offset,
341 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800342 next_inline_info_offset += inline_region.size();
343 InlineInfo inline_info(inline_region);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100344
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000345 // Currently relative to the dex register map.
346 stack_map.SetInlineDescriptorOffset(
347 code_info, inline_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100348
349 inline_info.SetDepth(entry.inlining_depth);
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800350 for (size_t j = 0; j < entry.inlining_depth; ++j) {
351 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
352 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100353 }
354 } else {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000355 if (inline_info_size != 0) {
356 stack_map.SetInlineDescriptorOffset(code_info, StackMap::kNoInlineInfo);
357 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100358 }
359 }
360 }
361
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000362 void AddDexRegisterEntry(uint16_t dex_register, DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000363 StackMapEntry entry = stack_maps_.Get(stack_maps_.Size() - 1);
364 DCHECK_LT(dex_register, entry.num_dex_registers);
365
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000366 if (kind != DexRegisterLocation::Kind::kNone) {
367 // Ensure we only use non-compressed location kind at this stage.
368 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
369 << DexRegisterLocation::PrettyDescriptor(kind);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000370 DexRegisterLocation location(kind, value);
371
372 // Look for Dex register `location` in the location catalog (using the
373 // companion hash map of locations to indices). Use its index if it
374 // is already in the location catalog. If not, insert it (in the
375 // location catalog and the hash map) and use the newly created index.
376 auto it = location_catalog_entries_indices_.Find(location);
377 if (it != location_catalog_entries_indices_.end()) {
378 // Retrieve the index from the hash map.
379 dex_register_locations_.Add(it->second);
380 } else {
381 // Create a new entry in the location catalog and the hash map.
382 size_t index = location_catalog_entries_.Size();
383 location_catalog_entries_.Add(location);
384 dex_register_locations_.Add(index);
385 location_catalog_entries_indices_.Insert(std::make_pair(location, index));
386 }
387
Calin Juravle6ae70962015-03-18 16:31:28 +0000388 entry.live_dex_registers_mask->SetBit(dex_register);
389 entry.dex_register_map_hash += (1 << dex_register);
390 entry.dex_register_map_hash += static_cast<uint32_t>(value);
391 entry.dex_register_map_hash += static_cast<uint32_t>(kind);
392 stack_maps_.Put(stack_maps_.Size() - 1, entry);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000393 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000394 }
395
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000396 private:
Calin Juravle6ae70962015-03-18 16:31:28 +0000397 // Returns the index of an entry with the same dex register map
398 // or kNoSameDexMapFound if no such entry exists.
399 size_t FindEntryWithTheSameDexMap(size_t entry_index) {
400 StackMapEntry entry = stack_maps_.Get(entry_index);
401 auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.dex_register_map_hash);
402 if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
403 // We don't have a perfect hash functions so we need a list to collect all stack maps
404 // which might have the same dex register map.
405 GrowableArray<uint32_t> stack_map_indices(allocator_, 1);
406 stack_map_indices.Add(entry_index);
407 dex_map_hash_to_stack_map_indices_.Put(entry.dex_register_map_hash, stack_map_indices);
408 return kNoSameDexMapFound;
409 }
410
411 // TODO: We don't need to add ourselves to the map if we can guarantee that
412 // FindEntryWithTheSameDexMap is called just once per stack map entry.
413 // A good way to do this is to cache the offset in the stack map entry. This
414 // is easier to do if we add markers when the stack map constructions begins
415 // and when it ends.
416
417 // We might have collisions, so we need to check whether or not we should
418 // add the entry to the map. `needs_to_be_added` keeps track of this.
419 bool needs_to_be_added = true;
420 size_t result = kNoSameDexMapFound;
421 for (size_t i = 0; i < entries_it->second.Size(); i++) {
422 size_t test_entry_index = entries_it->second.Get(i);
423 if (test_entry_index == entry_index) {
424 needs_to_be_added = false;
425 } else if (HaveTheSameDexMaps(stack_maps_.Get(test_entry_index), entry)) {
426 result = test_entry_index;
427 needs_to_be_added = false;
428 break;
429 }
430 }
431 if (needs_to_be_added) {
432 entries_it->second.Add(entry_index);
433 }
434 return result;
435 }
436
437 bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const {
438 if (a.live_dex_registers_mask == nullptr && b.live_dex_registers_mask == nullptr) {
439 return true;
440 }
441 if (a.live_dex_registers_mask == nullptr || b.live_dex_registers_mask == nullptr) {
442 return false;
443 }
444 if (a.num_dex_registers != b.num_dex_registers) {
445 return false;
446 }
447
448 int index_in_dex_register_locations = 0;
449 for (uint32_t i = 0; i < a.num_dex_registers; i++) {
450 if (a.live_dex_registers_mask->IsBitSet(i) != b.live_dex_registers_mask->IsBitSet(i)) {
451 return false;
452 }
453 if (a.live_dex_registers_mask->IsBitSet(i)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000454 size_t a_loc = dex_register_locations_.Get(
Calin Juravle6ae70962015-03-18 16:31:28 +0000455 a.dex_register_locations_start_index + index_in_dex_register_locations);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000456 size_t b_loc = dex_register_locations_.Get(
Calin Juravle6ae70962015-03-18 16:31:28 +0000457 b.dex_register_locations_start_index + index_in_dex_register_locations);
458 if (a_loc != b_loc) {
459 return false;
460 }
461 ++index_in_dex_register_locations;
462 }
463 }
464 return true;
465 }
466
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000467 ArenaAllocator* allocator_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100468 GrowableArray<StackMapEntry> stack_maps_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000469
470 // A catalog of unique [location_kind, register_value] pairs (per method).
471 GrowableArray<DexRegisterLocation> location_catalog_entries_;
472 // Map from Dex register location catalog entries to their indices in the
473 // location catalog.
474 typedef HashMap<DexRegisterLocation, size_t, LocationCatalogEntriesIndicesEmptyFn,
475 DexRegisterLocationHashFn> LocationCatalogEntriesIndices;
476 LocationCatalogEntriesIndices location_catalog_entries_indices_;
477
478 // A set of concatenated maps of Dex register locations indices to
479 // `location_catalog_entries_`.
480 GrowableArray<size_t> dex_register_locations_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100481 GrowableArray<InlineInfoEntry> inline_infos_;
482 int stack_mask_max_;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000483 uint32_t dex_pc_max_;
484 uint32_t native_pc_offset_max_;
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100485 uint32_t register_mask_max_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100486 size_t number_of_stack_maps_with_inline_info_;
487
Calin Juravle6ae70962015-03-18 16:31:28 +0000488 ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
489
490 static constexpr uint32_t kNoSameDexMapFound = -1;
491
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100492 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
493};
494
495} // namespace art
496
497#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_