blob: b1dcb68415f0c7c99a388072fe365486e50bd90e [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 */
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000016
Calin Juravlec416d332015-04-23 16:01:43 +010017#include "stack_map_stream.h"
18
Andreas Gampe90b936d2017-01-31 08:58:55 -080019#include "art_method-inl.h"
David Srbecky45aa5982016-03-18 02:15:09 +000020#include "base/stl_util.h"
David Sehr9e734c72018-01-04 17:56:19 -080021#include "dex/dex_file_types.h"
Nicolas Geoffrayfbdfa6d2017-02-03 10:43:13 +000022#include "optimizing/optimizing_compiler.h"
Nicolas Geoffray5d37c152017-01-12 13:25:19 +000023#include "runtime.h"
24#include "scoped_thread_state_change-inl.h"
25
Calin Juravlec416d332015-04-23 16:01:43 +010026namespace art {
27
David Srbeckyd02b23f2018-05-29 23:27:22 +010028uint32_t StackMapStream::GetStackMapNativePcOffset(size_t i) {
29 return StackMap::UnpackNativePc(stack_maps_[i].packed_native_pc, instruction_set_);
30}
31
32void StackMapStream::SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) {
33 stack_maps_[i].packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_);
34}
35
Calin Juravle4f46ac52015-04-23 18:47:21 +010036void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,
37 uint32_t native_pc_offset,
38 uint32_t register_mask,
39 BitVector* sp_mask,
40 uint32_t num_dex_registers,
41 uint8_t inlining_depth) {
42 DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
43 current_entry_.dex_pc = dex_pc;
David Srbeckyd02b23f2018-05-29 23:27:22 +010044 current_entry_.packed_native_pc = StackMap::PackNativePc(native_pc_offset, instruction_set_);
Calin Juravle4f46ac52015-04-23 18:47:21 +010045 current_entry_.register_mask = register_mask;
46 current_entry_.sp_mask = sp_mask;
Calin Juravle4f46ac52015-04-23 18:47:21 +010047 current_entry_.inlining_depth = inlining_depth;
Vladimir Marko225b6462015-09-28 12:17:40 +010048 current_entry_.inline_infos_start_index = inline_infos_.size();
David Srbecky45aa5982016-03-18 02:15:09 +000049 current_entry_.stack_mask_index = 0;
Andreas Gampee2abbc62017-09-15 11:59:26 -070050 current_entry_.dex_method_index = dex::kDexNoIndex;
Mathieu Chartier32289082017-02-09 15:57:37 -080051 current_entry_.dex_register_entry.num_dex_registers = num_dex_registers;
52 current_entry_.dex_register_entry.locations_start_index = dex_register_locations_.size();
Vladimir Marko174b2e22017-10-12 13:34:49 +010053 current_entry_.dex_register_entry.live_dex_registers_mask = nullptr;
54 if (num_dex_registers != 0u) {
55 current_entry_.dex_register_entry.live_dex_registers_mask =
56 ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream);
57 current_entry_.dex_register_entry.live_dex_registers_mask->ClearAllBits();
58 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010059 current_dex_register_ = 0;
Calin Juravlec416d332015-04-23 16:01:43 +010060}
61
Calin Juravle4f46ac52015-04-23 18:47:21 +010062void StackMapStream::EndStackMapEntry() {
Mathieu Chartier32289082017-02-09 15:57:37 -080063 current_entry_.dex_register_map_index = AddDexRegisterMapEntry(current_entry_.dex_register_entry);
Vladimir Marko225b6462015-09-28 12:17:40 +010064 stack_maps_.push_back(current_entry_);
Calin Juravle4f46ac52015-04-23 18:47:21 +010065 current_entry_ = StackMapEntry();
66}
67
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010068void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
Calin Juravlec416d332015-04-23 16:01:43 +010069 if (kind != DexRegisterLocation::Kind::kNone) {
70 // Ensure we only use non-compressed location kind at this stage.
David Srbecky7dc11782016-02-25 13:23:56 +000071 DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) << kind;
Calin Juravlec416d332015-04-23 16:01:43 +010072 DexRegisterLocation location(kind, value);
73
74 // Look for Dex register `location` in the location catalog (using the
75 // companion hash map of locations to indices). Use its index if it
76 // is already in the location catalog. If not, insert it (in the
77 // location catalog and the hash map) and use the newly created index.
78 auto it = location_catalog_entries_indices_.Find(location);
79 if (it != location_catalog_entries_indices_.end()) {
80 // Retrieve the index from the hash map.
Vladimir Marko225b6462015-09-28 12:17:40 +010081 dex_register_locations_.push_back(it->second);
Calin Juravlec416d332015-04-23 16:01:43 +010082 } else {
83 // Create a new entry in the location catalog and the hash map.
Vladimir Marko225b6462015-09-28 12:17:40 +010084 size_t index = location_catalog_entries_.size();
85 location_catalog_entries_.push_back(location);
86 dex_register_locations_.push_back(index);
Calin Juravlec416d332015-04-23 16:01:43 +010087 location_catalog_entries_indices_.Insert(std::make_pair(location, index));
88 }
Mathieu Chartier32289082017-02-09 15:57:37 -080089 DexRegisterMapEntry* const entry = in_inline_frame_
90 ? &current_inline_info_.dex_register_entry
91 : &current_entry_.dex_register_entry;
92 DCHECK_LT(current_dex_register_, entry->num_dex_registers);
93 entry->live_dex_registers_mask->SetBit(current_dex_register_);
94 entry->hash += (1 <<
95 (current_dex_register_ % (sizeof(DexRegisterMapEntry::hash) * kBitsPerByte)));
96 entry->hash += static_cast<uint32_t>(value);
97 entry->hash += static_cast<uint32_t>(kind);
Calin Juravlec416d332015-04-23 16:01:43 +010098 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010099 current_dex_register_++;
Calin Juravlec416d332015-04-23 16:01:43 +0100100}
101
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800102void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) {
103 current_entry_.invoke_type = invoke_type;
104 current_entry_.dex_method_index = dex_method_index;
105}
106
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000107void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100108 uint32_t dex_pc,
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000109 uint32_t num_dex_registers,
110 const DexFile* outer_dex_file) {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100111 DCHECK(!in_inline_frame_);
112 in_inline_frame_ = true;
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000113 if (EncodeArtMethodInInlineInfo(method)) {
114 current_inline_info_.method = method;
115 } else {
116 if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) {
117 ScopedObjectAccess soa(Thread::Current());
118 DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile()));
119 }
120 current_inline_info_.method_index = method->GetDexMethodIndexUnchecked();
121 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100122 current_inline_info_.dex_pc = dex_pc;
Mathieu Chartier32289082017-02-09 15:57:37 -0800123 current_inline_info_.dex_register_entry.num_dex_registers = num_dex_registers;
124 current_inline_info_.dex_register_entry.locations_start_index = dex_register_locations_.size();
Vladimir Marko174b2e22017-10-12 13:34:49 +0100125 current_inline_info_.dex_register_entry.live_dex_registers_mask = nullptr;
126 if (num_dex_registers != 0) {
127 current_inline_info_.dex_register_entry.live_dex_registers_mask =
128 ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream);
129 current_inline_info_.dex_register_entry.live_dex_registers_mask->ClearAllBits();
130 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100131 current_dex_register_ = 0;
132}
133
134void StackMapStream::EndInlineInfoEntry() {
Mathieu Chartier32289082017-02-09 15:57:37 -0800135 current_inline_info_.dex_register_map_index =
136 AddDexRegisterMapEntry(current_inline_info_.dex_register_entry);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100137 DCHECK(in_inline_frame_);
Mathieu Chartier32289082017-02-09 15:57:37 -0800138 DCHECK_EQ(current_dex_register_, current_inline_info_.dex_register_entry.num_dex_registers)
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100139 << "Inline information contains less registers than expected";
140 in_inline_frame_ = false;
Vladimir Marko225b6462015-09-28 12:17:40 +0100141 inline_infos_.push_back(current_inline_info_);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100142 current_inline_info_ = InlineInfoEntry();
Calin Juravlec416d332015-04-23 16:01:43 +0100143}
144
Calin Juravlec416d332015-04-23 16:01:43 +0100145size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const {
146 size_t size = DexRegisterLocationCatalog::kFixedSize;
Vladimir Marko225b6462015-09-28 12:17:40 +0100147 for (const DexRegisterLocation& dex_register_location : location_catalog_entries_) {
Calin Juravlec416d332015-04-23 16:01:43 +0100148 size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
149 }
150 return size;
151}
152
Mathieu Chartier32289082017-02-09 15:57:37 -0800153size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) const {
Vladimir Marko225b6462015-09-28 12:17:40 +0100154 // For num_dex_registers == 0u live_dex_registers_mask may be null.
155 if (num_dex_registers == 0u) {
156 return 0u; // No register map will be emitted.
157 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100158 size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits();
159 if (live_dex_registers_mask->NumSetBits() == 0) {
160 return 0u; // No register map will be emitted.
161 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100162 DCHECK(live_dex_registers_mask != nullptr);
163
Calin Juravlec416d332015-04-23 16:01:43 +0100164 // Size of the map in bytes.
165 size_t size = DexRegisterMap::kFixedSize;
166 // Add the live bit mask for the Dex register liveness.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100167 size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
Calin Juravlec416d332015-04-23 16:01:43 +0100168 // Compute the size of the set of live Dex register entries.
Calin Juravlec416d332015-04-23 16:01:43 +0100169 size_t map_entries_size_in_bits =
Mathieu Chartier32289082017-02-09 15:57:37 -0800170 DexRegisterMap::SingleEntrySizeInBits(catalog_size) * number_of_live_dex_registers;
Calin Juravlec416d332015-04-23 16:01:43 +0100171 size_t map_entries_size_in_bytes =
172 RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
173 size += map_entries_size_in_bytes;
174 return size;
175}
176
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700177void StackMapStream::FillInMethodInfo(MemoryRegion region) {
178 {
179 MethodInfo info(region.begin(), method_indices_.size());
180 for (size_t i = 0; i < method_indices_.size(); ++i) {
181 info.SetMethodIndex(i, method_indices_[i]);
182 }
183 }
184 if (kIsDebugBuild) {
185 // Check the data matches.
186 MethodInfo info(region.begin());
187 const size_t count = info.NumMethodIndices();
188 DCHECK_EQ(count, method_indices_.size());
189 for (size_t i = 0; i < count; ++i) {
190 DCHECK_EQ(info.GetMethodIndex(i), method_indices_[i]);
191 }
192 }
193}
194
David Srbecky052f8ca2018-04-26 15:42:54 +0100195template<typename Vector>
196static MemoryRegion EncodeMemoryRegion(Vector* out, size_t* bit_offset, uint32_t bit_length) {
197 uint32_t byte_length = BitsToBytesRoundUp(bit_length);
198 EncodeVarintBits(out, bit_offset, byte_length);
199 *bit_offset = RoundUp(*bit_offset, kBitsPerByte);
200 out->resize(out->size() + byte_length);
201 MemoryRegion region(out->data() + *bit_offset / kBitsPerByte, byte_length);
202 *bit_offset += kBitsPerByte * byte_length;
203 return region;
204}
Calin Juravle4f46ac52015-04-23 18:47:21 +0100205
David Srbecky052f8ca2018-04-26 15:42:54 +0100206size_t StackMapStream::PrepareForFillIn() {
207 size_t bit_offset = 0;
208 out_.clear();
David Srbecky09ed0982016-02-12 21:58:43 +0000209
David Srbecky052f8ca2018-04-26 15:42:54 +0100210 // Decide the offsets of dex register map entries, but do not write them out yet.
211 // Needs to be done first as it modifies the stack map entry.
212 size_t dex_register_map_bytes = 0;
213 for (DexRegisterMapEntry& entry : dex_register_entries_) {
214 size_t size = entry.ComputeSize(location_catalog_entries_.size());
215 entry.offset = size == 0 ? DexRegisterMapEntry::kOffsetUnassigned : dex_register_map_bytes;
216 dex_register_map_bytes += size;
217 }
Calin Juravlec416d332015-04-23 16:01:43 +0100218
David Srbecky052f8ca2018-04-26 15:42:54 +0100219 // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires
220 // dex_method_index_idx to be filled in.
221 PrepareMethodIndices();
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800222
David Srbecky052f8ca2018-04-26 15:42:54 +0100223 // Dedup stack masks. Needs to be done first as it modifies the stack map entry.
David Srbecky4b59d102018-05-29 21:46:10 +0000224 BitmapTableBuilder stack_mask_builder(allocator_);
225 for (StackMapEntry& stack_map : stack_maps_) {
226 BitVector* mask = stack_map.sp_mask;
227 size_t num_bits = (mask != nullptr) ? mask->GetNumberOfBits() : 0;
228 if (num_bits != 0) {
229 stack_map.stack_mask_index = stack_mask_builder.Dedup(mask->GetRawStorage(), num_bits);
230 } else {
231 stack_map.stack_mask_index = StackMap::kNoValue;
232 }
233 }
Calin Juravlec416d332015-04-23 16:01:43 +0100234
David Srbecky052f8ca2018-04-26 15:42:54 +0100235 // Dedup register masks. Needs to be done first as it modifies the stack map entry.
David Srbecky4b59d102018-05-29 21:46:10 +0000236 BitTableBuilder<std::array<uint32_t, RegisterMask::kCount>> register_mask_builder(allocator_);
237 for (StackMapEntry& stack_map : stack_maps_) {
238 uint32_t register_mask = stack_map.register_mask;
239 if (register_mask != 0) {
240 uint32_t shift = LeastSignificantBit(register_mask);
241 std::array<uint32_t, RegisterMask::kCount> entry = {
242 register_mask >> shift,
243 shift,
244 };
245 stack_map.register_mask_index = register_mask_builder.Dedup(&entry);
246 } else {
247 stack_map.register_mask_index = StackMap::kNoValue;
248 }
249 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100250
David Srbecky21d45b42018-05-30 06:35:05 +0100251 // Allocate space for dex register maps.
252 EncodeMemoryRegion(&out_, &bit_offset, dex_register_map_bytes * kBitsPerByte);
David Srbecky052f8ca2018-04-26 15:42:54 +0100253
254 // Write dex register catalog.
255 EncodeVarintBits(&out_, &bit_offset, location_catalog_entries_.size());
256 size_t location_catalog_bytes = ComputeDexRegisterLocationCatalogSize();
257 MemoryRegion dex_register_location_catalog_region =
258 EncodeMemoryRegion(&out_, &bit_offset, location_catalog_bytes * kBitsPerByte);
Calin Juravlec416d332015-04-23 16:01:43 +0100259 DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
260 // Offset in `dex_register_location_catalog` where to store the next
261 // register location.
262 size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
Vladimir Marko225b6462015-09-28 12:17:40 +0100263 for (DexRegisterLocation dex_register_location : location_catalog_entries_) {
Calin Juravlec416d332015-04-23 16:01:43 +0100264 dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
265 location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
266 }
267 // Ensure we reached the end of the Dex registers location_catalog.
268 DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());
269
David Srbecky052f8ca2018-04-26 15:42:54 +0100270 // Write stack maps.
David Srbeckydd966bc2018-05-24 13:55:52 +0100271 BitTableBuilder<std::array<uint32_t, StackMap::kCount>> stack_map_builder(allocator_);
272 BitTableBuilder<std::array<uint32_t, InvokeInfo::kCount>> invoke_info_builder(allocator_);
273 BitTableBuilder<std::array<uint32_t, InlineInfo::kCount>> inline_info_builder(allocator_);
David Srbecky052f8ca2018-04-26 15:42:54 +0100274 for (const StackMapEntry& entry : stack_maps_) {
Andreas Gampee2abbc62017-09-15 11:59:26 -0700275 if (entry.dex_method_index != dex::kDexNoIndex) {
David Srbeckydd966bc2018-05-24 13:55:52 +0100276 std::array<uint32_t, InvokeInfo::kCount> invoke_info_entry {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100277 entry.packed_native_pc,
David Srbecky052f8ca2018-04-26 15:42:54 +0100278 entry.invoke_type,
David Srbeckydd966bc2018-05-24 13:55:52 +0100279 entry.dex_method_index_idx
280 };
281 invoke_info_builder.Add(invoke_info_entry);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800282 }
283
Calin Juravlec416d332015-04-23 16:01:43 +0100284 // Set the inlining info.
David Srbeckydd966bc2018-05-24 13:55:52 +0100285 uint32_t inline_info_index = inline_info_builder.size();
David Srbecky052f8ca2018-04-26 15:42:54 +0100286 DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size());
287 for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
288 InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index];
289 uint32_t method_index_idx = inline_entry.dex_method_index_idx;
290 uint32_t extra_data = 1;
291 if (inline_entry.method != nullptr) {
292 method_index_idx = High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method));
293 extra_data = Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method));
Calin Juravlec416d332015-04-23 16:01:43 +0100294 }
David Srbeckydd966bc2018-05-24 13:55:52 +0100295 std::array<uint32_t, InlineInfo::kCount> inline_info_entry {
David Srbecky052f8ca2018-04-26 15:42:54 +0100296 (depth == entry.inlining_depth - 1) ? InlineInfo::kLast : InlineInfo::kMore,
297 method_index_idx,
298 inline_entry.dex_pc,
299 extra_data,
David Srbeckydd966bc2018-05-24 13:55:52 +0100300 dex_register_entries_[inline_entry.dex_register_map_index].offset,
301 };
302 inline_info_builder.Add(inline_info_entry);
Calin Juravlec416d332015-04-23 16:01:43 +0100303 }
David Srbeckydd966bc2018-05-24 13:55:52 +0100304 std::array<uint32_t, StackMap::kCount> stack_map_entry {
David Srbeckyd02b23f2018-05-29 23:27:22 +0100305 entry.packed_native_pc,
David Srbecky052f8ca2018-04-26 15:42:54 +0100306 entry.dex_pc,
307 dex_register_entries_[entry.dex_register_map_index].offset,
David Srbeckydd966bc2018-05-24 13:55:52 +0100308 entry.inlining_depth != 0 ? inline_info_index : InlineInfo::kNoValue,
David Srbecky052f8ca2018-04-26 15:42:54 +0100309 entry.register_mask_index,
David Srbeckydd966bc2018-05-24 13:55:52 +0100310 entry.stack_mask_index,
311 };
312 stack_map_builder.Add(stack_map_entry);
Calin Juravlec416d332015-04-23 16:01:43 +0100313 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100314 stack_map_builder.Encode(&out_, &bit_offset);
315 invoke_info_builder.Encode(&out_, &bit_offset);
316 inline_info_builder.Encode(&out_, &bit_offset);
David Srbecky052f8ca2018-04-26 15:42:54 +0100317 register_mask_builder.Encode(&out_, &bit_offset);
David Srbecky4b59d102018-05-29 21:46:10 +0000318 stack_mask_builder.Encode(&out_, &bit_offset);
David Srbecky45aa5982016-03-18 02:15:09 +0000319
David Srbecky052f8ca2018-04-26 15:42:54 +0100320 return UnsignedLeb128Size(out_.size()) + out_.size();
321}
322
323void StackMapStream::FillInCodeInfo(MemoryRegion region) {
324 DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
325 DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before FillIn";
326 DCHECK_EQ(region.size(), UnsignedLeb128Size(out_.size()) + out_.size());
327
328 uint8_t* ptr = EncodeUnsignedLeb128(region.begin(), out_.size());
329 region.CopyFromVector(ptr - region.begin(), out_);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800330
David Srbecky21d45b42018-05-30 06:35:05 +0100331 // Write dex register maps.
332 CodeInfo code_info(region);
333 for (DexRegisterMapEntry& entry : dex_register_entries_) {
334 size_t entry_size = entry.ComputeSize(location_catalog_entries_.size());
335 if (entry_size != 0) {
336 DexRegisterMap dex_register_map(
337 code_info.dex_register_maps_.Subregion(entry.offset, entry_size),
338 entry.num_dex_registers,
339 code_info);
340 FillInDexRegisterMap(dex_register_map,
341 entry.num_dex_registers,
342 *entry.live_dex_registers_mask,
343 entry.locations_start_index);
344 }
345 }
346
David Srbecky1bbdfd72016-02-24 16:39:26 +0000347 // Verify all written data in debug build.
348 if (kIsDebugBuild) {
349 CheckCodeInfo(region);
350 }
Calin Juravlec416d332015-04-23 16:01:43 +0100351}
352
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100353void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
354 uint32_t num_dex_registers,
355 const BitVector& live_dex_registers_mask,
356 uint32_t start_index_in_dex_register_locations) const {
357 dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
358 // Set the dex register location mapping data.
Vladimir Marko225b6462015-09-28 12:17:40 +0100359 size_t number_of_live_dex_registers = live_dex_registers_mask.NumSetBits();
360 DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
361 DCHECK_LE(start_index_in_dex_register_locations,
362 dex_register_locations_.size() - number_of_live_dex_registers);
363 for (size_t index_in_dex_register_locations = 0;
364 index_in_dex_register_locations != number_of_live_dex_registers;
365 ++index_in_dex_register_locations) {
366 size_t location_catalog_entry_index = dex_register_locations_[
367 start_index_in_dex_register_locations + index_in_dex_register_locations];
368 dex_register_map.SetLocationCatalogEntryIndex(
369 index_in_dex_register_locations,
370 location_catalog_entry_index,
Vladimir Marko225b6462015-09-28 12:17:40 +0100371 location_catalog_entries_.size());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100372 }
373}
374
Mathieu Chartier32289082017-02-09 15:57:37 -0800375size_t StackMapStream::AddDexRegisterMapEntry(const DexRegisterMapEntry& entry) {
376 const size_t current_entry_index = dex_register_entries_.size();
377 auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.hash);
Calin Juravlec416d332015-04-23 16:01:43 +0100378 if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
379 // We don't have a perfect hash functions so we need a list to collect all stack maps
380 // which might have the same dex register map.
Vladimir Marko174b2e22017-10-12 13:34:49 +0100381 ScopedArenaVector<uint32_t> stack_map_indices(allocator_->Adapter(kArenaAllocStackMapStream));
Vladimir Marko225b6462015-09-28 12:17:40 +0100382 stack_map_indices.push_back(current_entry_index);
Mathieu Chartier32289082017-02-09 15:57:37 -0800383 dex_map_hash_to_stack_map_indices_.Put(entry.hash, std::move(stack_map_indices));
384 } else {
385 // We might have collisions, so we need to check whether or not we really have a match.
386 for (uint32_t test_entry_index : entries_it->second) {
387 if (DexRegisterMapEntryEquals(dex_register_entries_[test_entry_index], entry)) {
388 return test_entry_index;
389 }
Calin Juravlec416d332015-04-23 16:01:43 +0100390 }
Mathieu Chartier32289082017-02-09 15:57:37 -0800391 entries_it->second.push_back(current_entry_index);
Calin Juravlec416d332015-04-23 16:01:43 +0100392 }
Mathieu Chartier32289082017-02-09 15:57:37 -0800393 dex_register_entries_.push_back(entry);
394 return current_entry_index;
Calin Juravlec416d332015-04-23 16:01:43 +0100395}
396
Mathieu Chartier32289082017-02-09 15:57:37 -0800397bool StackMapStream::DexRegisterMapEntryEquals(const DexRegisterMapEntry& a,
398 const DexRegisterMapEntry& b) const {
399 if ((a.live_dex_registers_mask == nullptr) != (b.live_dex_registers_mask == nullptr)) {
Calin Juravlec416d332015-04-23 16:01:43 +0100400 return false;
401 }
402 if (a.num_dex_registers != b.num_dex_registers) {
403 return false;
404 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100405 if (a.num_dex_registers != 0u) {
406 DCHECK(a.live_dex_registers_mask != nullptr);
407 DCHECK(b.live_dex_registers_mask != nullptr);
408 if (!a.live_dex_registers_mask->Equal(b.live_dex_registers_mask)) {
Calin Juravlec416d332015-04-23 16:01:43 +0100409 return false;
410 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100411 size_t number_of_live_dex_registers = a.live_dex_registers_mask->NumSetBits();
412 DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
Mathieu Chartier32289082017-02-09 15:57:37 -0800413 DCHECK_LE(a.locations_start_index,
Vladimir Marko225b6462015-09-28 12:17:40 +0100414 dex_register_locations_.size() - number_of_live_dex_registers);
Mathieu Chartier32289082017-02-09 15:57:37 -0800415 DCHECK_LE(b.locations_start_index,
Vladimir Marko225b6462015-09-28 12:17:40 +0100416 dex_register_locations_.size() - number_of_live_dex_registers);
Mathieu Chartier32289082017-02-09 15:57:37 -0800417 auto a_begin = dex_register_locations_.begin() + a.locations_start_index;
418 auto b_begin = dex_register_locations_.begin() + b.locations_start_index;
Vladimir Marko225b6462015-09-28 12:17:40 +0100419 if (!std::equal(a_begin, a_begin + number_of_live_dex_registers, b_begin)) {
420 return false;
Calin Juravlec416d332015-04-23 16:01:43 +0100421 }
422 }
423 return true;
424}
425
David Srbecky1bbdfd72016-02-24 16:39:26 +0000426// Helper for CheckCodeInfo - check that register map has the expected content.
David Srbecky21d45b42018-05-30 06:35:05 +0100427void StackMapStream::CheckDexRegisterMap(const DexRegisterMap& dex_register_map,
David Srbecky1bbdfd72016-02-24 16:39:26 +0000428 size_t num_dex_registers,
429 BitVector* live_dex_registers_mask,
430 size_t dex_register_locations_index) const {
David Srbecky1bbdfd72016-02-24 16:39:26 +0000431 for (size_t reg = 0; reg < num_dex_registers; reg++) {
432 // Find the location we tried to encode.
433 DexRegisterLocation expected = DexRegisterLocation::None();
434 if (live_dex_registers_mask->IsBitSet(reg)) {
435 size_t catalog_index = dex_register_locations_[dex_register_locations_index++];
436 expected = location_catalog_entries_[catalog_index];
437 }
438 // Compare to the seen location.
439 if (expected.GetKind() == DexRegisterLocation::Kind::kNone) {
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800440 DCHECK(!dex_register_map.IsValid() || !dex_register_map.IsDexRegisterLive(reg))
441 << dex_register_map.IsValid() << " " << dex_register_map.IsDexRegisterLive(reg);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000442 } else {
443 DCHECK(dex_register_map.IsDexRegisterLive(reg));
David Srbecky21d45b42018-05-30 06:35:05 +0100444 DexRegisterLocation seen = dex_register_map.GetDexRegisterLocation(reg);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000445 DCHECK_EQ(expected.GetKind(), seen.GetKind());
446 DCHECK_EQ(expected.GetValue(), seen.GetValue());
447 }
448 }
449 if (num_dex_registers == 0) {
450 DCHECK(!dex_register_map.IsValid());
451 }
452}
453
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700454void StackMapStream::PrepareMethodIndices() {
455 CHECK(method_indices_.empty());
456 method_indices_.resize(stack_maps_.size() + inline_infos_.size());
Vladimir Marko174b2e22017-10-12 13:34:49 +0100457 ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream));
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700458 for (StackMapEntry& stack_map : stack_maps_) {
459 const size_t index = dedupe.size();
460 const uint32_t method_index = stack_map.dex_method_index;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700461 if (method_index != dex::kDexNoIndex) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700462 stack_map.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
463 method_indices_[index] = method_index;
464 }
465 }
466 for (InlineInfoEntry& inline_info : inline_infos_) {
467 const size_t index = dedupe.size();
468 const uint32_t method_index = inline_info.method_index;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700469 CHECK_NE(method_index, dex::kDexNoIndex);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700470 inline_info.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
471 method_indices_[index] = method_index;
472 }
473 method_indices_.resize(dedupe.size());
474}
475
David Srbecky1bbdfd72016-02-24 16:39:26 +0000476// Check that all StackMapStream inputs are correctly encoded by trying to read them back.
477void StackMapStream::CheckCodeInfo(MemoryRegion region) const {
478 CodeInfo code_info(region);
David Srbecky052f8ca2018-04-26 15:42:54 +0100479 DCHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size());
David Srbecky052f8ca2018-04-26 15:42:54 +0100480 DCHECK_EQ(code_info.GetNumberOfLocationCatalogEntries(), location_catalog_entries_.size());
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800481 size_t invoke_info_index = 0;
David Srbecky1bbdfd72016-02-24 16:39:26 +0000482 for (size_t s = 0; s < stack_maps_.size(); ++s) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100483 const StackMap stack_map = code_info.GetStackMapAt(s);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000484 StackMapEntry entry = stack_maps_[s];
485
486 // Check main stack map fields.
David Srbecky052f8ca2018-04-26 15:42:54 +0100487 DCHECK_EQ(stack_map.GetNativePcOffset(instruction_set_),
David Srbeckyd02b23f2018-05-29 23:27:22 +0100488 StackMap::UnpackNativePc(entry.packed_native_pc, instruction_set_));
David Srbecky052f8ca2018-04-26 15:42:54 +0100489 DCHECK_EQ(stack_map.GetDexPc(), entry.dex_pc);
490 DCHECK_EQ(stack_map.GetRegisterMaskIndex(), entry.register_mask_index);
491 DCHECK_EQ(code_info.GetRegisterMaskOf(stack_map), entry.register_mask);
David Srbecky052f8ca2018-04-26 15:42:54 +0100492 DCHECK_EQ(stack_map.GetStackMaskIndex(), entry.stack_mask_index);
493 BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000494 if (entry.sp_mask != nullptr) {
David Srbecky45aa5982016-03-18 02:15:09 +0000495 DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits());
David Srbecky4b59d102018-05-29 21:46:10 +0000496 for (size_t b = 0; b < stack_mask.size_in_bits(); b++) {
497 DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b)) << b;
David Srbecky1bbdfd72016-02-24 16:39:26 +0000498 }
499 } else {
David Srbecky4b59d102018-05-29 21:46:10 +0000500 DCHECK_EQ(stack_mask.size_in_bits(), 0u);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000501 }
Andreas Gampee2abbc62017-09-15 11:59:26 -0700502 if (entry.dex_method_index != dex::kDexNoIndex) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100503 InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index);
504 DCHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_),
David Srbeckyd02b23f2018-05-29 23:27:22 +0100505 StackMap::UnpackNativePc(entry.packed_native_pc, instruction_set_));
David Srbecky052f8ca2018-04-26 15:42:54 +0100506 DCHECK_EQ(invoke_info.GetInvokeType(), entry.invoke_type);
507 DCHECK_EQ(invoke_info.GetMethodIndexIdx(), entry.dex_method_index_idx);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800508 invoke_info_index++;
509 }
David Srbecky21d45b42018-05-30 06:35:05 +0100510 CheckDexRegisterMap(code_info.GetDexRegisterMapOf(
David Srbecky052f8ca2018-04-26 15:42:54 +0100511 stack_map, entry.dex_register_entry.num_dex_registers),
Mathieu Chartier32289082017-02-09 15:57:37 -0800512 entry.dex_register_entry.num_dex_registers,
513 entry.dex_register_entry.live_dex_registers_mask,
514 entry.dex_register_entry.locations_start_index);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000515
516 // Check inline info.
David Srbecky052f8ca2018-04-26 15:42:54 +0100517 DCHECK_EQ(stack_map.HasInlineInfo(), (entry.inlining_depth != 0));
David Srbecky1bbdfd72016-02-24 16:39:26 +0000518 if (entry.inlining_depth != 0) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100519 InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
520 DCHECK_EQ(inline_info.GetDepth(), entry.inlining_depth);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000521 for (size_t d = 0; d < entry.inlining_depth; ++d) {
522 size_t inline_info_index = entry.inline_infos_start_index + d;
523 DCHECK_LT(inline_info_index, inline_infos_.size());
524 InlineInfoEntry inline_entry = inline_infos_[inline_info_index];
David Srbecky052f8ca2018-04-26 15:42:54 +0100525 DCHECK_EQ(inline_info.GetDexPcAtDepth(d), inline_entry.dex_pc);
526 if (inline_info.EncodesArtMethodAtDepth(d)) {
527 DCHECK_EQ(inline_info.GetArtMethodAtDepth(d),
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000528 inline_entry.method);
529 } else {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700530 const size_t method_index_idx =
David Srbecky052f8ca2018-04-26 15:42:54 +0100531 inline_info.GetMethodIndexIdxAtDepth(d);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700532 DCHECK_EQ(method_index_idx, inline_entry.dex_method_index_idx);
533 DCHECK_EQ(method_indices_[method_index_idx], inline_entry.method_index);
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000534 }
David Srbecky1bbdfd72016-02-24 16:39:26 +0000535
David Srbecky21d45b42018-05-30 06:35:05 +0100536 CheckDexRegisterMap(code_info.GetDexRegisterMapAtDepth(
Mathieu Chartier32289082017-02-09 15:57:37 -0800537 d,
538 inline_info,
Mathieu Chartier32289082017-02-09 15:57:37 -0800539 inline_entry.dex_register_entry.num_dex_registers),
540 inline_entry.dex_register_entry.num_dex_registers,
541 inline_entry.dex_register_entry.live_dex_registers_mask,
542 inline_entry.dex_register_entry.locations_start_index);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000543 }
544 }
545 }
546}
547
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700548size_t StackMapStream::ComputeMethodInfoSize() const {
David Srbecky052f8ca2018-04-26 15:42:54 +0100549 DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before " << __FUNCTION__;
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700550 return MethodInfo::ComputeSize(method_indices_.size());
551}
552
Calin Juravlec416d332015-04-23 16:01:43 +0100553} // namespace art