blob: b77e60471b5b55d61f9ac9db59ee1bb3b4e58074 [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),
Calin Juravle6ae70962015-03-18 16:31:28 +000071 number_of_stack_maps_with_inline_info_(0),
72 dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010073
74 // Compute bytes needed to encode a mask with the given maximum element.
75 static uint32_t StackMaskEncodingSize(int max_element) {
76 int number_of_bits = max_element + 1; // Need room for max element too.
77 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
78 }
79
80 // See runtime/stack_map.h to know what these fields contain.
81 struct StackMapEntry {
82 uint32_t dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010083 uint32_t native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010084 uint32_t register_mask;
85 BitVector* sp_mask;
86 uint32_t num_dex_registers;
87 uint8_t inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000088 size_t dex_register_locations_start_index;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010089 size_t inline_infos_start_index;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000090 BitVector* live_dex_registers_mask;
Calin Juravle6ae70962015-03-18 16:31:28 +000091 uint32_t dex_register_map_hash;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010092 };
93
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010094 struct InlineInfoEntry {
95 uint32_t method_index;
96 };
97
98 void AddStackMapEntry(uint32_t dex_pc,
Nicolas Geoffray39468442014-09-02 15:17:15 +010099 uint32_t native_pc_offset,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100100 uint32_t register_mask,
101 BitVector* sp_mask,
102 uint32_t num_dex_registers,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000103 uint8_t inlining_depth) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100104 StackMapEntry entry;
105 entry.dex_pc = dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100106 entry.native_pc_offset = native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100107 entry.register_mask = register_mask;
108 entry.sp_mask = sp_mask;
109 entry.num_dex_registers = num_dex_registers;
110 entry.inlining_depth = inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000111 entry.dex_register_locations_start_index = dex_register_locations_.Size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100112 entry.inline_infos_start_index = inline_infos_.Size();
Calin Juravle6ae70962015-03-18 16:31:28 +0000113 entry.dex_register_map_hash = 0;
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000114 if (num_dex_registers != 0) {
115 entry.live_dex_registers_mask =
116 new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
117 } else {
118 entry.live_dex_registers_mask = nullptr;
119 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100120 stack_maps_.Add(entry);
121
Nicolas Geoffray39468442014-09-02 15:17:15 +0100122 if (sp_mask != nullptr) {
123 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
124 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100125 if (inlining_depth > 0) {
126 number_of_stack_maps_with_inline_info_++;
127 }
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000128
129 dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
130 native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100131 }
132
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100133 void AddInlineInfoEntry(uint32_t method_index) {
134 InlineInfoEntry entry;
135 entry.method_index = method_index;
136 inline_infos_.Add(entry);
137 }
138
Calin Juravle6ae70962015-03-18 16:31:28 +0000139 size_t ComputeNeededSize() {
Roland Levillainede7bf82015-03-13 12:23:04 +0000140 size_t size = CodeInfo::kFixedSize
Roland Levillaina552e1c2015-03-26 15:01:03 +0000141 + ComputeDexRegisterLocationCatalogSize()
Roland Levillain29ba1b02015-03-13 11:45:07 +0000142 + ComputeStackMapsSize()
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000143 + ComputeDexRegisterMapsSize()
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100144 + ComputeInlineInfoSize();
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000145 // Note: use RoundUp to word-size here if you want CodeInfo objects to be word aligned.
146 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100147 }
148
Roland Levillain29ba1b02015-03-13 11:45:07 +0000149 size_t ComputeStackMaskSize() const {
150 return StackMaskEncodingSize(stack_mask_max_);
151 }
152
Calin Juravle6ae70962015-03-18 16:31:28 +0000153 size_t ComputeStackMapsSize() {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000154 return stack_maps_.Size() * StackMap::ComputeStackMapSize(
155 ComputeStackMaskSize(),
156 ComputeInlineInfoSize(),
157 ComputeDexRegisterMapsSize(),
158 dex_pc_max_,
159 native_pc_offset_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100160 }
161
Roland Levillaina552e1c2015-03-26 15:01:03 +0000162 // Compute the size of the Dex register location catalog of `entry`.
163 size_t ComputeDexRegisterLocationCatalogSize() const {
164 size_t size = DexRegisterLocationCatalog::kFixedSize;
165 for (size_t location_catalog_entry_index = 0;
166 location_catalog_entry_index < location_catalog_entries_.Size();
167 ++location_catalog_entry_index) {
168 DexRegisterLocation dex_register_location =
169 location_catalog_entries_.Get(location_catalog_entry_index);
170 size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
171 }
172 return size;
173 }
174
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000175 size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000176 // Size of the map in bytes.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000177 size_t size = DexRegisterMap::kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000178 // Add the live bit mask for the Dex register liveness.
179 size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
180 // Compute the size of the set of live Dex register entries.
181 size_t number_of_live_dex_registers = 0;
182 for (size_t dex_register_number = 0;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000183 dex_register_number < entry.num_dex_registers;
184 ++dex_register_number) {
185 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000186 ++number_of_live_dex_registers;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000187 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000188 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000189 size_t map_entries_size_in_bits =
190 DexRegisterMap::SingleEntrySizeInBits(location_catalog_entries_.Size())
191 * number_of_live_dex_registers;
192 size_t map_entries_size_in_bytes =
193 RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
194 size += map_entries_size_in_bytes;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000195 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100196 }
197
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000198 // Compute the size of all the Dex register maps.
Calin Juravle6ae70962015-03-18 16:31:28 +0000199 size_t ComputeDexRegisterMapsSize() {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000200 size_t size = 0;
201 for (size_t i = 0; i < stack_maps_.Size(); ++i) {
Calin Juravle6ae70962015-03-18 16:31:28 +0000202 if (FindEntryWithTheSameDexMap(i) == kNoSameDexMapFound) {
203 // Entries with the same dex map will have the same offset.
204 size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
205 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000206 }
Roland Levillainede7bf82015-03-13 12:23:04 +0000207 return size;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000208 }
209
210 // Compute the size of all the inline information pieces.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100211 size_t ComputeInlineInfoSize() const {
212 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
213 // For encoding the depth.
214 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
215 }
216
Roland Levillaina552e1c2015-03-26 15:01:03 +0000217 size_t ComputeDexRegisterLocationCatalogStart() const {
218 return CodeInfo::kFixedSize;
219 }
220
221 size_t ComputeStackMapsStart() const {
222 return ComputeDexRegisterLocationCatalogStart() + ComputeDexRegisterLocationCatalogSize();
223 }
224
Calin Juravle6ae70962015-03-18 16:31:28 +0000225 size_t ComputeDexRegisterMapsStart() {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000226 return ComputeStackMapsStart() + ComputeStackMapsSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100227 }
228
Calin Juravle6ae70962015-03-18 16:31:28 +0000229 size_t ComputeInlineInfoStart() {
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000230 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000231 }
232
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100233 void FillIn(MemoryRegion region) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100234 CodeInfo code_info(region);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000235 DCHECK_EQ(region.size(), ComputeNeededSize());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100236 code_info.SetOverallSize(region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100237
Roland Levillain29ba1b02015-03-13 11:45:07 +0000238 size_t stack_mask_size = ComputeStackMaskSize();
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000239
240 size_t dex_register_map_size = ComputeDexRegisterMapsSize();
241 size_t inline_info_size = ComputeInlineInfoSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100242
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000243 MemoryRegion dex_register_locations_region = region.Subregion(
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000244 ComputeDexRegisterMapsStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000245 dex_register_map_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100246
247 MemoryRegion inline_infos_region = region.Subregion(
248 ComputeInlineInfoStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000249 inline_info_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100250
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000251 code_info.SetEncoding(
252 inline_info_size, dex_register_map_size, dex_pc_max_, native_pc_offset_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100253 code_info.SetNumberOfStackMaps(stack_maps_.Size());
254 code_info.SetStackMaskSize(stack_mask_size);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000255 DCHECK_EQ(code_info.GetStackMapsSize(), ComputeStackMapsSize());
256
257 // Set the Dex register location catalog.
258 code_info.SetNumberOfDexRegisterLocationCatalogEntries(
259 location_catalog_entries_.Size());
260 MemoryRegion dex_register_location_catalog_region = region.Subregion(
261 ComputeDexRegisterLocationCatalogStart(),
262 ComputeDexRegisterLocationCatalogSize());
263 DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
264 // Offset in `dex_register_location_catalog` where to store the next
265 // register location.
266 size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
267 for (size_t i = 0, e = location_catalog_entries_.Size(); i < e; ++i) {
268 DexRegisterLocation dex_register_location = location_catalog_entries_.Get(i);
269 dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
270 location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
271 }
272 // Ensure we reached the end of the Dex registers location_catalog.
273 DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100274
275 uintptr_t next_dex_register_map_offset = 0;
276 uintptr_t next_inline_info_offset = 0;
277 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100278 StackMap stack_map = code_info.GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100279 StackMapEntry entry = stack_maps_.Get(i);
280
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000281 stack_map.SetDexPc(code_info, entry.dex_pc);
282 stack_map.SetNativePcOffset(code_info, entry.native_pc_offset);
283 stack_map.SetRegisterMask(code_info, entry.register_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100284 if (entry.sp_mask != nullptr) {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000285 stack_map.SetStackMask(code_info, *entry.sp_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100286 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100287
Calin Juravle6ae70962015-03-18 16:31:28 +0000288 if (entry.num_dex_registers == 0) {
289 // No dex map available.
290 stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
291 } else {
292 // Search for an entry with the same dex map.
293 size_t entry_with_same_map = FindEntryWithTheSameDexMap(i);
294 if (entry_with_same_map != kNoSameDexMapFound) {
295 // If we have a hit reuse the offset.
296 stack_map.SetDexRegisterMapOffset(code_info,
297 code_info.GetStackMapAt(entry_with_same_map).GetDexRegisterMapOffset(code_info));
298 } else {
299 // New dex registers maps should be added to the stack map.
300 MemoryRegion register_region =
301 dex_register_locations_region.Subregion(
302 next_dex_register_map_offset,
303 ComputeDexRegisterMapSize(entry));
304 next_dex_register_map_offset += register_region.size();
305 DexRegisterMap dex_register_map(register_region);
306 stack_map.SetDexRegisterMapOffset(
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000307 code_info, register_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100308
Roland Levillaina552e1c2015-03-26 15:01:03 +0000309 // Set the live bit mask.
310 dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
311
312 // Set the dex register location mapping data.
Calin Juravle6ae70962015-03-18 16:31:28 +0000313 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
314 dex_register_number < entry.num_dex_registers;
315 ++dex_register_number) {
316 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000317 size_t location_catalog_entry_index =
318 dex_register_locations_.Get(entry.dex_register_locations_start_index
319 + index_in_dex_register_locations);
320 dex_register_map.SetLocationCatalogEntryIndex(
321 index_in_dex_register_locations,
322 location_catalog_entry_index,
323 entry.num_dex_registers,
324 location_catalog_entries_.Size());
Calin Juravle6ae70962015-03-18 16:31:28 +0000325 ++index_in_dex_register_locations;
326 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000327 }
Roland Levillain442b46a2015-02-18 16:54:21 +0000328 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100329 }
330
331 // Set the inlining info.
332 if (entry.inlining_depth != 0) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800333 MemoryRegion inline_region = inline_infos_region.Subregion(
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100334 next_inline_info_offset,
335 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800336 next_inline_info_offset += inline_region.size();
337 InlineInfo inline_info(inline_region);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100338
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000339 // Currently relative to the dex register map.
340 stack_map.SetInlineDescriptorOffset(
341 code_info, inline_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100342
343 inline_info.SetDepth(entry.inlining_depth);
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800344 for (size_t j = 0; j < entry.inlining_depth; ++j) {
345 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
346 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100347 }
348 } else {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000349 if (inline_info_size != 0) {
350 stack_map.SetInlineDescriptorOffset(code_info, StackMap::kNoInlineInfo);
351 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100352 }
353 }
354 }
355
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000356 void AddDexRegisterEntry(uint16_t dex_register, DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000357 StackMapEntry entry = stack_maps_.Get(stack_maps_.Size() - 1);
358 DCHECK_LT(dex_register, entry.num_dex_registers);
359
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000360 if (kind != DexRegisterLocation::Kind::kNone) {
361 // Ensure we only use non-compressed location kind at this stage.
362 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
363 << DexRegisterLocation::PrettyDescriptor(kind);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000364 DexRegisterLocation location(kind, value);
365
366 // Look for Dex register `location` in the location catalog (using the
367 // companion hash map of locations to indices). Use its index if it
368 // is already in the location catalog. If not, insert it (in the
369 // location catalog and the hash map) and use the newly created index.
370 auto it = location_catalog_entries_indices_.Find(location);
371 if (it != location_catalog_entries_indices_.end()) {
372 // Retrieve the index from the hash map.
373 dex_register_locations_.Add(it->second);
374 } else {
375 // Create a new entry in the location catalog and the hash map.
376 size_t index = location_catalog_entries_.Size();
377 location_catalog_entries_.Add(location);
378 dex_register_locations_.Add(index);
379 location_catalog_entries_indices_.Insert(std::make_pair(location, index));
380 }
381
Calin Juravle6ae70962015-03-18 16:31:28 +0000382 entry.live_dex_registers_mask->SetBit(dex_register);
383 entry.dex_register_map_hash += (1 << dex_register);
384 entry.dex_register_map_hash += static_cast<uint32_t>(value);
385 entry.dex_register_map_hash += static_cast<uint32_t>(kind);
386 stack_maps_.Put(stack_maps_.Size() - 1, entry);
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000387 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000388 }
389
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000390 private:
Calin Juravle6ae70962015-03-18 16:31:28 +0000391 // Returns the index of an entry with the same dex register map
392 // or kNoSameDexMapFound if no such entry exists.
393 size_t FindEntryWithTheSameDexMap(size_t entry_index) {
394 StackMapEntry entry = stack_maps_.Get(entry_index);
395 auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.dex_register_map_hash);
396 if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
397 // We don't have a perfect hash functions so we need a list to collect all stack maps
398 // which might have the same dex register map.
399 GrowableArray<uint32_t> stack_map_indices(allocator_, 1);
400 stack_map_indices.Add(entry_index);
401 dex_map_hash_to_stack_map_indices_.Put(entry.dex_register_map_hash, stack_map_indices);
402 return kNoSameDexMapFound;
403 }
404
405 // TODO: We don't need to add ourselves to the map if we can guarantee that
406 // FindEntryWithTheSameDexMap is called just once per stack map entry.
407 // A good way to do this is to cache the offset in the stack map entry. This
408 // is easier to do if we add markers when the stack map constructions begins
409 // and when it ends.
410
411 // We might have collisions, so we need to check whether or not we should
412 // add the entry to the map. `needs_to_be_added` keeps track of this.
413 bool needs_to_be_added = true;
414 size_t result = kNoSameDexMapFound;
415 for (size_t i = 0; i < entries_it->second.Size(); i++) {
416 size_t test_entry_index = entries_it->second.Get(i);
417 if (test_entry_index == entry_index) {
418 needs_to_be_added = false;
419 } else if (HaveTheSameDexMaps(stack_maps_.Get(test_entry_index), entry)) {
420 result = test_entry_index;
421 needs_to_be_added = false;
422 break;
423 }
424 }
425 if (needs_to_be_added) {
426 entries_it->second.Add(entry_index);
427 }
428 return result;
429 }
430
431 bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const {
432 if (a.live_dex_registers_mask == nullptr && b.live_dex_registers_mask == nullptr) {
433 return true;
434 }
435 if (a.live_dex_registers_mask == nullptr || b.live_dex_registers_mask == nullptr) {
436 return false;
437 }
438 if (a.num_dex_registers != b.num_dex_registers) {
439 return false;
440 }
441
442 int index_in_dex_register_locations = 0;
443 for (uint32_t i = 0; i < a.num_dex_registers; i++) {
444 if (a.live_dex_registers_mask->IsBitSet(i) != b.live_dex_registers_mask->IsBitSet(i)) {
445 return false;
446 }
447 if (a.live_dex_registers_mask->IsBitSet(i)) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000448 size_t a_loc = dex_register_locations_.Get(
Calin Juravle6ae70962015-03-18 16:31:28 +0000449 a.dex_register_locations_start_index + index_in_dex_register_locations);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000450 size_t b_loc = dex_register_locations_.Get(
Calin Juravle6ae70962015-03-18 16:31:28 +0000451 b.dex_register_locations_start_index + index_in_dex_register_locations);
452 if (a_loc != b_loc) {
453 return false;
454 }
455 ++index_in_dex_register_locations;
456 }
457 }
458 return true;
459 }
460
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000461 ArenaAllocator* allocator_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100462 GrowableArray<StackMapEntry> stack_maps_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000463
464 // A catalog of unique [location_kind, register_value] pairs (per method).
465 GrowableArray<DexRegisterLocation> location_catalog_entries_;
466 // Map from Dex register location catalog entries to their indices in the
467 // location catalog.
468 typedef HashMap<DexRegisterLocation, size_t, LocationCatalogEntriesIndicesEmptyFn,
469 DexRegisterLocationHashFn> LocationCatalogEntriesIndices;
470 LocationCatalogEntriesIndices location_catalog_entries_indices_;
471
472 // A set of concatenated maps of Dex register locations indices to
473 // `location_catalog_entries_`.
474 GrowableArray<size_t> dex_register_locations_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100475 GrowableArray<InlineInfoEntry> inline_infos_;
476 int stack_mask_max_;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000477 uint32_t dex_pc_max_;
478 uint32_t native_pc_offset_max_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100479 size_t number_of_stack_maps_with_inline_info_;
480
Calin Juravle6ae70962015-03-18 16:31:28 +0000481 ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
482
483 static constexpr uint32_t kNoSameDexMapFound = -1;
484
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100485 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
486};
487
488} // namespace art
489
490#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_