blob: 3168801e1286bb6f4a8e323ef639acae6267a696 [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
20#include "base/bit_vector.h"
Ian Rogers0279ebb2014-10-08 17:27:48 -070021#include "base/value_object.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010022#include "memory_region.h"
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000023#include "nodes.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010024#include "stack_map.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010025#include "utils/growable_array.h"
26
27namespace art {
28
29/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010030 * Collects and builds stack maps for a method. All the stack maps
31 * for a method are placed in a CodeInfo object.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010032 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010033class StackMapStream : public ValueObject {
34 public:
35 explicit StackMapStream(ArenaAllocator* allocator)
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000036 : allocator_(allocator),
37 stack_maps_(allocator, 10),
38 dex_register_locations_(allocator, 10 * 4),
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010039 inline_infos_(allocator, 2),
Andreas Gampe8eddd2a2014-07-28 14:53:22 -070040 stack_mask_max_(-1),
41 number_of_stack_maps_with_inline_info_(0) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010042
43 // Compute bytes needed to encode a mask with the given maximum element.
44 static uint32_t StackMaskEncodingSize(int max_element) {
45 int number_of_bits = max_element + 1; // Need room for max element too.
46 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
47 }
48
49 // See runtime/stack_map.h to know what these fields contain.
50 struct StackMapEntry {
51 uint32_t dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010052 uint32_t native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010053 uint32_t register_mask;
54 BitVector* sp_mask;
55 uint32_t num_dex_registers;
56 uint8_t inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000057 size_t dex_register_locations_start_index;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010058 size_t inline_infos_start_index;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000059 BitVector* live_dex_registers_mask;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010060 };
61
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010062 struct InlineInfoEntry {
63 uint32_t method_index;
64 };
65
66 void AddStackMapEntry(uint32_t dex_pc,
Nicolas Geoffray39468442014-09-02 15:17:15 +010067 uint32_t native_pc_offset,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010068 uint32_t register_mask,
69 BitVector* sp_mask,
70 uint32_t num_dex_registers,
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000071 uint8_t inlining_depth,
72 BitVector* live_dex_registers_mask) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010073 StackMapEntry entry;
74 entry.dex_pc = dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 entry.native_pc_offset = native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010076 entry.register_mask = register_mask;
77 entry.sp_mask = sp_mask;
78 entry.num_dex_registers = num_dex_registers;
79 entry.inlining_depth = inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000080 entry.dex_register_locations_start_index = dex_register_locations_.Size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010081 entry.inline_infos_start_index = inline_infos_.Size();
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000082 entry.live_dex_registers_mask = live_dex_registers_mask;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010083 stack_maps_.Add(entry);
84
Nicolas Geoffray39468442014-09-02 15:17:15 +010085 if (sp_mask != nullptr) {
86 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
87 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010088 if (inlining_depth > 0) {
89 number_of_stack_maps_with_inline_info_++;
90 }
91 }
92
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000093 void RecordEnvironment(HEnvironment* environment,
94 size_t environment_size,
95 LocationSummary* locations,
96 uint32_t dex_pc,
97 uint32_t native_pc,
98 uint32_t register_mask,
99 uint32_t inlining_depth) {
100 if (environment == nullptr) {
101 // For stack overflow checks.
102 AddStackMapEntry(dex_pc, native_pc, 0, 0, 0, inlining_depth, nullptr);
103 return;
104 }
105
106 BitVector* live_dex_registers_mask = new (allocator_) ArenaBitVector(allocator_, 0, true);
107
108 AddStackMapEntry(
109 dex_pc, native_pc, register_mask,
110 locations->GetStackMask(), environment_size, inlining_depth, live_dex_registers_mask);
111
112 // Walk over the environment, and record the location of dex registers.
113 for (size_t i = 0; i < environment_size; ++i) {
114 HInstruction* current = environment->GetInstructionAt(i);
115 if (current == nullptr) {
116 // No need to store anything, the `live_dex_registers_mask` will hold the
117 // information that this register is not live.
118 continue;
119 }
120
121 Location location = locations->GetEnvironmentAt(i);
122 switch (location.GetKind()) {
123 case Location::kConstant: {
124 DCHECK_EQ(current, location.GetConstant());
125 if (current->IsLongConstant()) {
126 // TODO: Consider moving setting the bit in AddDexRegisterEntry to avoid
127 // doing it manually here.
128 live_dex_registers_mask->SetBit(i);
129 live_dex_registers_mask->SetBit(i + 1);
130 int64_t value = current->AsLongConstant()->GetValue();
131 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value));
132 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value));
133 ++i;
134 DCHECK_LT(i, environment_size);
135 } else if (current->IsDoubleConstant()) {
136 live_dex_registers_mask->SetBit(i);
137 live_dex_registers_mask->SetBit(i + 1);
138 int64_t value = bit_cast<double, int64_t>(current->AsDoubleConstant()->GetValue());
139 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, Low32Bits(value));
140 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, High32Bits(value));
141 ++i;
142 DCHECK_LT(i, environment_size);
143 } else if (current->IsIntConstant()) {
144 live_dex_registers_mask->SetBit(i);
145 int32_t value = current->AsIntConstant()->GetValue();
146 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
147 } else if (current->IsNullConstant()) {
148 live_dex_registers_mask->SetBit(i);
149 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
150 } else {
151 DCHECK(current->IsFloatConstant()) << current->DebugName();
152 live_dex_registers_mask->SetBit(i);
153 int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
154 AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
155 }
156 break;
157 }
158
159 case Location::kStackSlot: {
160 live_dex_registers_mask->SetBit(i);
161 AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
162 location.GetStackIndex());
163 break;
164 }
165
166 case Location::kDoubleStackSlot: {
167 live_dex_registers_mask->SetBit(i);
168 live_dex_registers_mask->SetBit(i + 1);
169 AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
170 AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack,
171 location.GetHighStackIndex(kVRegSize));
172 ++i;
173 DCHECK_LT(i, environment_size);
174 break;
175 }
176
177 case Location::kRegister : {
178 live_dex_registers_mask->SetBit(i);
179 int id = location.reg();
180 AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
181 if (current->GetType() == Primitive::kPrimLong) {
182 live_dex_registers_mask->SetBit(i + 1);
183 AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
184 ++i;
185 DCHECK_LT(i, environment_size);
186 }
187 break;
188 }
189
190 case Location::kFpuRegister : {
191 live_dex_registers_mask->SetBit(i);
192 int id = location.reg();
193 AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
194 if (current->GetType() == Primitive::kPrimDouble) {
195 live_dex_registers_mask->SetBit(i + 1);
196 AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
197 ++i;
198 DCHECK_LT(i, environment_size);
199 }
200 break;
201 }
202
203 case Location::kFpuRegisterPair : {
204 live_dex_registers_mask->SetBit(i);
205 live_dex_registers_mask->SetBit(i + 1);
206 AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.low());
207 AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, location.high());
208 ++i;
209 DCHECK_LT(i, environment_size);
210 break;
211 }
212
213 case Location::kRegisterPair : {
214 live_dex_registers_mask->SetBit(i);
215 live_dex_registers_mask->SetBit(i + 1);
216 AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.low());
217 AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, location.high());
218 ++i;
219 DCHECK_LT(i, environment_size);
220 break;
221 }
222
223 case Location::kInvalid: {
224 // No need to store anything, the `live_dex_registers_mask` will hold the
225 // information that this register is not live.
226 break;
227 }
228
229 default:
230 LOG(FATAL) << "Unexpected kind " << location.GetKind();
231 }
232 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100233 }
234
235 void AddInlineInfoEntry(uint32_t method_index) {
236 InlineInfoEntry entry;
237 entry.method_index = method_index;
238 inline_infos_.Add(entry);
239 }
240
241 size_t ComputeNeededSize() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000242 size_t size = CodeInfo::kFixedSize
Roland Levillain29ba1b02015-03-13 11:45:07 +0000243 + ComputeStackMapsSize()
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000244 + ComputeDexRegisterMapsSize()
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100245 + ComputeInlineInfoSize();
Roland Levillainede7bf82015-03-13 12:23:04 +0000246 // On ARM, CodeInfo data must be 4-byte aligned.
247 return RoundUp(size, kWordAlignment);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100248 }
249
Roland Levillain29ba1b02015-03-13 11:45:07 +0000250 size_t ComputeStackMaskSize() const {
251 return StackMaskEncodingSize(stack_mask_max_);
252 }
253
254 size_t ComputeStackMapsSize() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000255 return stack_maps_.Size() * StackMap::ComputeStackMapSize(ComputeStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100256 }
257
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000258 // Compute the size of the Dex register map of `entry`.
259 size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
260 size_t size = DexRegisterMap::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000261 // Add the bit mask for the dex register liveness.
262 size += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
263 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
264 dex_register_number < entry.num_dex_registers;
265 ++dex_register_number) {
266 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
267 DexRegisterLocation dex_register_location = dex_register_locations_.Get(
268 entry.dex_register_locations_start_index + index_in_dex_register_locations);
269 size += DexRegisterMap::EntrySize(dex_register_location);
270 index_in_dex_register_locations++;
271 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000272 }
273 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100274 }
275
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000276 // Compute the size of all the Dex register maps.
277 size_t ComputeDexRegisterMapsSize() const {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000278 size_t size = 0;
279 for (size_t i = 0; i < stack_maps_.Size(); ++i) {
280 size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000281 }
Roland Levillainede7bf82015-03-13 12:23:04 +0000282 return size;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000283 }
284
285 // Compute the size of all the inline information pieces.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100286 size_t ComputeInlineInfoSize() const {
287 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
288 // For encoding the depth.
289 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
290 }
291
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000292 size_t ComputeDexRegisterMapsStart() const {
Roland Levillain29ba1b02015-03-13 11:45:07 +0000293 return CodeInfo::kFixedSize + ComputeStackMapsSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100294 }
295
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000296 size_t ComputeInlineInfoStart() const {
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000297 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000298 }
299
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100300 void FillIn(MemoryRegion region) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100301 CodeInfo code_info(region);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000302 DCHECK_EQ(region.size(), ComputeNeededSize());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100303 code_info.SetOverallSize(region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100304
Roland Levillain29ba1b02015-03-13 11:45:07 +0000305 size_t stack_mask_size = ComputeStackMaskSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100306 uint8_t* memory_start = region.start();
307
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000308 MemoryRegion dex_register_locations_region = region.Subregion(
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000309 ComputeDexRegisterMapsStart(),
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000310 ComputeDexRegisterMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100311
312 MemoryRegion inline_infos_region = region.Subregion(
313 ComputeInlineInfoStart(),
314 ComputeInlineInfoSize());
315
316 code_info.SetNumberOfStackMaps(stack_maps_.Size());
317 code_info.SetStackMaskSize(stack_mask_size);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000318 DCHECK_EQ(code_info.StackMapsSize(), ComputeStackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100319
320 uintptr_t next_dex_register_map_offset = 0;
321 uintptr_t next_inline_info_offset = 0;
322 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100323 StackMap stack_map = code_info.GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100324 StackMapEntry entry = stack_maps_.Get(i);
325
326 stack_map.SetDexPc(entry.dex_pc);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100327 stack_map.SetNativePcOffset(entry.native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100328 stack_map.SetRegisterMask(entry.register_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100329 if (entry.sp_mask != nullptr) {
330 stack_map.SetStackMask(*entry.sp_mask);
331 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100332
Roland Levillain442b46a2015-02-18 16:54:21 +0000333 if (entry.num_dex_registers != 0) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000334 // Set the Dex register map.
335 MemoryRegion register_region =
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000336 dex_register_locations_region.Subregion(
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000337 next_dex_register_map_offset,
338 ComputeDexRegisterMapSize(entry));
Roland Levillain442b46a2015-02-18 16:54:21 +0000339 next_dex_register_map_offset += register_region.size();
340 DexRegisterMap dex_register_map(register_region);
341 stack_map.SetDexRegisterMapOffset(register_region.start() - memory_start);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100342
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000343 // Offset in `dex_register_map` where to store the next register entry.
344 size_t offset = DexRegisterMap::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000345 dex_register_map.SetLiveBitMask(offset,
346 entry.num_dex_registers,
347 *entry.live_dex_registers_mask);
348 offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
349 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
350 dex_register_number < entry.num_dex_registers;
351 ++dex_register_number) {
352 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
353 DexRegisterLocation dex_register_location = dex_register_locations_.Get(
354 entry.dex_register_locations_start_index + index_in_dex_register_locations);
355 dex_register_map.SetRegisterInfo(offset, dex_register_location);
356 offset += DexRegisterMap::EntrySize(dex_register_location);
357 ++index_in_dex_register_locations;
358 }
Roland Levillain442b46a2015-02-18 16:54:21 +0000359 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000360 // Ensure we reached the end of the Dex registers region.
361 DCHECK_EQ(offset, register_region.size());
Roland Levillain442b46a2015-02-18 16:54:21 +0000362 } else {
363 stack_map.SetDexRegisterMapOffset(StackMap::kNoDexRegisterMap);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100364 }
365
366 // Set the inlining info.
367 if (entry.inlining_depth != 0) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800368 MemoryRegion inline_region = inline_infos_region.Subregion(
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100369 next_inline_info_offset,
370 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800371 next_inline_info_offset += inline_region.size();
372 InlineInfo inline_info(inline_region);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100373
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800374 stack_map.SetInlineDescriptorOffset(inline_region.start() - memory_start);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100375
376 inline_info.SetDepth(entry.inlining_depth);
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800377 for (size_t j = 0; j < entry.inlining_depth; ++j) {
378 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
379 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100380 }
381 } else {
Roland Levillain442b46a2015-02-18 16:54:21 +0000382 stack_map.SetInlineDescriptorOffset(StackMap::kNoInlineInfo);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100383 }
384 }
385 }
386
387 private:
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000388 void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
389 // Ensure we only use non-compressed location kind at this stage.
390 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
391 << DexRegisterLocation::PrettyDescriptor(kind);
392 dex_register_locations_.Add(DexRegisterLocation(kind, value));
393 }
394
395 ArenaAllocator* allocator_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100396 GrowableArray<StackMapEntry> stack_maps_;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000397 GrowableArray<DexRegisterLocation> dex_register_locations_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100398 GrowableArray<InlineInfoEntry> inline_infos_;
399 int stack_mask_max_;
400 size_t number_of_stack_maps_with_inline_info_;
401
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000402 ART_FRIEND_TEST(StackMapTest, Test1);
403 ART_FRIEND_TEST(StackMapTest, Test2);
404 ART_FRIEND_TEST(StackMapTest, TestNonLiveDexRegisters);
405
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100406 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
407};
408
409} // namespace art
410
411#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_