stack_map_stream.h revision 8eddd2a379e1d3c76b22f40d3d4387d12ed1a8d1
1/*
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        number_of_stack_maps_with_inline_info_(0) {}
40
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;
50    T native_pc;
51    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
59  struct DexRegisterEntry {
60    DexRegisterMap::LocationKind kind;
61    int32_t value;
62  };
63
64  struct InlineInfoEntry {
65    uint32_t method_index;
66  };
67
68  void AddStackMapEntry(uint32_t dex_pc,
69                        T native_pc,
70                        uint32_t register_mask,
71                        BitVector* sp_mask,
72                        uint32_t num_dex_registers,
73                        uint8_t inlining_depth) {
74    StackMapEntry entry;
75    entry.dex_pc = dex_pc;
76    entry.native_pc = native_pc;
77    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;
81    entry.dex_register_maps_start_index = dex_register_maps_.Size();
82    entry.inline_infos_start_index = inline_infos_.Size();
83    stack_maps_.Add(entry);
84
85    stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet());
86    if (inlining_depth > 0) {
87      number_of_stack_maps_with_inline_info_++;
88    }
89  }
90
91  void AddDexRegisterEntry(DexRegisterMap::LocationKind kind, int32_t value) {
92    DexRegisterEntry entry;
93    entry.kind = kind;
94    entry.value = value;
95    dex_register_maps_.Add(entry);
96  }
97
98  void AddInlineInfoEntry(uint32_t method_index) {
99    InlineInfoEntry entry;
100    entry.method_index = method_index;
101    inline_infos_.Add(entry);
102  }
103
104  size_t ComputeNeededSize() const {
105    return CodeInfo<T>::kFixedSize
106        + ComputeStackMapSize()
107        + ComputeDexRegisterMapSize()
108        + ComputeInlineInfoSize();
109  }
110
111  size_t ComputeStackMapSize() const {
112    return stack_maps_.Size() * (StackMap<T>::kFixedSize + StackMaskEncodingSize(stack_mask_max_));
113  }
114
115  size_t ComputeDexRegisterMapSize() const {
116    // We currently encode all dex register information per stack map.
117    return stack_maps_.Size() * DexRegisterMap::kFixedSize
118      // For each dex register entry.
119      + (dex_register_maps_.Size() * DexRegisterMap::SingleEntrySize());
120  }
121
122  size_t ComputeInlineInfoSize() const {
123    return inline_infos_.Size() * InlineInfo::SingleEntrySize()
124      // For encoding the depth.
125      + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
126  }
127
128  size_t ComputeInlineInfoStart() const {
129    return ComputeDexRegisterMapStart() + ComputeDexRegisterMapSize();
130  }
131
132  size_t ComputeDexRegisterMapStart() const {
133    return CodeInfo<T>::kFixedSize + ComputeStackMapSize();
134  }
135
136  void FillIn(MemoryRegion region) {
137    CodeInfo<T> code_info(region);
138
139    size_t stack_mask_size = StackMaskEncodingSize(stack_mask_max_);
140    uint8_t* memory_start = region.start();
141
142    MemoryRegion dex_register_maps_region = region.Subregion(
143      ComputeDexRegisterMapStart(),
144      ComputeDexRegisterMapSize());
145
146    MemoryRegion inline_infos_region = region.Subregion(
147      ComputeInlineInfoStart(),
148      ComputeInlineInfoSize());
149
150    code_info.SetNumberOfStackMaps(stack_maps_.Size());
151    code_info.SetStackMaskSize(stack_mask_size);
152
153    uintptr_t next_dex_register_map_offset = 0;
154    uintptr_t next_inline_info_offset = 0;
155    for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
156      StackMap<T> stack_map = code_info.GetStackMapAt(i);
157      StackMapEntry entry = stack_maps_.Get(i);
158
159      stack_map.SetDexPc(entry.dex_pc);
160      stack_map.SetNativePc(entry.native_pc);
161      stack_map.SetRegisterMask(entry.register_mask);
162      stack_map.SetStackMask(*entry.sp_mask);
163
164      // Set the register map.
165      MemoryRegion region = dex_register_maps_region.Subregion(
166          next_dex_register_map_offset,
167          DexRegisterMap::kFixedSize + entry.num_dex_registers * DexRegisterMap::SingleEntrySize());
168      next_dex_register_map_offset += region.size();
169      DexRegisterMap dex_register_map(region);
170      stack_map.SetDexRegisterMapOffset(region.start() - memory_start);
171
172      for (size_t i = 0; i < entry.num_dex_registers; ++i) {
173        DexRegisterEntry register_entry =
174            dex_register_maps_.Get(i + entry.dex_register_maps_start_index);
175        dex_register_map.SetRegisterInfo(i, register_entry.kind, register_entry.value);
176      }
177
178      // Set the inlining info.
179      if (entry.inlining_depth != 0) {
180        MemoryRegion region = inline_infos_region.Subregion(
181            next_inline_info_offset,
182            InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
183        next_inline_info_offset += region.size();
184        InlineInfo inline_info(region);
185
186        stack_map.SetInlineDescriptorOffset(region.start() - memory_start);
187
188        inline_info.SetDepth(entry.inlining_depth);
189        for (size_t i = 0; i < entry.inlining_depth; ++i) {
190          InlineInfoEntry inline_entry = inline_infos_.Get(i + entry.inline_infos_start_index);
191          inline_info.SetMethodReferenceIndexAtDepth(i, inline_entry.method_index);
192        }
193      } else {
194        stack_map.SetInlineDescriptorOffset(InlineInfo::kNoInlineInfo);
195      }
196    }
197  }
198
199 private:
200  GrowableArray<StackMapEntry> stack_maps_;
201  GrowableArray<DexRegisterEntry> dex_register_maps_;
202  GrowableArray<InlineInfoEntry> inline_infos_;
203  int stack_mask_max_;
204  size_t number_of_stack_maps_with_inline_info_;
205
206  DISALLOW_COPY_AND_ASSIGN(StackMapStream);
207};
208
209}  // namespace art
210
211#endif  // ART_COMPILER_OPTIMIZING_STACK_MAP_STREAM_H_
212