code_generator.cc revision e3ea83811d47152c00abea24a9b420651a33b496
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#include "code_generator.h" 18 19#include "code_generator_arm.h" 20#include "code_generator_x86.h" 21#include "code_generator_x86_64.h" 22#include "compiled_method.h" 23#include "dex/verified_method.h" 24#include "driver/dex_compilation_unit.h" 25#include "gc_map_builder.h" 26#include "leb128.h" 27#include "mapping_table.h" 28#include "utils/assembler.h" 29#include "verifier/dex_gc_map.h" 30#include "vmap_table.h" 31 32namespace art { 33 34void CodeGenerator::CompileBaseline(CodeAllocator* allocator, bool is_leaf) { 35 const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks(); 36 DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock()); 37 DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1))); 38 block_labels_.SetSize(blocks.Size()); 39 40 DCHECK_EQ(frame_size_, kUninitializedFrameSize); 41 if (!is_leaf) { 42 MarkNotLeaf(); 43 } 44 ComputeFrameSize(GetGraph()->GetMaximumNumberOfOutVRegs() 45 + GetGraph()->GetNumberOfLocalVRegs() 46 + GetGraph()->GetNumberOfTemporaries() 47 + 1 /* filler */); 48 GenerateFrameEntry(); 49 50 for (size_t i = 0, e = blocks.Size(); i < e; ++i) { 51 HBasicBlock* block = blocks.Get(i); 52 Bind(GetLabelOf(block)); 53 HGraphVisitor* location_builder = GetLocationBuilder(); 54 HGraphVisitor* instruction_visitor = GetInstructionVisitor(); 55 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 56 HInstruction* current = it.Current(); 57 current->Accept(location_builder); 58 InitLocations(current); 59 current->Accept(instruction_visitor); 60 } 61 } 62 GenerateSlowPaths(); 63 64 size_t code_size = GetAssembler()->CodeSize(); 65 uint8_t* buffer = allocator->Allocate(code_size); 66 MemoryRegion code(buffer, code_size); 67 GetAssembler()->FinalizeInstructions(code); 68} 69 70void CodeGenerator::CompileOptimized(CodeAllocator* allocator) { 71 // The frame size has already been computed during register allocation. 72 DCHECK_NE(frame_size_, kUninitializedFrameSize); 73 const GrowableArray<HBasicBlock*>& blocks = GetGraph()->GetBlocks(); 74 DCHECK(blocks.Get(0) == GetGraph()->GetEntryBlock()); 75 DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks.Get(1))); 76 block_labels_.SetSize(blocks.Size()); 77 78 GenerateFrameEntry(); 79 for (size_t i = 0, e = blocks.Size(); i < e; ++i) { 80 HBasicBlock* block = blocks.Get(i); 81 Bind(GetLabelOf(block)); 82 HGraphVisitor* instruction_visitor = GetInstructionVisitor(); 83 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 84 HInstruction* current = it.Current(); 85 current->Accept(instruction_visitor); 86 } 87 } 88 GenerateSlowPaths(); 89 90 size_t code_size = GetAssembler()->CodeSize(); 91 uint8_t* buffer = allocator->Allocate(code_size); 92 MemoryRegion code(buffer, code_size); 93 GetAssembler()->FinalizeInstructions(code); 94} 95 96void CodeGenerator::GenerateSlowPaths() { 97 for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) { 98 slow_paths_.Get(i)->EmitNativeCode(this); 99 } 100} 101 102size_t CodeGenerator::AllocateFreeRegisterInternal( 103 bool* blocked_registers, size_t number_of_registers) const { 104 for (size_t regno = 0; regno < number_of_registers; regno++) { 105 if (!blocked_registers[regno]) { 106 blocked_registers[regno] = true; 107 return regno; 108 } 109 } 110 return -1; 111} 112 113void CodeGenerator::ComputeFrameSize(size_t number_of_spill_slots) { 114 SetFrameSize(RoundUp( 115 number_of_spill_slots * kVRegSize 116 + kVRegSize // Art method 117 + FrameEntrySpillSize(), 118 kStackAlignment)); 119} 120 121Location CodeGenerator::GetTemporaryLocation(HTemporary* temp) const { 122 uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs(); 123 // Use the temporary region (right below the dex registers). 124 int32_t slot = GetFrameSize() - FrameEntrySpillSize() 125 - kVRegSize // filler 126 - (number_of_locals * kVRegSize) 127 - ((1 + temp->GetIndex()) * kVRegSize); 128 return Location::StackSlot(slot); 129} 130 131int32_t CodeGenerator::GetStackSlot(HLocal* local) const { 132 uint16_t reg_number = local->GetRegNumber(); 133 uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs(); 134 if (reg_number >= number_of_locals) { 135 // Local is a parameter of the method. It is stored in the caller's frame. 136 return GetFrameSize() + kVRegSize // ART method 137 + (reg_number - number_of_locals) * kVRegSize; 138 } else { 139 // Local is a temporary in this method. It is stored in this method's frame. 140 return GetFrameSize() - FrameEntrySpillSize() 141 - kVRegSize // filler. 142 - (number_of_locals * kVRegSize) 143 + (reg_number * kVRegSize); 144 } 145} 146 147void CodeGenerator::AllocateRegistersLocally(HInstruction* instruction) const { 148 LocationSummary* locations = instruction->GetLocations(); 149 if (locations == nullptr) return; 150 151 for (size_t i = 0, e = GetNumberOfRegisters(); i < e; ++i) { 152 blocked_registers_[i] = false; 153 } 154 155 // Mark all fixed input, temp and output registers as used. 156 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) { 157 Location loc = locations->InAt(i); 158 if (loc.IsRegister()) { 159 // Check that a register is not specified twice in the summary. 160 DCHECK(!blocked_registers_[loc.GetEncoding()]); 161 blocked_registers_[loc.GetEncoding()] = true; 162 } 163 } 164 165 for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) { 166 Location loc = locations->GetTemp(i); 167 if (loc.IsRegister()) { 168 // Check that a register is not specified twice in the summary. 169 DCHECK(!blocked_registers_[loc.GetEncoding()]); 170 blocked_registers_[loc.GetEncoding()] = true; 171 } 172 } 173 174 SetupBlockedRegisters(blocked_registers_); 175 176 // Allocate all unallocated input locations. 177 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) { 178 Location loc = locations->InAt(i); 179 HInstruction* input = instruction->InputAt(i); 180 if (loc.IsUnallocated()) { 181 if (loc.GetPolicy() == Location::kRequiresRegister) { 182 loc = Location::RegisterLocation( 183 AllocateFreeRegister(input->GetType(), blocked_registers_)); 184 } else { 185 DCHECK_EQ(loc.GetPolicy(), Location::kAny); 186 HLoadLocal* load = input->AsLoadLocal(); 187 if (load != nullptr) { 188 loc = GetStackLocation(load); 189 } else { 190 loc = Location::RegisterLocation( 191 AllocateFreeRegister(input->GetType(), blocked_registers_)); 192 } 193 } 194 locations->SetInAt(i, loc); 195 } 196 } 197 198 // Allocate all unallocated temp locations. 199 for (size_t i = 0, e = locations->GetTempCount(); i < e; ++i) { 200 Location loc = locations->GetTemp(i); 201 if (loc.IsUnallocated()) { 202 DCHECK_EQ(loc.GetPolicy(), Location::kRequiresRegister); 203 // TODO: Adjust handling of temps. We currently consider temps to use 204 // core registers. They may also use floating point registers at some point. 205 loc = Location::RegisterLocation(static_cast<ManagedRegister>( 206 AllocateFreeRegister(Primitive::kPrimInt, blocked_registers_))); 207 locations->SetTempAt(i, loc); 208 } 209 } 210 Location result_location = locations->Out(); 211 if (result_location.IsUnallocated()) { 212 switch (result_location.GetPolicy()) { 213 case Location::kAny: 214 case Location::kRequiresRegister: 215 result_location = Location::RegisterLocation( 216 AllocateFreeRegister(instruction->GetType(), blocked_registers_)); 217 break; 218 case Location::kSameAsFirstInput: 219 result_location = locations->InAt(0); 220 break; 221 } 222 locations->SetOut(result_location); 223 } 224} 225 226void CodeGenerator::InitLocations(HInstruction* instruction) { 227 if (instruction->GetLocations() == nullptr) { 228 if (instruction->IsTemporary()) { 229 HInstruction* previous = instruction->GetPrevious(); 230 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 231 Move(previous, temp_location, instruction); 232 previous->GetLocations()->SetOut(temp_location); 233 } 234 return; 235 } 236 AllocateRegistersLocally(instruction); 237 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 238 Location location = instruction->GetLocations()->InAt(i); 239 if (location.IsValid()) { 240 // Move the input to the desired location. 241 Move(instruction->InputAt(i), location, instruction); 242 } 243 } 244} 245 246bool CodeGenerator::GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const { 247 // We currently iterate over the block in insertion order. 248 return current->GetBlockId() + 1 == next->GetBlockId(); 249} 250 251Label* CodeGenerator::GetLabelOf(HBasicBlock* block) const { 252 return block_labels_.GetRawStorage() + block->GetBlockId(); 253} 254 255CodeGenerator* CodeGenerator::Create(ArenaAllocator* allocator, 256 HGraph* graph, 257 InstructionSet instruction_set) { 258 switch (instruction_set) { 259 case kArm: 260 case kThumb2: { 261 return new (allocator) arm::CodeGeneratorARM(graph); 262 } 263 case kMips: 264 return nullptr; 265 case kX86: { 266 return new (allocator) x86::CodeGeneratorX86(graph); 267 } 268 case kX86_64: { 269 return new (allocator) x86_64::CodeGeneratorX86_64(graph); 270 } 271 default: 272 return nullptr; 273 } 274} 275 276void CodeGenerator::BuildNativeGCMap( 277 std::vector<uint8_t>* data, const DexCompilationUnit& dex_compilation_unit) const { 278 const std::vector<uint8_t>& gc_map_raw = 279 dex_compilation_unit.GetVerifiedMethod()->GetDexGcMap(); 280 verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]); 281 282 uint32_t max_native_offset = 0; 283 for (size_t i = 0; i < pc_infos_.Size(); i++) { 284 uint32_t native_offset = pc_infos_.Get(i).native_pc; 285 if (native_offset > max_native_offset) { 286 max_native_offset = native_offset; 287 } 288 } 289 290 GcMapBuilder builder(data, pc_infos_.Size(), max_native_offset, dex_gc_map.RegWidth()); 291 for (size_t i = 0; i < pc_infos_.Size(); i++) { 292 struct PcInfo pc_info = pc_infos_.Get(i); 293 uint32_t native_offset = pc_info.native_pc; 294 uint32_t dex_pc = pc_info.dex_pc; 295 const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); 296 CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc; 297 builder.AddEntry(native_offset, references); 298 } 299} 300 301void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_map) const { 302 uint32_t pc2dex_data_size = 0u; 303 uint32_t pc2dex_entries = pc_infos_.Size(); 304 uint32_t pc2dex_offset = 0u; 305 int32_t pc2dex_dalvik_offset = 0; 306 uint32_t dex2pc_data_size = 0u; 307 uint32_t dex2pc_entries = 0u; 308 309 if (src_map != nullptr) { 310 src_map->reserve(pc2dex_entries); 311 } 312 313 // We currently only have pc2dex entries. 314 for (size_t i = 0; i < pc2dex_entries; i++) { 315 struct PcInfo pc_info = pc_infos_.Get(i); 316 pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset); 317 pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset); 318 pc2dex_offset = pc_info.native_pc; 319 pc2dex_dalvik_offset = pc_info.dex_pc; 320 if (src_map != nullptr) { 321 src_map->push_back(SrcMapElem({pc2dex_offset, pc2dex_dalvik_offset})); 322 } 323 } 324 325 uint32_t total_entries = pc2dex_entries + dex2pc_entries; 326 uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries); 327 uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size; 328 data->resize(data_size); 329 330 uint8_t* data_ptr = &(*data)[0]; 331 uint8_t* write_pos = data_ptr; 332 write_pos = EncodeUnsignedLeb128(write_pos, total_entries); 333 write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries); 334 DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size); 335 uint8_t* write_pos2 = write_pos + pc2dex_data_size; 336 337 pc2dex_offset = 0u; 338 pc2dex_dalvik_offset = 0u; 339 for (size_t i = 0; i < pc2dex_entries; i++) { 340 struct PcInfo pc_info = pc_infos_.Get(i); 341 DCHECK(pc2dex_offset <= pc_info.native_pc); 342 write_pos = EncodeUnsignedLeb128(write_pos, pc_info.native_pc - pc2dex_offset); 343 write_pos = EncodeSignedLeb128(write_pos, pc_info.dex_pc - pc2dex_dalvik_offset); 344 pc2dex_offset = pc_info.native_pc; 345 pc2dex_dalvik_offset = pc_info.dex_pc; 346 } 347 DCHECK_EQ(static_cast<size_t>(write_pos - data_ptr), hdr_data_size + pc2dex_data_size); 348 DCHECK_EQ(static_cast<size_t>(write_pos2 - data_ptr), data_size); 349 350 if (kIsDebugBuild) { 351 // Verify the encoded table holds the expected data. 352 MappingTable table(data_ptr); 353 CHECK_EQ(table.TotalSize(), total_entries); 354 CHECK_EQ(table.PcToDexSize(), pc2dex_entries); 355 auto it = table.PcToDexBegin(); 356 auto it2 = table.DexToPcBegin(); 357 for (size_t i = 0; i < pc2dex_entries; i++) { 358 struct PcInfo pc_info = pc_infos_.Get(i); 359 CHECK_EQ(pc_info.native_pc, it.NativePcOffset()); 360 CHECK_EQ(pc_info.dex_pc, it.DexPc()); 361 ++it; 362 } 363 CHECK(it == table.PcToDexEnd()); 364 CHECK(it2 == table.DexToPcEnd()); 365 } 366} 367 368void CodeGenerator::BuildVMapTable(std::vector<uint8_t>* data) const { 369 Leb128EncodingVector vmap_encoder; 370 // We currently don't use callee-saved registers. 371 size_t size = 0 + 1 /* marker */ + 0; 372 vmap_encoder.Reserve(size + 1u); // All values are likely to be one byte in ULEB128 (<128). 373 vmap_encoder.PushBackUnsigned(size); 374 vmap_encoder.PushBackUnsigned(VmapTable::kAdjustedFpMarker); 375 376 *data = vmap_encoder.GetData(); 377} 378 379} // namespace art 380