blob: 9914ef49c3ea51638f96e68ee74a33c4bc2d7e0e [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),
Nicolas Geoffray004c2302015-03-20 10:06:38 +000041 dex_pc_max_(0),
42 native_pc_offset_max_(0),
Andreas Gampe8eddd2a2014-07-28 14:53:22 -070043 number_of_stack_maps_with_inline_info_(0) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010044
45 // Compute bytes needed to encode a mask with the given maximum element.
46 static uint32_t StackMaskEncodingSize(int max_element) {
47 int number_of_bits = max_element + 1; // Need room for max element too.
48 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
49 }
50
51 // See runtime/stack_map.h to know what these fields contain.
52 struct StackMapEntry {
53 uint32_t dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010054 uint32_t native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010055 uint32_t register_mask;
56 BitVector* sp_mask;
57 uint32_t num_dex_registers;
58 uint8_t inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000059 size_t dex_register_locations_start_index;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010060 size_t inline_infos_start_index;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000061 BitVector* live_dex_registers_mask;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010062 };
63
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010064 struct InlineInfoEntry {
65 uint32_t method_index;
66 };
67
68 void AddStackMapEntry(uint32_t dex_pc,
Nicolas Geoffray39468442014-09-02 15:17:15 +010069 uint32_t native_pc_offset,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010070 uint32_t register_mask,
71 BitVector* sp_mask,
72 uint32_t num_dex_registers,
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000073 uint8_t inlining_depth) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010074 StackMapEntry entry;
75 entry.dex_pc = dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 entry.native_pc_offset = native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010077 entry.register_mask = register_mask;
78 entry.sp_mask = sp_mask;
79 entry.num_dex_registers = num_dex_registers;
80 entry.inlining_depth = inlining_depth;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000081 entry.dex_register_locations_start_index = dex_register_locations_.Size();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010082 entry.inline_infos_start_index = inline_infos_.Size();
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +000083 if (num_dex_registers != 0) {
84 entry.live_dex_registers_mask =
85 new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
86 } else {
87 entry.live_dex_registers_mask = nullptr;
88 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010089 stack_maps_.Add(entry);
90
Nicolas Geoffray39468442014-09-02 15:17:15 +010091 if (sp_mask != nullptr) {
92 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
93 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010094 if (inlining_depth > 0) {
95 number_of_stack_maps_with_inline_info_++;
96 }
Nicolas Geoffray004c2302015-03-20 10:06:38 +000097
98 dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
99 native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100100 }
101
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100102 void AddInlineInfoEntry(uint32_t method_index) {
103 InlineInfoEntry entry;
104 entry.method_index = method_index;
105 inline_infos_.Add(entry);
106 }
107
108 size_t ComputeNeededSize() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000109 size_t size = CodeInfo::kFixedSize
Roland Levillain29ba1b02015-03-13 11:45:07 +0000110 + ComputeStackMapsSize()
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000111 + ComputeDexRegisterMapsSize()
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100112 + ComputeInlineInfoSize();
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000113 // Note: use RoundUp to word-size here if you want CodeInfo objects to be word aligned.
114 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100115 }
116
Roland Levillain29ba1b02015-03-13 11:45:07 +0000117 size_t ComputeStackMaskSize() const {
118 return StackMaskEncodingSize(stack_mask_max_);
119 }
120
121 size_t ComputeStackMapsSize() const {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000122 return stack_maps_.Size() * StackMap::ComputeStackMapSize(
123 ComputeStackMaskSize(),
124 ComputeInlineInfoSize(),
125 ComputeDexRegisterMapsSize(),
126 dex_pc_max_,
127 native_pc_offset_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100128 }
129
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000130 // Compute the size of the Dex register map of `entry`.
131 size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
132 size_t size = DexRegisterMap::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000133 // Add the bit mask for the dex register liveness.
134 size += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
135 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
136 dex_register_number < entry.num_dex_registers;
137 ++dex_register_number) {
138 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
139 DexRegisterLocation dex_register_location = dex_register_locations_.Get(
140 entry.dex_register_locations_start_index + index_in_dex_register_locations);
141 size += DexRegisterMap::EntrySize(dex_register_location);
142 index_in_dex_register_locations++;
143 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000144 }
145 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100146 }
147
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000148 // Compute the size of all the Dex register maps.
149 size_t ComputeDexRegisterMapsSize() const {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000150 size_t size = 0;
151 for (size_t i = 0; i < stack_maps_.Size(); ++i) {
152 size += ComputeDexRegisterMapSize(stack_maps_.Get(i));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000153 }
Roland Levillainede7bf82015-03-13 12:23:04 +0000154 return size;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000155 }
156
157 // Compute the size of all the inline information pieces.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100158 size_t ComputeInlineInfoSize() const {
159 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
160 // For encoding the depth.
161 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
162 }
163
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000164 size_t ComputeDexRegisterMapsStart() const {
Roland Levillain29ba1b02015-03-13 11:45:07 +0000165 return CodeInfo::kFixedSize + ComputeStackMapsSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100166 }
167
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000168 size_t ComputeInlineInfoStart() const {
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000169 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000170 }
171
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100172 void FillIn(MemoryRegion region) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100173 CodeInfo code_info(region);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000174 DCHECK_EQ(region.size(), ComputeNeededSize());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100175 code_info.SetOverallSize(region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100176
Roland Levillain29ba1b02015-03-13 11:45:07 +0000177 size_t stack_mask_size = ComputeStackMaskSize();
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000178
179 size_t dex_register_map_size = ComputeDexRegisterMapsSize();
180 size_t inline_info_size = ComputeInlineInfoSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100181
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000182 MemoryRegion dex_register_locations_region = region.Subregion(
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000183 ComputeDexRegisterMapsStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000184 dex_register_map_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100185
186 MemoryRegion inline_infos_region = region.Subregion(
187 ComputeInlineInfoStart(),
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000188 inline_info_size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100189
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000190 code_info.SetEncoding(
191 inline_info_size, dex_register_map_size, dex_pc_max_, native_pc_offset_max_);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100192 code_info.SetNumberOfStackMaps(stack_maps_.Size());
193 code_info.SetStackMaskSize(stack_mask_size);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000194 DCHECK_EQ(code_info.StackMapsSize(), ComputeStackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100195
196 uintptr_t next_dex_register_map_offset = 0;
197 uintptr_t next_inline_info_offset = 0;
198 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100199 StackMap stack_map = code_info.GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100200 StackMapEntry entry = stack_maps_.Get(i);
201
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000202 stack_map.SetDexPc(code_info, entry.dex_pc);
203 stack_map.SetNativePcOffset(code_info, entry.native_pc_offset);
204 stack_map.SetRegisterMask(code_info, entry.register_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100205 if (entry.sp_mask != nullptr) {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000206 stack_map.SetStackMask(code_info, *entry.sp_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100207 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100208
Roland Levillain442b46a2015-02-18 16:54:21 +0000209 if (entry.num_dex_registers != 0) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000210 // Set the Dex register map.
211 MemoryRegion register_region =
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000212 dex_register_locations_region.Subregion(
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000213 next_dex_register_map_offset,
214 ComputeDexRegisterMapSize(entry));
Roland Levillain442b46a2015-02-18 16:54:21 +0000215 next_dex_register_map_offset += register_region.size();
216 DexRegisterMap dex_register_map(register_region);
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000217 stack_map.SetDexRegisterMapOffset(
218 code_info, register_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100219
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000220 // Offset in `dex_register_map` where to store the next register entry.
221 size_t offset = DexRegisterMap::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000222 dex_register_map.SetLiveBitMask(offset,
223 entry.num_dex_registers,
224 *entry.live_dex_registers_mask);
225 offset += DexRegisterMap::LiveBitMaskSize(entry.num_dex_registers);
226 for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
227 dex_register_number < entry.num_dex_registers;
228 ++dex_register_number) {
229 if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
230 DexRegisterLocation dex_register_location = dex_register_locations_.Get(
231 entry.dex_register_locations_start_index + index_in_dex_register_locations);
232 dex_register_map.SetRegisterInfo(offset, dex_register_location);
233 offset += DexRegisterMap::EntrySize(dex_register_location);
234 ++index_in_dex_register_locations;
235 }
Roland Levillain442b46a2015-02-18 16:54:21 +0000236 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000237 // Ensure we reached the end of the Dex registers region.
238 DCHECK_EQ(offset, register_region.size());
Roland Levillain442b46a2015-02-18 16:54:21 +0000239 } else {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000240 stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100241 }
242
243 // Set the inlining info.
244 if (entry.inlining_depth != 0) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800245 MemoryRegion inline_region = inline_infos_region.Subregion(
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100246 next_inline_info_offset,
247 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800248 next_inline_info_offset += inline_region.size();
249 InlineInfo inline_info(inline_region);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100250
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000251 // Currently relative to the dex register map.
252 stack_map.SetInlineDescriptorOffset(
253 code_info, inline_region.start() - dex_register_locations_region.start());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100254
255 inline_info.SetDepth(entry.inlining_depth);
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800256 for (size_t j = 0; j < entry.inlining_depth; ++j) {
257 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
258 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100259 }
260 } else {
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000261 if (inline_info_size != 0) {
262 stack_map.SetInlineDescriptorOffset(code_info, StackMap::kNoInlineInfo);
263 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100264 }
265 }
266 }
267
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000268 void AddDexRegisterEntry(uint16_t dex_register, DexRegisterLocation::Kind kind, int32_t value) {
269 if (kind != DexRegisterLocation::Kind::kNone) {
270 // Ensure we only use non-compressed location kind at this stage.
271 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
272 << DexRegisterLocation::PrettyDescriptor(kind);
273 dex_register_locations_.Add(DexRegisterLocation(kind, value));
274 stack_maps_.Get(stack_maps_.Size() - 1).live_dex_registers_mask->SetBit(dex_register);
275 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000276 }
277
Nicolas Geoffrayeeefa122015-03-13 18:52:59 +0000278 private:
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000279 ArenaAllocator* allocator_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100280 GrowableArray<StackMapEntry> stack_maps_;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000281 GrowableArray<DexRegisterLocation> dex_register_locations_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100282 GrowableArray<InlineInfoEntry> inline_infos_;
283 int stack_mask_max_;
Nicolas Geoffray004c2302015-03-20 10:06:38 +0000284 uint32_t dex_pc_max_;
285 uint32_t native_pc_offset_max_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100286 size_t number_of_stack_maps_with_inline_info_;
287
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000288 ART_FRIEND_TEST(StackMapTest, Test1);
289 ART_FRIEND_TEST(StackMapTest, Test2);
290 ART_FRIEND_TEST(StackMapTest, TestNonLiveDexRegisters);
291
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100292 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
293};
294
295} // namespace art
296
297#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_