blob: fcc86d51630549147886d4b5d783e1ca156fb212 [file] [log] [blame]
Calin Juravlec416d332015-04-23 16:01:43 +01001/*
2 * Copyright (C) 2015 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#include "stack_map_stream.h"
18
19namespace art {
20
21void StackMapStream::AddStackMapEntry(uint32_t dex_pc,
22 uint32_t native_pc_offset,
23 uint32_t register_mask,
24 BitVector* sp_mask,
25 uint32_t num_dex_registers,
26 uint8_t inlining_depth) {
27 StackMapEntry entry;
28 entry.dex_pc = dex_pc;
29 entry.native_pc_offset = native_pc_offset;
30 entry.register_mask = register_mask;
31 entry.sp_mask = sp_mask;
32 entry.num_dex_registers = num_dex_registers;
33 entry.inlining_depth = inlining_depth;
34 entry.dex_register_locations_start_index = dex_register_locations_.Size();
35 entry.inline_infos_start_index = inline_infos_.Size();
36 entry.dex_register_map_hash = 0;
37 if (num_dex_registers != 0) {
38 entry.live_dex_registers_mask =
39 new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
40 } else {
41 entry.live_dex_registers_mask = nullptr;
42 }
43 stack_maps_.Add(entry);
44
45 if (sp_mask != nullptr) {
46 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
47 }
48 if (inlining_depth > 0) {
49 number_of_stack_maps_with_inline_info_++;
50 }
51
52 dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
53 native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
54 register_mask_max_ = std::max(register_mask_max_, register_mask);
55}
56
57void StackMapStream::AddDexRegisterEntry(uint16_t dex_register,
58 DexRegisterLocation::Kind kind,
59 int32_t value) {
60 StackMapEntry entry = stack_maps_.Get(stack_maps_.Size() - 1);
61 DCHECK_LT(dex_register, entry.num_dex_registers);
62
63 if (kind != DexRegisterLocation::Kind::kNone) {
64 // Ensure we only use non-compressed location kind at this stage.
65 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
66 << DexRegisterLocation::PrettyDescriptor(kind);
67 DexRegisterLocation location(kind, value);
68
69 // Look for Dex register `location` in the location catalog (using the
70 // companion hash map of locations to indices). Use its index if it
71 // is already in the location catalog. If not, insert it (in the
72 // location catalog and the hash map) and use the newly created index.
73 auto it = location_catalog_entries_indices_.Find(location);
74 if (it != location_catalog_entries_indices_.end()) {
75 // Retrieve the index from the hash map.
76 dex_register_locations_.Add(it->second);
77 } else {
78 // Create a new entry in the location catalog and the hash map.
79 size_t index = location_catalog_entries_.Size();
80 location_catalog_entries_.Add(location);
81 dex_register_locations_.Add(index);
82 location_catalog_entries_indices_.Insert(std::make_pair(location, index));
83 }
84
85 entry.live_dex_registers_mask->SetBit(dex_register);
86 entry.dex_register_map_hash +=
87 (1 << (dex_register % (sizeof(entry.dex_register_map_hash) * kBitsPerByte)));
88 entry.dex_register_map_hash += static_cast<uint32_t>(value);
89 entry.dex_register_map_hash += static_cast<uint32_t>(kind);
90 stack_maps_.Put(stack_maps_.Size() - 1, entry);
91 }
92}
93
94void StackMapStream::AddInlineInfoEntry(uint32_t method_index) {
95 InlineInfoEntry entry;
96 entry.method_index = method_index;
97 inline_infos_.Add(entry);
98}
99
100size_t StackMapStream::ComputeNeededSize() {
101 size_t size = CodeInfo::kFixedSize
102 + ComputeDexRegisterLocationCatalogSize()
103 + ComputeStackMapsSize()
104 + ComputeDexRegisterMapsSize()
105 + ComputeInlineInfoSize();
106 // Note: use RoundUp to word-size here if you want CodeInfo objects to be word aligned.
107 return size;
108}
109
110size_t StackMapStream::ComputeStackMaskSize() const {
111 int number_of_bits = stack_mask_max_ + 1; // Need room for max element too.
112 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
113}
114
115size_t StackMapStream::ComputeStackMapsSize() {
116 return stack_maps_.Size() * StackMap::ComputeStackMapSize(
117 ComputeStackMaskSize(),
118 ComputeInlineInfoSize(),
119 ComputeDexRegisterMapsSize(),
120 dex_pc_max_,
121 native_pc_offset_max_,
122 register_mask_max_);
123}
124
125size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const {
126 size_t size = DexRegisterLocationCatalog::kFixedSize;
127 for (size_t location_catalog_entry_index = 0;
128 location_catalog_entry_index < location_catalog_entries_.Size();
129 ++location_catalog_entry_index) {
130 DexRegisterLocation dex_register_location =
131 location_catalog_entries_.Get(location_catalog_entry_index);
132 size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
133 }
134 return size;
135}
136
137size_t StackMapStream::ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
138 // Size of the map in bytes.
139 size_t size = DexRegisterMap::kFixedSize;
140 // Add the live bit mask for the Dex register liveness.
141 size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
142 // Compute the size of the set of live Dex register entries.
143 size_t number_of_live_dex_registers = 0;
144 for (size_t dex_register_number = 0;
145 dex_register_number < entry.num_dex_registers;
146 ++dex_register_number) {
147 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
148 ++number_of_live_dex_registers;
149 }
150 }
151 size_t map_entries_size_in_bits =
152 DexRegisterMap::SingleEntrySizeInBits(location_catalog_entries_.Size())
153 * number_of_live_dex_registers;
154 size_t map_entries_size_in_bytes =
155 RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
156 size += map_entries_size_in_bytes;
157 return size;
158}
159
160size_t StackMapStream::ComputeDexRegisterMapsSize() {
161 size_t size = 0;
162 for (size_t i = 0; i < stack_maps_.Size(); ++i) {
163 if (FindEntryWithTheSameDexMap(i) == kNoSameDexMapFound) {
164 // Entries with the same dex map will have the same offset.
165 size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
166 }
167 }
168 return size;
169}
170
171size_t StackMapStream::ComputeInlineInfoSize() const {
172 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
173 // For encoding the depth.
174 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
175}
176
177size_t StackMapStream::ComputeDexRegisterLocationCatalogStart() const {
178 return CodeInfo::kFixedSize;
179}
180
181size_t StackMapStream::ComputeStackMapsStart() const {
182 return ComputeDexRegisterLocationCatalogStart() + ComputeDexRegisterLocationCatalogSize();
183}
184
185size_t StackMapStream::ComputeDexRegisterMapsStart() {
186 return ComputeStackMapsStart() + ComputeStackMapsSize();
187}
188
189size_t StackMapStream::ComputeInlineInfoStart() {
190 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
191}
192
193void StackMapStream::FillIn(MemoryRegion region) {
194 CodeInfo code_info(region);
195 DCHECK_EQ(region.size(), ComputeNeededSize());
196 code_info.SetOverallSize(region.size());
197
198 size_t stack_mask_size = ComputeStackMaskSize();
199
200 size_t dex_register_map_size = ComputeDexRegisterMapsSize();
201 size_t inline_info_size = ComputeInlineInfoSize();
202
203 MemoryRegion dex_register_locations_region = region.Subregion(
204 ComputeDexRegisterMapsStart(),
205 dex_register_map_size);
206
207 MemoryRegion inline_infos_region = region.Subregion(
208 ComputeInlineInfoStart(),
209 inline_info_size);
210
211 code_info.SetEncoding(inline_info_size,
212 dex_register_map_size,
213 dex_pc_max_,
214 native_pc_offset_max_,
215 register_mask_max_);
216 code_info.SetNumberOfStackMaps(stack_maps_.Size());
217 code_info.SetStackMaskSize(stack_mask_size);
218 DCHECK_EQ(code_info.GetStackMapsSize(), ComputeStackMapsSize());
219
220 // Set the Dex register location catalog.
221 code_info.SetNumberOfDexRegisterLocationCatalogEntries(
222 location_catalog_entries_.Size());
223 MemoryRegion dex_register_location_catalog_region = region.Subregion(
224 ComputeDexRegisterLocationCatalogStart(),
225 ComputeDexRegisterLocationCatalogSize());
226 DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
227 // Offset in `dex_register_location_catalog` where to store the next
228 // register location.
229 size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
230 for (size_t i = 0, e = location_catalog_entries_.Size(); i < e; ++i) {
231 DexRegisterLocation dex_register_location = location_catalog_entries_.Get(i);
232 dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
233 location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
234 }
235 // Ensure we reached the end of the Dex registers location_catalog.
236 DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());
237
238 uintptr_t next_dex_register_map_offset = 0;
239 uintptr_t next_inline_info_offset = 0;
240 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
241 StackMap stack_map = code_info.GetStackMapAt(i);
242 StackMapEntry entry = stack_maps_.Get(i);
243
244 stack_map.SetDexPc(code_info, entry.dex_pc);
245 stack_map.SetNativePcOffset(code_info, entry.native_pc_offset);
246 stack_map.SetRegisterMask(code_info, entry.register_mask);
247 if (entry.sp_mask != nullptr) {
248 stack_map.SetStackMask(code_info, *entry.sp_mask);
249 }
250
251 if (entry.num_dex_registers == 0) {
252 // No dex map available.
253 stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
254 } else {
255 // Search for an entry with the same dex map.
256 size_t entry_with_same_map = FindEntryWithTheSameDexMap(i);
257 if (entry_with_same_map != kNoSameDexMapFound) {
258 // If we have a hit reuse the offset.
259 stack_map.SetDexRegisterMapOffset(code_info,
260 code_info.GetStackMapAt(entry_with_same_map).GetDexRegisterMapOffset(code_info));
261 } else {
262 // New dex registers maps should be added to the stack map.
263 MemoryRegion register_region =
264 dex_register_locations_region.Subregion(
265 next_dex_register_map_offset,
266 ComputeDexRegisterMapSize(entry));
267 next_dex_register_map_offset += register_region.size();
268 DexRegisterMap dex_register_map(register_region);
269 stack_map.SetDexRegisterMapOffset(
270 code_info, register_region.start() - dex_register_locations_region.start());
271
272 // Set the live bit mask.
273 dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
274
275 // Set the dex register location mapping data.
276 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
277 dex_register_number < entry.num_dex_registers;
278 ++dex_register_number) {
279 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
280 size_t location_catalog_entry_index =
281 dex_register_locations_.Get(entry.dex_register_locations_start_index
282 + index_in_dex_register_locations);
283 dex_register_map.SetLocationCatalogEntryIndex(
284 index_in_dex_register_locations,
285 location_catalog_entry_index,
286 entry.num_dex_registers,
287 location_catalog_entries_.Size());
288 ++index_in_dex_register_locations;
289 }
290 }
291 }
292 }
293
294 // Set the inlining info.
295 if (entry.inlining_depth != 0) {
296 MemoryRegion inline_region = inline_infos_region.Subregion(
297 next_inline_info_offset,
298 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
299 next_inline_info_offset += inline_region.size();
300 InlineInfo inline_info(inline_region);
301
302 // Currently relative to the dex register map.
303 stack_map.SetInlineDescriptorOffset(
304 code_info, inline_region.start() - dex_register_locations_region.start());
305
306 inline_info.SetDepth(entry.inlining_depth);
307 for (size_t j = 0; j < entry.inlining_depth; ++j) {
308 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
309 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
310 }
311 } else {
312 if (inline_info_size != 0) {
313 stack_map.SetInlineDescriptorOffset(code_info, StackMap::kNoInlineInfo);
314 }
315 }
316 }
317}
318
319size_t StackMapStream::FindEntryWithTheSameDexMap(size_t entry_index) {
320 StackMapEntry entry = stack_maps_.Get(entry_index);
321 auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.dex_register_map_hash);
322 if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
323 // We don't have a perfect hash functions so we need a list to collect all stack maps
324 // which might have the same dex register map.
325 GrowableArray<uint32_t> stack_map_indices(allocator_, 1);
326 stack_map_indices.Add(entry_index);
327 dex_map_hash_to_stack_map_indices_.Put(entry.dex_register_map_hash, stack_map_indices);
328 return kNoSameDexMapFound;
329 }
330
331 // TODO: We don't need to add ourselves to the map if we can guarantee that
332 // FindEntryWithTheSameDexMap is called just once per stack map entry.
333 // A good way to do this is to cache the offset in the stack map entry. This
334 // is easier to do if we add markers when the stack map constructions begins
335 // and when it ends.
336
337 // We might have collisions, so we need to check whether or not we should
338 // add the entry to the map. `needs_to_be_added` keeps track of this.
339 bool needs_to_be_added = true;
340 size_t result = kNoSameDexMapFound;
341 for (size_t i = 0; i < entries_it->second.Size(); i++) {
342 size_t test_entry_index = entries_it->second.Get(i);
343 if (test_entry_index == entry_index) {
344 needs_to_be_added = false;
345 } else if (HaveTheSameDexMaps(stack_maps_.Get(test_entry_index), entry)) {
346 result = test_entry_index;
347 needs_to_be_added = false;
348 break;
349 }
350 }
351 if (needs_to_be_added) {
352 entries_it->second.Add(entry_index);
353 }
354 return result;
355}
356
357bool StackMapStream::HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const {
358 if (a.live_dex_registers_mask == nullptr && b.live_dex_registers_mask == nullptr) {
359 return true;
360 }
361 if (a.live_dex_registers_mask == nullptr || b.live_dex_registers_mask == nullptr) {
362 return false;
363 }
364 if (a.num_dex_registers != b.num_dex_registers) {
365 return false;
366 }
367
368 int index_in_dex_register_locations = 0;
369 for (uint32_t i = 0; i < a.num_dex_registers; i++) {
370 if (a.live_dex_registers_mask->IsBitSet(i) != b.live_dex_registers_mask->IsBitSet(i)) {
371 return false;
372 }
373 if (a.live_dex_registers_mask->IsBitSet(i)) {
374 size_t a_loc = dex_register_locations_.Get(
375 a.dex_register_locations_start_index + index_in_dex_register_locations);
376 size_t b_loc = dex_register_locations_.Get(
377 b.dex_register_locations_start_index + index_in_dex_register_locations);
378 if (a_loc != b_loc) {
379 return false;
380 }
381 ++index_in_dex_register_locations;
382 }
383 }
384 return true;
385}
386
387} // namespace art