blob: 3c6ad8fd72088e6989068bf804c0830264d989b9 [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"
21#include "memory_region.h"
22#include "stack_map.h"
23#include "utils/allocation.h"
24#include "utils/growable_array.h"
25
26namespace art {
27
28/**
29 * Collects and builds a CodeInfo for a method.
30 */
31template<typename T>
32class 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),
38 stack_mask_max_(-1) {}
39
40 // Compute bytes needed to encode a mask with the given maximum element.
41 static uint32_t StackMaskEncodingSize(int max_element) {
42 int number_of_bits = max_element + 1; // Need room for max element too.
43 return RoundUp(number_of_bits, kBitsPerByte) / kBitsPerByte;
44 }
45
46 // See runtime/stack_map.h to know what these fields contain.
47 struct StackMapEntry {
48 uint32_t dex_pc;
49 T native_pc;
50 uint32_t register_mask;
51 BitVector* sp_mask;
52 uint32_t num_dex_registers;
53 uint8_t inlining_depth;
54 size_t dex_register_maps_start_index;
55 size_t inline_infos_start_index;
56 };
57
58 struct DexRegisterEntry {
59 DexRegisterMap::LocationKind kind;
60 int32_t value;
61 };
62
63 struct InlineInfoEntry {
64 uint32_t method_index;
65 };
66
67 void AddStackMapEntry(uint32_t dex_pc,
68 T native_pc,
69 uint32_t register_mask,
70 BitVector* sp_mask,
71 uint32_t num_dex_registers,
72 uint8_t inlining_depth) {
73 StackMapEntry entry;
74 entry.dex_pc = dex_pc;
75 entry.native_pc = native_pc;
76 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;
80 entry.dex_register_maps_start_index = dex_register_maps_.Size();
81 entry.inline_infos_start_index = inline_infos_.Size();
82 stack_maps_.Add(entry);
83
84 stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
85 if (inlining_depth > 0) {
86 number_of_stack_maps_with_inline_info_++;
87 }
88 }
89
90 void AddDexRegisterEntry(DexRegisterMap::LocationKind kind, int32_t value) {
91 DexRegisterEntry entry;
92 entry.kind = kind;
93 entry.value = value;
94 dex_register_maps_.Add(entry);
95 }
96
97 void AddInlineInfoEntry(uint32_t method_index) {
98 InlineInfoEntry entry;
99 entry.method_index = method_index;
100 inline_infos_.Add(entry);
101 }
102
103 size_t ComputeNeededSize() const {
104 return CodeInfo<T>::kFixedSize
105 + ComputeStackMapSize()
106 + ComputeDexRegisterMapSize()
107 + ComputeInlineInfoSize();
108 }
109
110 size_t ComputeStackMapSize() const {
111 return stack_maps_.Size() * (StackMap<T>::kFixedSize + StackMaskEncodingSize(stack_mask_max_));
112 }
113
114 size_t ComputeDexRegisterMapSize() const {
115 // We currently encode all dex register information per stack map.
116 return stack_maps_.Size() * DexRegisterMap::kFixedSize
117 // For each dex register entry.
118 + (dex_register_maps_.Size() * DexRegisterMap::SingleEntrySize());
119 }
120
121 size_t ComputeInlineInfoSize() const {
122 return inline_infos_.Size() * InlineInfo::SingleEntrySize()
123 // For encoding the depth.
124 + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
125 }
126
127 size_t ComputeInlineInfoStart() const {
128 return ComputeDexRegisterMapStart() + ComputeDexRegisterMapSize();
129 }
130
131 size_t ComputeDexRegisterMapStart() const {
132 return CodeInfo<T>::kFixedSize + ComputeStackMapSize();
133 }
134
135 void FillIn(MemoryRegion region) {
136 CodeInfo<T> code_info(region);
137
138 size_t stack_mask_size = StackMaskEncodingSize(stack_mask_max_);
139 uint8_t* memory_start = region.start();
140
141 MemoryRegion dex_register_maps_region = region.Subregion(
142 ComputeDexRegisterMapStart(),
143 ComputeDexRegisterMapSize());
144
145 MemoryRegion inline_infos_region = region.Subregion(
146 ComputeInlineInfoStart(),
147 ComputeInlineInfoSize());
148
149 code_info.SetNumberOfStackMaps(stack_maps_.Size());
150 code_info.SetStackMaskSize(stack_mask_size);
151
152 uintptr_t next_dex_register_map_offset = 0;
153 uintptr_t next_inline_info_offset = 0;
154 for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
155 StackMap<T> stack_map = code_info.GetStackMapAt(i);
156 StackMapEntry entry = stack_maps_.Get(i);
157
158 stack_map.SetDexPc(entry.dex_pc);
159 stack_map.SetNativePc(entry.native_pc);
160 stack_map.SetRegisterMask(entry.register_mask);
161 stack_map.SetStackMask(*entry.sp_mask);
162
163 // Set the register map.
164 MemoryRegion region = dex_register_maps_region.Subregion(
165 next_dex_register_map_offset,
166 DexRegisterMap::kFixedSize + entry.num_dex_registers * DexRegisterMap::SingleEntrySize());
167 next_dex_register_map_offset += region.size();
168 DexRegisterMap dex_register_map(region);
169 stack_map.SetDexRegisterMapOffset(region.start() - memory_start);
170
171 for (size_t i = 0; i < entry.num_dex_registers; ++i) {
172 DexRegisterEntry register_entry =
173 dex_register_maps_.Get(i + entry.dex_register_maps_start_index);
174 dex_register_map.SetRegisterInfo(i, register_entry.kind, register_entry.value);
175 }
176
177 // Set the inlining info.
178 if (entry.inlining_depth != 0) {
179 MemoryRegion region = inline_infos_region.Subregion(
180 next_inline_info_offset,
181 InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
182 next_inline_info_offset += region.size();
183 InlineInfo inline_info(region);
184
185 stack_map.SetInlineDescriptorOffset(region.start() - memory_start);
186
187 inline_info.SetDepth(entry.inlining_depth);
188 for (size_t i = 0; i < entry.inlining_depth; ++i) {
189 InlineInfoEntry inline_entry = inline_infos_.Get(i + entry.inline_infos_start_index);
190 inline_info.SetMethodReferenceIndexAtDepth(i, inline_entry.method_index);
191 }
192 } else {
193 stack_map.SetInlineDescriptorOffset(InlineInfo::kNoInlineInfo);
194 }
195 }
196 }
197
198 private:
199 GrowableArray<StackMapEntry> stack_maps_;
200 GrowableArray<DexRegisterEntry> dex_register_maps_;
201 GrowableArray<InlineInfoEntry> inline_infos_;
202 int stack_mask_max_;
203 size_t number_of_stack_maps_with_inline_info_;
204
205 DISALLOW_COPY_AND_ASSIGN(StackMapStream);
206};
207
208} // namespace art
209
210#endif // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_