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 26 namespace art { 27 28 /** 29 * Collects and builds a CodeInfo for a method. 30 */ 31 template<typename T> 32 class 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