blob: c6e375a1b27c63703da9f8d6524b4a5eeca3bd2f [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
Calin Juravle4f46ac52015-04-23 18:47:21 +010028void StackMapStream::BeginStackMapEntry(uint32_t dex_pc,
29 uint32_t native_pc_offset,
30 uint32_t register_mask,
31 BitVector* sp_mask,
32 uint32_t num_dex_registers,
33 uint8_t inlining_depth) {
34 DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
35 current_entry_.dex_pc = dex_pc;
Mathieu Chartiera2f526f2017-01-19 14:48:48 -080036 current_entry_.native_pc_code_offset = CodeOffset::FromOffset(native_pc_offset, instruction_set_);
Calin Juravle4f46ac52015-04-23 18:47:21 +010037 current_entry_.register_mask = register_mask;
38 current_entry_.sp_mask = sp_mask;
Calin Juravle4f46ac52015-04-23 18:47:21 +010039 current_entry_.inlining_depth = inlining_depth;
Vladimir Marko225b6462015-09-28 12:17:40 +010040 current_entry_.inline_infos_start_index = inline_infos_.size();
David Srbecky45aa5982016-03-18 02:15:09 +000041 current_entry_.stack_mask_index = 0;
Andreas Gampee2abbc62017-09-15 11:59:26 -070042 current_entry_.dex_method_index = dex::kDexNoIndex;
Mathieu Chartier32289082017-02-09 15:57:37 -080043 current_entry_.dex_register_entry.num_dex_registers = num_dex_registers;
44 current_entry_.dex_register_entry.locations_start_index = dex_register_locations_.size();
Vladimir Marko174b2e22017-10-12 13:34:49 +010045 current_entry_.dex_register_entry.live_dex_registers_mask = nullptr;
46 if (num_dex_registers != 0u) {
47 current_entry_.dex_register_entry.live_dex_registers_mask =
48 ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream);
49 current_entry_.dex_register_entry.live_dex_registers_mask->ClearAllBits();
50 }
Vladimir Marko8b20b5c2018-05-29 15:32:55 +000051 if (sp_mask != nullptr) {
52 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
53 }
54
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010055 current_dex_register_ = 0;
Calin Juravlec416d332015-04-23 16:01:43 +010056}
57
Calin Juravle4f46ac52015-04-23 18:47:21 +010058void StackMapStream::EndStackMapEntry() {
Mathieu Chartier32289082017-02-09 15:57:37 -080059 current_entry_.dex_register_map_index = AddDexRegisterMapEntry(current_entry_.dex_register_entry);
Vladimir Marko225b6462015-09-28 12:17:40 +010060 stack_maps_.push_back(current_entry_);
Calin Juravle4f46ac52015-04-23 18:47:21 +010061 current_entry_ = StackMapEntry();
62}
63
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010064void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
Calin Juravlec416d332015-04-23 16:01:43 +010065 if (kind != DexRegisterLocation::Kind::kNone) {
66 // Ensure we only use non-compressed location kind at this stage.
David Srbecky7dc11782016-02-25 13:23:56 +000067 DCHECK(DexRegisterLocation::IsShortLocationKind(kind)) << kind;
Calin Juravlec416d332015-04-23 16:01:43 +010068 DexRegisterLocation location(kind, value);
69
70 // Look for Dex register `location` in the location catalog (using the
71 // companion hash map of locations to indices). Use its index if it
72 // is already in the location catalog. If not, insert it (in the
73 // location catalog and the hash map) and use the newly created index.
74 auto it = location_catalog_entries_indices_.Find(location);
75 if (it != location_catalog_entries_indices_.end()) {
76 // Retrieve the index from the hash map.
Vladimir Marko225b6462015-09-28 12:17:40 +010077 dex_register_locations_.push_back(it->second);
Calin Juravlec416d332015-04-23 16:01:43 +010078 } else {
79 // Create a new entry in the location catalog and the hash map.
Vladimir Marko225b6462015-09-28 12:17:40 +010080 size_t index = location_catalog_entries_.size();
81 location_catalog_entries_.push_back(location);
82 dex_register_locations_.push_back(index);
Calin Juravlec416d332015-04-23 16:01:43 +010083 location_catalog_entries_indices_.Insert(std::make_pair(location, index));
84 }
Mathieu Chartier32289082017-02-09 15:57:37 -080085 DexRegisterMapEntry* const entry = in_inline_frame_
86 ? &current_inline_info_.dex_register_entry
87 : &current_entry_.dex_register_entry;
88 DCHECK_LT(current_dex_register_, entry->num_dex_registers);
89 entry->live_dex_registers_mask->SetBit(current_dex_register_);
90 entry->hash += (1 <<
91 (current_dex_register_ % (sizeof(DexRegisterMapEntry::hash) * kBitsPerByte)));
92 entry->hash += static_cast<uint32_t>(value);
93 entry->hash += static_cast<uint32_t>(kind);
Calin Juravlec416d332015-04-23 16:01:43 +010094 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +010095 current_dex_register_++;
Calin Juravlec416d332015-04-23 16:01:43 +010096}
97
Mathieu Chartierd776ff02017-01-17 09:32:18 -080098void StackMapStream::AddInvoke(InvokeType invoke_type, uint32_t dex_method_index) {
99 current_entry_.invoke_type = invoke_type;
100 current_entry_.dex_method_index = dex_method_index;
101}
102
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000103void StackMapStream::BeginInlineInfoEntry(ArtMethod* method,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100104 uint32_t dex_pc,
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000105 uint32_t num_dex_registers,
106 const DexFile* outer_dex_file) {
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100107 DCHECK(!in_inline_frame_);
108 in_inline_frame_ = true;
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000109 if (EncodeArtMethodInInlineInfo(method)) {
110 current_inline_info_.method = method;
111 } else {
112 if (dex_pc != static_cast<uint32_t>(-1) && kIsDebugBuild) {
113 ScopedObjectAccess soa(Thread::Current());
114 DCHECK(IsSameDexFile(*outer_dex_file, *method->GetDexFile()));
115 }
116 current_inline_info_.method_index = method->GetDexMethodIndexUnchecked();
117 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100118 current_inline_info_.dex_pc = dex_pc;
Mathieu Chartier32289082017-02-09 15:57:37 -0800119 current_inline_info_.dex_register_entry.num_dex_registers = num_dex_registers;
120 current_inline_info_.dex_register_entry.locations_start_index = dex_register_locations_.size();
Vladimir Marko174b2e22017-10-12 13:34:49 +0100121 current_inline_info_.dex_register_entry.live_dex_registers_mask = nullptr;
122 if (num_dex_registers != 0) {
123 current_inline_info_.dex_register_entry.live_dex_registers_mask =
124 ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream);
125 current_inline_info_.dex_register_entry.live_dex_registers_mask->ClearAllBits();
126 }
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100127 current_dex_register_ = 0;
128}
129
130void StackMapStream::EndInlineInfoEntry() {
Mathieu Chartier32289082017-02-09 15:57:37 -0800131 current_inline_info_.dex_register_map_index =
132 AddDexRegisterMapEntry(current_inline_info_.dex_register_entry);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100133 DCHECK(in_inline_frame_);
Mathieu Chartier32289082017-02-09 15:57:37 -0800134 DCHECK_EQ(current_dex_register_, current_inline_info_.dex_register_entry.num_dex_registers)
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100135 << "Inline information contains less registers than expected";
136 in_inline_frame_ = false;
Vladimir Marko225b6462015-09-28 12:17:40 +0100137 inline_infos_.push_back(current_inline_info_);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100138 current_inline_info_ = InlineInfoEntry();
Calin Juravlec416d332015-04-23 16:01:43 +0100139}
140
Calin Juravlec416d332015-04-23 16:01:43 +0100141size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const {
142 size_t size = DexRegisterLocationCatalog::kFixedSize;
Vladimir Marko225b6462015-09-28 12:17:40 +0100143 for (const DexRegisterLocation& dex_register_location : location_catalog_entries_) {
Calin Juravlec416d332015-04-23 16:01:43 +0100144 size += DexRegisterLocationCatalog::EntrySize(dex_register_location);
145 }
146 return size;
147}
148
Mathieu Chartier32289082017-02-09 15:57:37 -0800149size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) const {
Vladimir Marko225b6462015-09-28 12:17:40 +0100150 // For num_dex_registers == 0u live_dex_registers_mask may be null.
151 if (num_dex_registers == 0u) {
152 return 0u; // No register map will be emitted.
153 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100154 size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits();
155 if (live_dex_registers_mask->NumSetBits() == 0) {
156 return 0u; // No register map will be emitted.
157 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100158 DCHECK(live_dex_registers_mask != nullptr);
159
Calin Juravlec416d332015-04-23 16:01:43 +0100160 // Size of the map in bytes.
161 size_t size = DexRegisterMap::kFixedSize;
162 // Add the live bit mask for the Dex register liveness.
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100163 size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
Calin Juravlec416d332015-04-23 16:01:43 +0100164 // Compute the size of the set of live Dex register entries.
Calin Juravlec416d332015-04-23 16:01:43 +0100165 size_t map_entries_size_in_bits =
Mathieu Chartier32289082017-02-09 15:57:37 -0800166 DexRegisterMap::SingleEntrySizeInBits(catalog_size) * number_of_live_dex_registers;
Calin Juravlec416d332015-04-23 16:01:43 +0100167 size_t map_entries_size_in_bytes =
168 RoundUp(map_entries_size_in_bits, kBitsPerByte) / kBitsPerByte;
169 size += map_entries_size_in_bytes;
170 return size;
171}
172
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700173void StackMapStream::FillInMethodInfo(MemoryRegion region) {
174 {
175 MethodInfo info(region.begin(), method_indices_.size());
176 for (size_t i = 0; i < method_indices_.size(); ++i) {
177 info.SetMethodIndex(i, method_indices_[i]);
178 }
179 }
180 if (kIsDebugBuild) {
181 // Check the data matches.
182 MethodInfo info(region.begin());
183 const size_t count = info.NumMethodIndices();
184 DCHECK_EQ(count, method_indices_.size());
185 for (size_t i = 0; i < count; ++i) {
186 DCHECK_EQ(info.GetMethodIndex(i), method_indices_[i]);
187 }
188 }
189}
190
David Srbecky052f8ca2018-04-26 15:42:54 +0100191template<typename Vector>
192static MemoryRegion EncodeMemoryRegion(Vector* out, size_t* bit_offset, uint32_t bit_length) {
193 uint32_t byte_length = BitsToBytesRoundUp(bit_length);
194 EncodeVarintBits(out, bit_offset, byte_length);
195 *bit_offset = RoundUp(*bit_offset, kBitsPerByte);
196 out->resize(out->size() + byte_length);
197 MemoryRegion region(out->data() + *bit_offset / kBitsPerByte, byte_length);
198 *bit_offset += kBitsPerByte * byte_length;
199 return region;
200}
Calin Juravle4f46ac52015-04-23 18:47:21 +0100201
David Srbecky052f8ca2018-04-26 15:42:54 +0100202size_t StackMapStream::PrepareForFillIn() {
203 size_t bit_offset = 0;
204 out_.clear();
David Srbecky09ed0982016-02-12 21:58:43 +0000205
David Srbecky052f8ca2018-04-26 15:42:54 +0100206 // Decide the offsets of dex register map entries, but do not write them out yet.
207 // Needs to be done first as it modifies the stack map entry.
208 size_t dex_register_map_bytes = 0;
209 for (DexRegisterMapEntry& entry : dex_register_entries_) {
210 size_t size = entry.ComputeSize(location_catalog_entries_.size());
211 entry.offset = size == 0 ? DexRegisterMapEntry::kOffsetUnassigned : dex_register_map_bytes;
212 dex_register_map_bytes += size;
213 }
Calin Juravlec416d332015-04-23 16:01:43 +0100214
David Srbecky052f8ca2018-04-26 15:42:54 +0100215 // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires
216 // dex_method_index_idx to be filled in.
217 PrepareMethodIndices();
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800218
David Srbecky052f8ca2018-04-26 15:42:54 +0100219 // Dedup stack masks. Needs to be done first as it modifies the stack map entry.
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000220 size_t stack_mask_bits = stack_mask_max_ + 1; // Need room for max element too.
221 size_t num_stack_masks = PrepareStackMasks(stack_mask_bits);
Calin Juravlec416d332015-04-23 16:01:43 +0100222
David Srbecky052f8ca2018-04-26 15:42:54 +0100223 // Dedup register masks. Needs to be done first as it modifies the stack map entry.
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000224 size_t num_register_masks = PrepareRegisterMasks();
David Srbecky052f8ca2018-04-26 15:42:54 +0100225
226 // Write dex register maps.
227 MemoryRegion dex_register_map_region =
228 EncodeMemoryRegion(&out_, &bit_offset, dex_register_map_bytes * kBitsPerByte);
229 for (DexRegisterMapEntry& entry : dex_register_entries_) {
230 size_t entry_size = entry.ComputeSize(location_catalog_entries_.size());
231 if (entry_size != 0) {
232 DexRegisterMap dex_register_map(
233 dex_register_map_region.Subregion(entry.offset, entry_size));
234 FillInDexRegisterMap(dex_register_map,
235 entry.num_dex_registers,
236 *entry.live_dex_registers_mask,
237 entry.locations_start_index);
238 }
239 }
240
241 // Write dex register catalog.
242 EncodeVarintBits(&out_, &bit_offset, location_catalog_entries_.size());
243 size_t location_catalog_bytes = ComputeDexRegisterLocationCatalogSize();
244 MemoryRegion dex_register_location_catalog_region =
245 EncodeMemoryRegion(&out_, &bit_offset, location_catalog_bytes * kBitsPerByte);
Calin Juravlec416d332015-04-23 16:01:43 +0100246 DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region);
247 // Offset in `dex_register_location_catalog` where to store the next
248 // register location.
249 size_t location_catalog_offset = DexRegisterLocationCatalog::kFixedSize;
Vladimir Marko225b6462015-09-28 12:17:40 +0100250 for (DexRegisterLocation dex_register_location : location_catalog_entries_) {
Calin Juravlec416d332015-04-23 16:01:43 +0100251 dex_register_location_catalog.SetRegisterInfo(location_catalog_offset, dex_register_location);
252 location_catalog_offset += DexRegisterLocationCatalog::EntrySize(dex_register_location);
253 }
254 // Ensure we reached the end of the Dex registers location_catalog.
255 DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size());
256
David Srbecky052f8ca2018-04-26 15:42:54 +0100257 // Write stack maps.
David Srbeckydd966bc2018-05-24 13:55:52 +0100258 BitTableBuilder<std::array<uint32_t, StackMap::kCount>> stack_map_builder(allocator_);
259 BitTableBuilder<std::array<uint32_t, InvokeInfo::kCount>> invoke_info_builder(allocator_);
260 BitTableBuilder<std::array<uint32_t, InlineInfo::kCount>> inline_info_builder(allocator_);
David Srbecky052f8ca2018-04-26 15:42:54 +0100261 for (const StackMapEntry& entry : stack_maps_) {
Andreas Gampee2abbc62017-09-15 11:59:26 -0700262 if (entry.dex_method_index != dex::kDexNoIndex) {
David Srbeckydd966bc2018-05-24 13:55:52 +0100263 std::array<uint32_t, InvokeInfo::kCount> invoke_info_entry {
David Srbecky052f8ca2018-04-26 15:42:54 +0100264 entry.native_pc_code_offset.CompressedValue(),
265 entry.invoke_type,
David Srbeckydd966bc2018-05-24 13:55:52 +0100266 entry.dex_method_index_idx
267 };
268 invoke_info_builder.Add(invoke_info_entry);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800269 }
270
Calin Juravlec416d332015-04-23 16:01:43 +0100271 // Set the inlining info.
David Srbeckydd966bc2018-05-24 13:55:52 +0100272 uint32_t inline_info_index = inline_info_builder.size();
David Srbecky052f8ca2018-04-26 15:42:54 +0100273 DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size());
274 for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
275 InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index];
276 uint32_t method_index_idx = inline_entry.dex_method_index_idx;
277 uint32_t extra_data = 1;
278 if (inline_entry.method != nullptr) {
279 method_index_idx = High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method));
280 extra_data = Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method));
Calin Juravlec416d332015-04-23 16:01:43 +0100281 }
David Srbeckydd966bc2018-05-24 13:55:52 +0100282 std::array<uint32_t, InlineInfo::kCount> inline_info_entry {
David Srbecky052f8ca2018-04-26 15:42:54 +0100283 (depth == entry.inlining_depth - 1) ? InlineInfo::kLast : InlineInfo::kMore,
284 method_index_idx,
285 inline_entry.dex_pc,
286 extra_data,
David Srbeckydd966bc2018-05-24 13:55:52 +0100287 dex_register_entries_[inline_entry.dex_register_map_index].offset,
288 };
289 inline_info_builder.Add(inline_info_entry);
Calin Juravlec416d332015-04-23 16:01:43 +0100290 }
David Srbeckydd966bc2018-05-24 13:55:52 +0100291 std::array<uint32_t, StackMap::kCount> stack_map_entry {
David Srbecky052f8ca2018-04-26 15:42:54 +0100292 entry.native_pc_code_offset.CompressedValue(),
293 entry.dex_pc,
294 dex_register_entries_[entry.dex_register_map_index].offset,
David Srbeckydd966bc2018-05-24 13:55:52 +0100295 entry.inlining_depth != 0 ? inline_info_index : InlineInfo::kNoValue,
David Srbecky052f8ca2018-04-26 15:42:54 +0100296 entry.register_mask_index,
David Srbeckydd966bc2018-05-24 13:55:52 +0100297 entry.stack_mask_index,
298 };
299 stack_map_builder.Add(stack_map_entry);
Calin Juravlec416d332015-04-23 16:01:43 +0100300 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100301 stack_map_builder.Encode(&out_, &bit_offset);
302 invoke_info_builder.Encode(&out_, &bit_offset);
303 inline_info_builder.Encode(&out_, &bit_offset);
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000304
305 // Write register masks table.
306 BitTableBuilder<uint32_t> register_mask_builder(allocator_);
307 for (size_t i = 0; i < num_register_masks; ++i) {
308 register_mask_builder.Add(register_masks_[i]);
309 }
David Srbecky052f8ca2018-04-26 15:42:54 +0100310 register_mask_builder.Encode(&out_, &bit_offset);
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000311
312 // Write stack masks table.
313 EncodeVarintBits(&out_, &bit_offset, stack_mask_bits);
314 out_.resize(BitsToBytesRoundUp(bit_offset + stack_mask_bits * num_stack_masks));
315 BitMemoryRegion stack_mask_region(MemoryRegion(out_.data(), out_.size()),
316 bit_offset,
317 stack_mask_bits * num_stack_masks);
318 if (stack_mask_bits > 0) {
319 for (size_t i = 0; i < num_stack_masks; ++i) {
320 size_t stack_mask_bytes = BitsToBytesRoundUp(stack_mask_bits);
321 BitMemoryRegion src(MemoryRegion(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes));
322 BitMemoryRegion dst = stack_mask_region.Subregion(i * stack_mask_bits, stack_mask_bits);
323 for (size_t bit_index = 0; bit_index < stack_mask_bits; bit_index += BitSizeOf<uint32_t>()) {
324 size_t num_bits = std::min<size_t>(stack_mask_bits - bit_index, BitSizeOf<uint32_t>());
325 dst.StoreBits(bit_index, src.LoadBits(bit_index, num_bits), num_bits);
326 }
327 }
328 }
David Srbecky45aa5982016-03-18 02:15:09 +0000329
David Srbecky052f8ca2018-04-26 15:42:54 +0100330 return UnsignedLeb128Size(out_.size()) + out_.size();
331}
332
333void StackMapStream::FillInCodeInfo(MemoryRegion region) {
334 DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry";
335 DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before FillIn";
336 DCHECK_EQ(region.size(), UnsignedLeb128Size(out_.size()) + out_.size());
337
338 uint8_t* ptr = EncodeUnsignedLeb128(region.begin(), out_.size());
339 region.CopyFromVector(ptr - region.begin(), out_);
Mathieu Chartier1a20b682017-01-31 14:25:16 -0800340
David Srbecky1bbdfd72016-02-24 16:39:26 +0000341 // Verify all written data in debug build.
342 if (kIsDebugBuild) {
343 CheckCodeInfo(region);
344 }
Calin Juravlec416d332015-04-23 16:01:43 +0100345}
346
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100347void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
348 uint32_t num_dex_registers,
349 const BitVector& live_dex_registers_mask,
350 uint32_t start_index_in_dex_register_locations) const {
351 dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
352 // Set the dex register location mapping data.
Vladimir Marko225b6462015-09-28 12:17:40 +0100353 size_t number_of_live_dex_registers = live_dex_registers_mask.NumSetBits();
354 DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
355 DCHECK_LE(start_index_in_dex_register_locations,
356 dex_register_locations_.size() - number_of_live_dex_registers);
357 for (size_t index_in_dex_register_locations = 0;
358 index_in_dex_register_locations != number_of_live_dex_registers;
359 ++index_in_dex_register_locations) {
360 size_t location_catalog_entry_index = dex_register_locations_[
361 start_index_in_dex_register_locations + index_in_dex_register_locations];
362 dex_register_map.SetLocationCatalogEntryIndex(
363 index_in_dex_register_locations,
364 location_catalog_entry_index,
365 num_dex_registers,
366 location_catalog_entries_.size());
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100367 }
368}
369
Mathieu Chartier32289082017-02-09 15:57:37 -0800370size_t StackMapStream::AddDexRegisterMapEntry(const DexRegisterMapEntry& entry) {
371 const size_t current_entry_index = dex_register_entries_.size();
372 auto entries_it = dex_map_hash_to_stack_map_indices_.find(entry.hash);
Calin Juravlec416d332015-04-23 16:01:43 +0100373 if (entries_it == dex_map_hash_to_stack_map_indices_.end()) {
374 // We don't have a perfect hash functions so we need a list to collect all stack maps
375 // which might have the same dex register map.
Vladimir Marko174b2e22017-10-12 13:34:49 +0100376 ScopedArenaVector<uint32_t> stack_map_indices(allocator_->Adapter(kArenaAllocStackMapStream));
Vladimir Marko225b6462015-09-28 12:17:40 +0100377 stack_map_indices.push_back(current_entry_index);
Mathieu Chartier32289082017-02-09 15:57:37 -0800378 dex_map_hash_to_stack_map_indices_.Put(entry.hash, std::move(stack_map_indices));
379 } else {
380 // We might have collisions, so we need to check whether or not we really have a match.
381 for (uint32_t test_entry_index : entries_it->second) {
382 if (DexRegisterMapEntryEquals(dex_register_entries_[test_entry_index], entry)) {
383 return test_entry_index;
384 }
Calin Juravlec416d332015-04-23 16:01:43 +0100385 }
Mathieu Chartier32289082017-02-09 15:57:37 -0800386 entries_it->second.push_back(current_entry_index);
Calin Juravlec416d332015-04-23 16:01:43 +0100387 }
Mathieu Chartier32289082017-02-09 15:57:37 -0800388 dex_register_entries_.push_back(entry);
389 return current_entry_index;
Calin Juravlec416d332015-04-23 16:01:43 +0100390}
391
Mathieu Chartier32289082017-02-09 15:57:37 -0800392bool StackMapStream::DexRegisterMapEntryEquals(const DexRegisterMapEntry& a,
393 const DexRegisterMapEntry& b) const {
394 if ((a.live_dex_registers_mask == nullptr) != (b.live_dex_registers_mask == nullptr)) {
Calin Juravlec416d332015-04-23 16:01:43 +0100395 return false;
396 }
397 if (a.num_dex_registers != b.num_dex_registers) {
398 return false;
399 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100400 if (a.num_dex_registers != 0u) {
401 DCHECK(a.live_dex_registers_mask != nullptr);
402 DCHECK(b.live_dex_registers_mask != nullptr);
403 if (!a.live_dex_registers_mask->Equal(b.live_dex_registers_mask)) {
Calin Juravlec416d332015-04-23 16:01:43 +0100404 return false;
405 }
Vladimir Marko225b6462015-09-28 12:17:40 +0100406 size_t number_of_live_dex_registers = a.live_dex_registers_mask->NumSetBits();
407 DCHECK_LE(number_of_live_dex_registers, dex_register_locations_.size());
Mathieu Chartier32289082017-02-09 15:57:37 -0800408 DCHECK_LE(a.locations_start_index,
Vladimir Marko225b6462015-09-28 12:17:40 +0100409 dex_register_locations_.size() - number_of_live_dex_registers);
Mathieu Chartier32289082017-02-09 15:57:37 -0800410 DCHECK_LE(b.locations_start_index,
Vladimir Marko225b6462015-09-28 12:17:40 +0100411 dex_register_locations_.size() - number_of_live_dex_registers);
Mathieu Chartier32289082017-02-09 15:57:37 -0800412 auto a_begin = dex_register_locations_.begin() + a.locations_start_index;
413 auto b_begin = dex_register_locations_.begin() + b.locations_start_index;
Vladimir Marko225b6462015-09-28 12:17:40 +0100414 if (!std::equal(a_begin, a_begin + number_of_live_dex_registers, b_begin)) {
415 return false;
Calin Juravlec416d332015-04-23 16:01:43 +0100416 }
417 }
418 return true;
419}
420
David Srbecky1bbdfd72016-02-24 16:39:26 +0000421// Helper for CheckCodeInfo - check that register map has the expected content.
422void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info,
423 const DexRegisterMap& dex_register_map,
424 size_t num_dex_registers,
425 BitVector* live_dex_registers_mask,
426 size_t dex_register_locations_index) const {
David Srbecky1bbdfd72016-02-24 16:39:26 +0000427 for (size_t reg = 0; reg < num_dex_registers; reg++) {
428 // Find the location we tried to encode.
429 DexRegisterLocation expected = DexRegisterLocation::None();
430 if (live_dex_registers_mask->IsBitSet(reg)) {
431 size_t catalog_index = dex_register_locations_[dex_register_locations_index++];
432 expected = location_catalog_entries_[catalog_index];
433 }
434 // Compare to the seen location.
435 if (expected.GetKind() == DexRegisterLocation::Kind::kNone) {
Mathieu Chartier575d3e62017-02-06 11:00:40 -0800436 DCHECK(!dex_register_map.IsValid() || !dex_register_map.IsDexRegisterLive(reg))
437 << dex_register_map.IsValid() << " " << dex_register_map.IsDexRegisterLive(reg);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000438 } else {
439 DCHECK(dex_register_map.IsDexRegisterLive(reg));
440 DexRegisterLocation seen = dex_register_map.GetDexRegisterLocation(
David Srbecky052f8ca2018-04-26 15:42:54 +0100441 reg, num_dex_registers, code_info);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000442 DCHECK_EQ(expected.GetKind(), seen.GetKind());
443 DCHECK_EQ(expected.GetValue(), seen.GetValue());
444 }
445 }
446 if (num_dex_registers == 0) {
447 DCHECK(!dex_register_map.IsValid());
448 }
449}
450
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000451size_t StackMapStream::PrepareRegisterMasks() {
452 register_masks_.resize(stack_maps_.size(), 0u);
453 ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream));
454 for (StackMapEntry& stack_map : stack_maps_) {
455 const size_t index = dedupe.size();
456 stack_map.register_mask_index = dedupe.emplace(stack_map.register_mask, index).first->second;
457 register_masks_[index] = stack_map.register_mask;
458 }
459 return dedupe.size();
460}
461
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700462void StackMapStream::PrepareMethodIndices() {
463 CHECK(method_indices_.empty());
464 method_indices_.resize(stack_maps_.size() + inline_infos_.size());
Vladimir Marko174b2e22017-10-12 13:34:49 +0100465 ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream));
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700466 for (StackMapEntry& stack_map : stack_maps_) {
467 const size_t index = dedupe.size();
468 const uint32_t method_index = stack_map.dex_method_index;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700469 if (method_index != dex::kDexNoIndex) {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700470 stack_map.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
471 method_indices_[index] = method_index;
472 }
473 }
474 for (InlineInfoEntry& inline_info : inline_infos_) {
475 const size_t index = dedupe.size();
476 const uint32_t method_index = inline_info.method_index;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700477 CHECK_NE(method_index, dex::kDexNoIndex);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700478 inline_info.dex_method_index_idx = dedupe.emplace(method_index, index).first->second;
479 method_indices_[index] = method_index;
480 }
481 method_indices_.resize(dedupe.size());
482}
483
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000484
485size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) {
486 // Preallocate memory since we do not want it to move (the dedup map will point into it).
487 const size_t byte_entry_size = RoundUp(entry_size_in_bits, kBitsPerByte) / kBitsPerByte;
488 stack_masks_.resize(byte_entry_size * stack_maps_.size(), 0u);
489 // For deduplicating we store the stack masks as byte packed for simplicity. We can bit pack later
490 // when copying out from stack_masks_.
491 ScopedArenaUnorderedMap<MemoryRegion,
492 size_t,
493 FNVHash<MemoryRegion>,
494 MemoryRegion::ContentEquals> dedup(
495 stack_maps_.size(), allocator_->Adapter(kArenaAllocStackMapStream));
496 for (StackMapEntry& stack_map : stack_maps_) {
497 size_t index = dedup.size();
498 MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size);
499 BitMemoryRegion stack_mask_bits(stack_mask);
500 for (size_t i = 0; i < entry_size_in_bits; i++) {
501 stack_mask_bits.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i));
502 }
503 stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second;
504 }
505 return dedup.size();
506}
507
David Srbecky1bbdfd72016-02-24 16:39:26 +0000508// Check that all StackMapStream inputs are correctly encoded by trying to read them back.
509void StackMapStream::CheckCodeInfo(MemoryRegion region) const {
510 CodeInfo code_info(region);
David Srbecky052f8ca2018-04-26 15:42:54 +0100511 DCHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size());
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000512 DCHECK_EQ(code_info.GetNumberOfStackMaskBits(), static_cast<uint32_t>(stack_mask_max_ + 1));
David Srbecky052f8ca2018-04-26 15:42:54 +0100513 DCHECK_EQ(code_info.GetNumberOfLocationCatalogEntries(), location_catalog_entries_.size());
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800514 size_t invoke_info_index = 0;
David Srbecky1bbdfd72016-02-24 16:39:26 +0000515 for (size_t s = 0; s < stack_maps_.size(); ++s) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100516 const StackMap stack_map = code_info.GetStackMapAt(s);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000517 StackMapEntry entry = stack_maps_[s];
518
519 // Check main stack map fields.
David Srbecky052f8ca2018-04-26 15:42:54 +0100520 DCHECK_EQ(stack_map.GetNativePcOffset(instruction_set_),
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800521 entry.native_pc_code_offset.Uint32Value(instruction_set_));
David Srbecky052f8ca2018-04-26 15:42:54 +0100522 DCHECK_EQ(stack_map.GetDexPc(), entry.dex_pc);
523 DCHECK_EQ(stack_map.GetRegisterMaskIndex(), entry.register_mask_index);
524 DCHECK_EQ(code_info.GetRegisterMaskOf(stack_map), entry.register_mask);
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000525 const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits();
David Srbecky052f8ca2018-04-26 15:42:54 +0100526 DCHECK_EQ(stack_map.GetStackMaskIndex(), entry.stack_mask_index);
527 BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000528 if (entry.sp_mask != nullptr) {
David Srbecky45aa5982016-03-18 02:15:09 +0000529 DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits());
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000530 for (size_t b = 0; b < num_stack_mask_bits; b++) {
531 DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b));
David Srbecky1bbdfd72016-02-24 16:39:26 +0000532 }
533 } else {
Vladimir Marko8b20b5c2018-05-29 15:32:55 +0000534 for (size_t b = 0; b < num_stack_mask_bits; b++) {
535 DCHECK_EQ(stack_mask.LoadBit(b), 0u);
536 }
David Srbecky1bbdfd72016-02-24 16:39:26 +0000537 }
Andreas Gampee2abbc62017-09-15 11:59:26 -0700538 if (entry.dex_method_index != dex::kDexNoIndex) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100539 InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index);
540 DCHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_),
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800541 entry.native_pc_code_offset.Uint32Value(instruction_set_));
David Srbecky052f8ca2018-04-26 15:42:54 +0100542 DCHECK_EQ(invoke_info.GetInvokeType(), entry.invoke_type);
543 DCHECK_EQ(invoke_info.GetMethodIndexIdx(), entry.dex_method_index_idx);
Mathieu Chartierd776ff02017-01-17 09:32:18 -0800544 invoke_info_index++;
545 }
David Srbecky1bbdfd72016-02-24 16:39:26 +0000546 CheckDexRegisterMap(code_info,
547 code_info.GetDexRegisterMapOf(
David Srbecky052f8ca2018-04-26 15:42:54 +0100548 stack_map, entry.dex_register_entry.num_dex_registers),
Mathieu Chartier32289082017-02-09 15:57:37 -0800549 entry.dex_register_entry.num_dex_registers,
550 entry.dex_register_entry.live_dex_registers_mask,
551 entry.dex_register_entry.locations_start_index);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000552
553 // Check inline info.
David Srbecky052f8ca2018-04-26 15:42:54 +0100554 DCHECK_EQ(stack_map.HasInlineInfo(), (entry.inlining_depth != 0));
David Srbecky1bbdfd72016-02-24 16:39:26 +0000555 if (entry.inlining_depth != 0) {
David Srbecky052f8ca2018-04-26 15:42:54 +0100556 InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
557 DCHECK_EQ(inline_info.GetDepth(), entry.inlining_depth);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000558 for (size_t d = 0; d < entry.inlining_depth; ++d) {
559 size_t inline_info_index = entry.inline_infos_start_index + d;
560 DCHECK_LT(inline_info_index, inline_infos_.size());
561 InlineInfoEntry inline_entry = inline_infos_[inline_info_index];
David Srbecky052f8ca2018-04-26 15:42:54 +0100562 DCHECK_EQ(inline_info.GetDexPcAtDepth(d), inline_entry.dex_pc);
563 if (inline_info.EncodesArtMethodAtDepth(d)) {
564 DCHECK_EQ(inline_info.GetArtMethodAtDepth(d),
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000565 inline_entry.method);
566 } else {
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700567 const size_t method_index_idx =
David Srbecky052f8ca2018-04-26 15:42:54 +0100568 inline_info.GetMethodIndexIdxAtDepth(d);
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700569 DCHECK_EQ(method_index_idx, inline_entry.dex_method_index_idx);
570 DCHECK_EQ(method_indices_[method_index_idx], inline_entry.method_index);
Nicolas Geoffray5d37c152017-01-12 13:25:19 +0000571 }
David Srbecky1bbdfd72016-02-24 16:39:26 +0000572
573 CheckDexRegisterMap(code_info,
574 code_info.GetDexRegisterMapAtDepth(
Mathieu Chartier32289082017-02-09 15:57:37 -0800575 d,
576 inline_info,
Mathieu Chartier32289082017-02-09 15:57:37 -0800577 inline_entry.dex_register_entry.num_dex_registers),
578 inline_entry.dex_register_entry.num_dex_registers,
579 inline_entry.dex_register_entry.live_dex_registers_mask,
580 inline_entry.dex_register_entry.locations_start_index);
David Srbecky1bbdfd72016-02-24 16:39:26 +0000581 }
582 }
583 }
584}
585
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700586size_t StackMapStream::ComputeMethodInfoSize() const {
David Srbecky052f8ca2018-04-26 15:42:54 +0100587 DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before " << __FUNCTION__;
Mathieu Chartiercbcedbf2017-03-12 22:24:50 -0700588 return MethodInfo::ComputeSize(method_indices_.size());
589}
590
Calin Juravlec416d332015-04-23 16:01:43 +0100591} // namespace art