blob: 8fb58d19a93a61505e6e9f7c35a4248be67bcb61 [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"
23#include "stack_map.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010024#include "utils/growable_array.h"
25
26namespace art {
27
28/**
Nicolas Geoffray39468442014-09-02 15:17:15 +010029 * Collects and builds stack maps for a method. All the stack maps
30 * for a method are placed in a CodeInfo object.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010031 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010032class StackMapStream : public ValueObject {
33 public:
34 explicit StackMapStream(ArenaAllocator* allocator)
35 : stack_maps_(allocator, 10),
36 dex_register_maps_(allocator, 10 * 4),
37 inline_infos_(allocator, 2),
Andreas Gampe8eddd2a2014-07-28 14:53:22 -070038 stack_mask_max_(-1),
39 number_of_stack_maps_with_inline_info_(0) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010040
41 // Compute bytes needed to encode a mask with the given maximum element.
42 static uint32_t StackMaskEncodingSize(int max_element) {
43 int number_of_bits = max_element + 1; // Need room for max element too.
44 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
45 }
46
47 // See runtime/stack_map.h to know what these fields contain.
48 struct StackMapEntry {
49 uint32_t dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010050 uint32_t native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010051 uint32_t register_mask;
52 BitVector* sp_mask;
53 uint32_t num_dex_registers;
54 uint8_t inlining_depth;
55 size_t dex_register_maps_start_index;
56 size_t inline_infos_start_index;
57 };
58
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010059 struct InlineInfoEntry {
60 uint32_t method_index;
61 };
62
63 void AddStackMapEntry(uint32_t dex_pc,
Nicolas Geoffray39468442014-09-02 15:17:15 +010064 uint32_t native_pc_offset,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010065 uint32_t register_mask,
66 BitVector* sp_mask,
67 uint32_t num_dex_registers,
68 uint8_t inlining_depth) {
69 StackMapEntry entry;
70 entry.dex_pc = dex_pc;
Nicolas Geoffray39468442014-09-02 15:17:15 +010071 entry.native_pc_offset = native_pc_offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010072 entry.register_mask = register_mask;
73 entry.sp_mask = sp_mask;
74 entry.num_dex_registers = num_dex_registers;
75 entry.inlining_depth = inlining_depth;
76 entry.dex_register_maps_start_index = dex_register_maps_.Size();
77 entry.inline_infos_start_index = inline_infos_.Size();
78 stack_maps_.Add(entry);
79
Nicolas Geoffray39468442014-09-02 15:17:15 +010080 if (sp_mask != nullptr) {
81 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
82 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010083 if (inlining_depth > 0) {
84 number_of_stack_maps_with_inline_info_++;
85 }
86 }
87
Roland Levillaina2d8ec62015-03-12 15:25:29 +000088 void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
89 // Ensure we only use non-compressed location kind at this stage.
90 DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
91 << DexRegisterLocation::PrettyDescriptor(kind);
92 dex_register_maps_.Add(DexRegisterLocation(kind, value));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010093 }
94
95 void AddInlineInfoEntry(uint32_t method_index) {
96 InlineInfoEntry entry;
97 entry.method_index = method_index;
98 inline_infos_.Add(entry);
99 }
100
101 size_t ComputeNeededSize() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100102 return CodeInfo::kFixedSize
Roland Levillain29ba1b02015-03-13 11:45:07 +0000103 + ComputeStackMapsSize()
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000104 + ComputeDexRegisterMapsSize()
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100105 + ComputeInlineInfoSize();
106 }
107
Roland Levillain29ba1b02015-03-13 11:45:07 +0000108 size_t ComputeStackMaskSize() const {
109 return StackMaskEncodingSize(stack_mask_max_);
110 }
111
112 size_t ComputeStackMapsSize() const {
113 return stack_maps_.Size() * StackMap::ComputeAlignedStackMapSize(ComputeStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100114 }
115
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000116 // Compute the size of the Dex register map of `entry`.
117 size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
118 size_t size = DexRegisterMap::kFixedSize;
119 for (size_t j = 0; j < entry.num_dex_registers; ++j) {
120 DexRegisterLocation dex_register_location =
121 dex_register_maps_.Get(entry.dex_register_maps_start_index + j);
122 size += DexRegisterMap::EntrySize(dex_register_location);
123 }
124 return size;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100125 }
126
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000127 // Compute the size of all the Dex register maps.
128 size_t ComputeDexRegisterMapsSize() const {
129 size_t size = stack_maps_.Size() * DexRegisterMap::kFixedSize;
130 // The size of each register location depends on the type of
131 // the entry.
132 for (size_t i = 0, e = dex_register_maps_.Size(); i < e; ++i) {
133 DexRegisterLocation entry = dex_register_maps_.Get(i);
134 size += DexRegisterMap::EntrySize(entry);
135 }
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000136 // On ARM, the Dex register maps must be 4-byte aligned.
137 return RoundUp(size, kWordAlignment);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000138 }
139
140 // Compute the size of all the inline information pieces.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100141 size_t ComputeInlineInfoSize() const {
142 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
143 // For encoding the depth.
144 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
145 }
146
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000147 size_t ComputeDexRegisterMapsStart() const {
Roland Levillain29ba1b02015-03-13 11:45:07 +0000148 return CodeInfo::kFixedSize + ComputeStackMapsSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100149 }
150
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000151 size_t ComputeInlineInfoStart() const {
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000152 return ComputeDexRegisterMapsStart() + ComputeDexRegisterMapsSize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000153 }
154
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100155 void FillIn(MemoryRegion region) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100156 CodeInfo code_info(region);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000157 DCHECK_EQ(region.size(), ComputeNeededSize());
Nicolas Geoffray39468442014-09-02 15:17:15 +0100158 code_info.SetOverallSize(region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100159
Roland Levillain29ba1b02015-03-13 11:45:07 +0000160 size_t stack_mask_size = ComputeStackMaskSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100161 uint8_t* memory_start = region.start();
162
163 MemoryRegion dex_register_maps_region = region.Subregion(
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000164 ComputeDexRegisterMapsStart(),
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000165 ComputeDexRegisterMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100166
167 MemoryRegion inline_infos_region = region.Subregion(
168 ComputeInlineInfoStart(),
169 ComputeInlineInfoSize());
170
171 code_info.SetNumberOfStackMaps(stack_maps_.Size());
172 code_info.SetStackMaskSize(stack_mask_size);
Roland Levillain29ba1b02015-03-13 11:45:07 +0000173 DCHECK_EQ(code_info.StackMapsSize(), ComputeStackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100174
175 uintptr_t next_dex_register_map_offset = 0;
176 uintptr_t next_inline_info_offset = 0;
177 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100178 StackMap stack_map = code_info.GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100179 StackMapEntry entry = stack_maps_.Get(i);
180
181 stack_map.SetDexPc(entry.dex_pc);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100182 stack_map.SetNativePcOffset(entry.native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100183 stack_map.SetRegisterMask(entry.register_mask);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100184 if (entry.sp_mask != nullptr) {
185 stack_map.SetStackMask(*entry.sp_mask);
186 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100187
Roland Levillain442b46a2015-02-18 16:54:21 +0000188 if (entry.num_dex_registers != 0) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000189 // Set the Dex register map.
190 MemoryRegion register_region =
191 dex_register_maps_region.Subregion(
192 next_dex_register_map_offset,
193 ComputeDexRegisterMapSize(entry));
Roland Levillain442b46a2015-02-18 16:54:21 +0000194 next_dex_register_map_offset += register_region.size();
195 DexRegisterMap dex_register_map(register_region);
196 stack_map.SetDexRegisterMapOffset(register_region.start() - memory_start);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100197
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000198 // Offset in `dex_register_map` where to store the next register entry.
199 size_t offset = DexRegisterMap::kFixedSize;
Roland Levillain442b46a2015-02-18 16:54:21 +0000200 for (size_t j = 0; j < entry.num_dex_registers; ++j) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000201 DexRegisterLocation dex_register_location =
202 dex_register_maps_.Get(entry.dex_register_maps_start_index + j);
203 dex_register_map.SetRegisterInfo(offset, dex_register_location);
204 offset += DexRegisterMap::EntrySize(dex_register_location);
Roland Levillain442b46a2015-02-18 16:54:21 +0000205 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000206 // Ensure we reached the end of the Dex registers region.
207 DCHECK_EQ(offset, register_region.size());
Roland Levillain442b46a2015-02-18 16:54:21 +0000208 } else {
209 stack_map.SetDexRegisterMapOffset(StackMap::kNoDexRegisterMap);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100210 }
211
212 // Set the inlining info.
213 if (entry.inlining_depth != 0) {
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800214 MemoryRegion inline_region = inline_infos_region.Subregion(
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100215 next_inline_info_offset,
216 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800217 next_inline_info_offset += inline_region.size();
218 InlineInfo inline_info(inline_region);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100219
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800220 stack_map.SetInlineDescriptorOffset(inline_region.start() - memory_start);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100221
222 inline_info.SetDepth(entry.inlining_depth);
Andreas Gampe277ccbd2014-11-03 21:36:10 -0800223 for (size_t j = 0; j < entry.inlining_depth; ++j) {
224 InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
225 inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100226 }
227 } else {
Roland Levillain442b46a2015-02-18 16:54:21 +0000228 stack_map.SetInlineDescriptorOffset(StackMap::kNoInlineInfo);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100229 }
230 }
231 }
232
233 private:
234 GrowableArray<StackMapEntry> stack_maps_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000235 GrowableArray<DexRegisterLocation> dex_register_maps_;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100236 GrowableArray<InlineInfoEntry> inline_infos_;
237 int stack_mask_max_;
238 size_t number_of_stack_maps_with_inline_info_;
239
240 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
241};
242
243} // namespace art
244
245#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_