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_CODE_GENERATOR_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ 19 20 #include "arch/instruction_set.h" 21 #include "arch/instruction_set_features.h" 22 #include "base/arena_containers.h" 23 #include "base/arena_object.h" 24 #include "base/array_ref.h" 25 #include "base/bit_field.h" 26 #include "base/bit_utils.h" 27 #include "base/enums.h" 28 #include "base/globals.h" 29 #include "base/memory_region.h" 30 #include "dex/string_reference.h" 31 #include "dex/type_reference.h" 32 #include "graph_visualizer.h" 33 #include "locations.h" 34 #include "nodes.h" 35 #include "optimizing_compiler_stats.h" 36 #include "read_barrier_option.h" 37 #include "stack.h" 38 #include "utils/label.h" 39 40 namespace art { 41 42 // Binary encoding of 2^32 for type double. 43 static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000); 44 // Binary encoding of 2^31 for type double. 45 static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000); 46 47 // Minimum value for a primitive integer. 48 static int32_t constexpr kPrimIntMin = 0x80000000; 49 // Minimum value for a primitive long. 50 static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000); 51 52 // Maximum value for a primitive integer. 53 static int32_t constexpr kPrimIntMax = 0x7fffffff; 54 // Maximum value for a primitive long. 55 static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff); 56 57 static constexpr ReadBarrierOption kCompilerReadBarrierOption = 58 kEmitCompilerReadBarrier ? kWithReadBarrier : kWithoutReadBarrier; 59 60 class Assembler; 61 class CodeGenerator; 62 class CompilerOptions; 63 class StackMapStream; 64 class ParallelMoveResolver; 65 66 namespace linker { 67 class LinkerPatch; 68 } // namespace linker 69 70 class CodeAllocator { 71 public: CodeAllocator()72 CodeAllocator() {} ~CodeAllocator()73 virtual ~CodeAllocator() {} 74 75 virtual uint8_t* Allocate(size_t size) = 0; 76 virtual ArrayRef<const uint8_t> GetMemory() const = 0; 77 78 private: 79 DISALLOW_COPY_AND_ASSIGN(CodeAllocator); 80 }; 81 82 class SlowPathCode : public DeletableArenaObject<kArenaAllocSlowPaths> { 83 public: SlowPathCode(HInstruction * instruction)84 explicit SlowPathCode(HInstruction* instruction) : instruction_(instruction) { 85 for (size_t i = 0; i < kMaximumNumberOfExpectedRegisters; ++i) { 86 saved_core_stack_offsets_[i] = kRegisterNotSaved; 87 saved_fpu_stack_offsets_[i] = kRegisterNotSaved; 88 } 89 } 90 ~SlowPathCode()91 virtual ~SlowPathCode() {} 92 93 virtual void EmitNativeCode(CodeGenerator* codegen) = 0; 94 95 // Save live core and floating-point caller-save registers and 96 // update the stack mask in `locations` for registers holding object 97 // references. 98 virtual void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations); 99 // Restore live core and floating-point caller-save registers. 100 virtual void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations); 101 IsCoreRegisterSaved(int reg)102 bool IsCoreRegisterSaved(int reg) const { 103 return saved_core_stack_offsets_[reg] != kRegisterNotSaved; 104 } 105 IsFpuRegisterSaved(int reg)106 bool IsFpuRegisterSaved(int reg) const { 107 return saved_fpu_stack_offsets_[reg] != kRegisterNotSaved; 108 } 109 GetStackOffsetOfCoreRegister(int reg)110 uint32_t GetStackOffsetOfCoreRegister(int reg) const { 111 return saved_core_stack_offsets_[reg]; 112 } 113 GetStackOffsetOfFpuRegister(int reg)114 uint32_t GetStackOffsetOfFpuRegister(int reg) const { 115 return saved_fpu_stack_offsets_[reg]; 116 } 117 IsFatal()118 virtual bool IsFatal() const { return false; } 119 120 virtual const char* GetDescription() const = 0; 121 GetEntryLabel()122 Label* GetEntryLabel() { return &entry_label_; } GetExitLabel()123 Label* GetExitLabel() { return &exit_label_; } 124 GetInstruction()125 HInstruction* GetInstruction() const { 126 return instruction_; 127 } 128 GetDexPc()129 uint32_t GetDexPc() const { 130 return instruction_ != nullptr ? instruction_->GetDexPc() : kNoDexPc; 131 } 132 133 protected: 134 static constexpr size_t kMaximumNumberOfExpectedRegisters = 32; 135 static constexpr uint32_t kRegisterNotSaved = -1; 136 // The instruction where this slow path is happening. 137 HInstruction* instruction_; 138 uint32_t saved_core_stack_offsets_[kMaximumNumberOfExpectedRegisters]; 139 uint32_t saved_fpu_stack_offsets_[kMaximumNumberOfExpectedRegisters]; 140 141 private: 142 Label entry_label_; 143 Label exit_label_; 144 145 DISALLOW_COPY_AND_ASSIGN(SlowPathCode); 146 }; 147 148 class InvokeDexCallingConventionVisitor { 149 public: 150 virtual Location GetNextLocation(DataType::Type type) = 0; 151 virtual Location GetReturnLocation(DataType::Type type) const = 0; 152 virtual Location GetMethodLocation() const = 0; 153 154 protected: InvokeDexCallingConventionVisitor()155 InvokeDexCallingConventionVisitor() {} ~InvokeDexCallingConventionVisitor()156 virtual ~InvokeDexCallingConventionVisitor() {} 157 158 // The current index for core registers. 159 uint32_t gp_index_ = 0u; 160 // The current index for floating-point registers. 161 uint32_t float_index_ = 0u; 162 // The current stack index. 163 uint32_t stack_index_ = 0u; 164 165 private: 166 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor); 167 }; 168 169 class FieldAccessCallingConvention { 170 public: 171 virtual Location GetObjectLocation() const = 0; 172 virtual Location GetFieldIndexLocation() const = 0; 173 virtual Location GetReturnLocation(DataType::Type type) const = 0; 174 virtual Location GetSetValueLocation(DataType::Type type, bool is_instance) const = 0; 175 virtual Location GetFpuLocation(DataType::Type type) const = 0; ~FieldAccessCallingConvention()176 virtual ~FieldAccessCallingConvention() {} 177 178 protected: FieldAccessCallingConvention()179 FieldAccessCallingConvention() {} 180 181 private: 182 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConvention); 183 }; 184 185 class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { 186 public: 187 // Compiles the graph to executable instructions. 188 void Compile(CodeAllocator* allocator); 189 static std::unique_ptr<CodeGenerator> Create(HGraph* graph, 190 const CompilerOptions& compiler_options, 191 OptimizingCompilerStats* stats = nullptr); 192 virtual ~CodeGenerator(); 193 194 // Get the graph. This is the outermost graph, never the graph of a method being inlined. GetGraph()195 HGraph* GetGraph() const { return graph_; } 196 197 HBasicBlock* GetNextBlockToEmit() const; 198 HBasicBlock* FirstNonEmptyBlock(HBasicBlock* block) const; 199 bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const; 200 GetStackSlotOfParameter(HParameterValue * parameter)201 size_t GetStackSlotOfParameter(HParameterValue* parameter) const { 202 // Note that this follows the current calling convention. 203 return GetFrameSize() 204 + static_cast<size_t>(InstructionSetPointerSize(GetInstructionSet())) // Art method 205 + parameter->GetIndex() * kVRegSize; 206 } 207 208 virtual void Initialize() = 0; 209 virtual void Finalize(CodeAllocator* allocator); 210 virtual void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches); 211 virtual bool NeedsThunkCode(const linker::LinkerPatch& patch) const; 212 virtual void EmitThunkCode(const linker::LinkerPatch& patch, 213 /*out*/ ArenaVector<uint8_t>* code, 214 /*out*/ std::string* debug_name); 215 virtual void GenerateFrameEntry() = 0; 216 virtual void GenerateFrameExit() = 0; 217 virtual void Bind(HBasicBlock* block) = 0; 218 virtual void MoveConstant(Location destination, int32_t value) = 0; 219 virtual void MoveLocation(Location dst, Location src, DataType::Type dst_type) = 0; 220 virtual void AddLocationAsTemp(Location location, LocationSummary* locations) = 0; 221 222 virtual Assembler* GetAssembler() = 0; 223 virtual const Assembler& GetAssembler() const = 0; 224 virtual size_t GetWordSize() const = 0; 225 226 // Returns whether the target supports predicated SIMD instructions. SupportsPredicatedSIMD()227 virtual bool SupportsPredicatedSIMD() const { return false; } 228 229 // Get FP register width in bytes for spilling/restoring in the slow paths. 230 // 231 // Note: In SIMD graphs this should return SIMD register width as all FP and SIMD registers 232 // alias and live SIMD registers are forced to be spilled in full size in the slow paths. GetSlowPathFPWidth()233 virtual size_t GetSlowPathFPWidth() const { 234 // Default implementation. 235 return GetCalleePreservedFPWidth(); 236 } 237 238 // Get FP register width required to be preserved by the target ABI. 239 virtual size_t GetCalleePreservedFPWidth() const = 0; 240 241 // Get the size of the target SIMD register in bytes. 242 virtual size_t GetSIMDRegisterWidth() const = 0; 243 virtual uintptr_t GetAddressOf(HBasicBlock* block) = 0; 244 void InitializeCodeGeneration(size_t number_of_spill_slots, 245 size_t maximum_safepoint_spill_size, 246 size_t number_of_out_slots, 247 const ArenaVector<HBasicBlock*>& block_order); 248 // Backends can override this as necessary. For most, no special alignment is required. GetPreferredSlotsAlignment()249 virtual uint32_t GetPreferredSlotsAlignment() const { return 1; } 250 GetFrameSize()251 uint32_t GetFrameSize() const { return frame_size_; } SetFrameSize(uint32_t size)252 void SetFrameSize(uint32_t size) { frame_size_ = size; } GetCoreSpillMask()253 uint32_t GetCoreSpillMask() const { return core_spill_mask_; } GetFpuSpillMask()254 uint32_t GetFpuSpillMask() const { return fpu_spill_mask_; } 255 GetNumberOfCoreRegisters()256 size_t GetNumberOfCoreRegisters() const { return number_of_core_registers_; } GetNumberOfFloatingPointRegisters()257 size_t GetNumberOfFloatingPointRegisters() const { return number_of_fpu_registers_; } 258 virtual void SetupBlockedRegisters() const = 0; 259 ComputeSpillMask()260 virtual void ComputeSpillMask() { 261 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_; 262 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved"; 263 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_; 264 } 265 ComputeRegisterMask(const int * registers,size_t length)266 static uint32_t ComputeRegisterMask(const int* registers, size_t length) { 267 uint32_t mask = 0; 268 for (size_t i = 0, e = length; i < e; ++i) { 269 mask |= (1 << registers[i]); 270 } 271 return mask; 272 } 273 274 virtual void DumpCoreRegister(std::ostream& stream, int reg) const = 0; 275 virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const = 0; 276 virtual InstructionSet GetInstructionSet() const = 0; 277 GetCompilerOptions()278 const CompilerOptions& GetCompilerOptions() const { return compiler_options_; } 279 280 // Saves the register in the stack. Returns the size taken on stack. 281 virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) = 0; 282 // Restores the register from the stack. Returns the size taken on stack. 283 virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) = 0; 284 285 virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0; 286 virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0; 287 288 virtual bool NeedsTwoRegisters(DataType::Type type) const = 0; 289 // Returns whether we should split long moves in parallel moves. ShouldSplitLongMoves()290 virtual bool ShouldSplitLongMoves() const { return false; } 291 GetNumberOfCoreCalleeSaveRegisters()292 size_t GetNumberOfCoreCalleeSaveRegisters() const { 293 return POPCOUNT(core_callee_save_mask_); 294 } 295 GetNumberOfCoreCallerSaveRegisters()296 size_t GetNumberOfCoreCallerSaveRegisters() const { 297 DCHECK_GE(GetNumberOfCoreRegisters(), GetNumberOfCoreCalleeSaveRegisters()); 298 return GetNumberOfCoreRegisters() - GetNumberOfCoreCalleeSaveRegisters(); 299 } 300 IsCoreCalleeSaveRegister(int reg)301 bool IsCoreCalleeSaveRegister(int reg) const { 302 return (core_callee_save_mask_ & (1 << reg)) != 0; 303 } 304 IsFloatingPointCalleeSaveRegister(int reg)305 bool IsFloatingPointCalleeSaveRegister(int reg) const { 306 return (fpu_callee_save_mask_ & (1 << reg)) != 0; 307 } 308 GetSlowPathSpills(LocationSummary * locations,bool core_registers)309 uint32_t GetSlowPathSpills(LocationSummary* locations, bool core_registers) const { 310 DCHECK(locations->OnlyCallsOnSlowPath() || 311 (locations->Intrinsified() && locations->CallsOnMainAndSlowPath() && 312 !locations->HasCustomSlowPathCallingConvention())); 313 uint32_t live_registers = core_registers 314 ? locations->GetLiveRegisters()->GetCoreRegisters() 315 : locations->GetLiveRegisters()->GetFloatingPointRegisters(); 316 if (locations->HasCustomSlowPathCallingConvention()) { 317 // Save only the live registers that the custom calling convention wants us to save. 318 uint32_t caller_saves = core_registers 319 ? locations->GetCustomSlowPathCallerSaves().GetCoreRegisters() 320 : locations->GetCustomSlowPathCallerSaves().GetFloatingPointRegisters(); 321 return live_registers & caller_saves; 322 } else { 323 // Default ABI, we need to spill non-callee-save live registers. 324 uint32_t callee_saves = core_registers ? core_callee_save_mask_ : fpu_callee_save_mask_; 325 return live_registers & ~callee_saves; 326 } 327 } 328 GetNumberOfSlowPathSpills(LocationSummary * locations,bool core_registers)329 size_t GetNumberOfSlowPathSpills(LocationSummary* locations, bool core_registers) const { 330 return POPCOUNT(GetSlowPathSpills(locations, core_registers)); 331 } 332 GetStackOffsetOfShouldDeoptimizeFlag()333 size_t GetStackOffsetOfShouldDeoptimizeFlag() const { 334 DCHECK(GetGraph()->HasShouldDeoptimizeFlag()); 335 DCHECK_GE(GetFrameSize(), FrameEntrySpillSize() + kShouldDeoptimizeFlagSize); 336 return GetFrameSize() - FrameEntrySpillSize() - kShouldDeoptimizeFlagSize; 337 } 338 339 // Record native to dex mapping for a suspend point. Required by runtime. 340 void RecordPcInfo(HInstruction* instruction, 341 uint32_t dex_pc, 342 uint32_t native_pc, 343 SlowPathCode* slow_path = nullptr, 344 bool native_debug_info = false); 345 346 // Record native to dex mapping for a suspend point. 347 // The native_pc is used from Assembler::CodePosition. 348 // 349 // Note: As Assembler::CodePosition is target dependent, it does not guarantee the exact native_pc 350 // for the instruction. If the exact native_pc is required it must be provided explicitly. 351 void RecordPcInfo(HInstruction* instruction, 352 uint32_t dex_pc, 353 SlowPathCode* slow_path = nullptr, 354 bool native_debug_info = false); 355 356 // Check whether we have already recorded mapping at this PC. 357 bool HasStackMapAtCurrentPc(); 358 359 // Record extra stack maps if we support native debugging. 360 // 361 // ARM specific behaviour: The recorded native PC might be a branch over pools to instructions 362 // corresponding the dex PC. 363 void MaybeRecordNativeDebugInfo(HInstruction* instruction, 364 uint32_t dex_pc, 365 SlowPathCode* slow_path = nullptr); 366 367 bool CanMoveNullCheckToUser(HNullCheck* null_check); 368 virtual void MaybeRecordImplicitNullCheck(HInstruction* instruction); 369 LocationSummary* CreateThrowingSlowPathLocations( 370 HInstruction* instruction, RegisterSet caller_saves = RegisterSet::Empty()); 371 void GenerateNullCheck(HNullCheck* null_check); 372 virtual void GenerateImplicitNullCheck(HNullCheck* null_check) = 0; 373 virtual void GenerateExplicitNullCheck(HNullCheck* null_check) = 0; 374 375 // Records a stack map which the runtime might use to set catch phi values 376 // during exception delivery. 377 // TODO: Replace with a catch-entering instruction that records the environment. 378 void RecordCatchBlockInfo(); 379 380 // Get the ScopedArenaAllocator used for codegen memory allocation. 381 ScopedArenaAllocator* GetScopedAllocator(); 382 383 void AddSlowPath(SlowPathCode* slow_path); 384 385 ScopedArenaVector<uint8_t> BuildStackMaps(const dex::CodeItem* code_item_for_osr_check); 386 size_t GetNumberOfJitRoots() const; 387 388 // Fills the `literals` array with literals collected during code generation. 389 // Also emits literal patches. 390 void EmitJitRoots(uint8_t* code, 391 const uint8_t* roots_data, 392 /*out*/std::vector<Handle<mirror::Object>>* roots) 393 REQUIRES_SHARED(Locks::mutator_lock_); 394 IsLeafMethod()395 bool IsLeafMethod() const { 396 return is_leaf_; 397 } 398 MarkNotLeaf()399 void MarkNotLeaf() { 400 is_leaf_ = false; 401 requires_current_method_ = true; 402 } 403 SetRequiresCurrentMethod()404 void SetRequiresCurrentMethod() { 405 requires_current_method_ = true; 406 } 407 RequiresCurrentMethod()408 bool RequiresCurrentMethod() const { 409 return requires_current_method_; 410 } 411 412 // Clears the spill slots taken by loop phis in the `LocationSummary` of the 413 // suspend check. This is called when the code generator generates code 414 // for the suspend check at the back edge (instead of where the suspend check 415 // is, which is the loop entry). At this point, the spill slots for the phis 416 // have not been written to. 417 void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check, 418 HParallelMove* spills) const; 419 GetBlockedCoreRegisters()420 bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; } GetBlockedFloatingPointRegisters()421 bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; } 422 IsBlockedCoreRegister(size_t i)423 bool IsBlockedCoreRegister(size_t i) { return blocked_core_registers_[i]; } IsBlockedFloatingPointRegister(size_t i)424 bool IsBlockedFloatingPointRegister(size_t i) { return blocked_fpu_registers_[i]; } 425 426 // Helper that returns the offset of the array's length field. 427 // Note: Besides the normal arrays, we also use the HArrayLength for 428 // accessing the String's `count` field in String intrinsics. 429 static uint32_t GetArrayLengthOffset(HArrayLength* array_length); 430 431 // Helper that returns the offset of the array's data. 432 // Note: Besides the normal arrays, we also use the HArrayGet for 433 // accessing the String's `value` field in String intrinsics. 434 static uint32_t GetArrayDataOffset(HArrayGet* array_get); 435 436 void EmitParallelMoves(Location from1, 437 Location to1, 438 DataType::Type type1, 439 Location from2, 440 Location to2, 441 DataType::Type type2); 442 InstanceOfNeedsReadBarrier(HInstanceOf * instance_of)443 static bool InstanceOfNeedsReadBarrier(HInstanceOf* instance_of) { 444 // Used only for kExactCheck, kAbstractClassCheck, kClassHierarchyCheck and kArrayObjectCheck. 445 DCHECK(instance_of->GetTypeCheckKind() == TypeCheckKind::kExactCheck || 446 instance_of->GetTypeCheckKind() == TypeCheckKind::kAbstractClassCheck || 447 instance_of->GetTypeCheckKind() == TypeCheckKind::kClassHierarchyCheck || 448 instance_of->GetTypeCheckKind() == TypeCheckKind::kArrayObjectCheck) 449 << instance_of->GetTypeCheckKind(); 450 // If the target class is in the boot image, it's non-moveable and it doesn't matter 451 // if we compare it with a from-space or to-space reference, the result is the same. 452 // It's OK to traverse a class hierarchy jumping between from-space and to-space. 453 return kEmitCompilerReadBarrier && !instance_of->GetTargetClass()->IsInBootImage(); 454 } 455 ReadBarrierOptionForInstanceOf(HInstanceOf * instance_of)456 static ReadBarrierOption ReadBarrierOptionForInstanceOf(HInstanceOf* instance_of) { 457 return InstanceOfNeedsReadBarrier(instance_of) ? kWithReadBarrier : kWithoutReadBarrier; 458 } 459 IsTypeCheckSlowPathFatal(HCheckCast * check_cast)460 static bool IsTypeCheckSlowPathFatal(HCheckCast* check_cast) { 461 switch (check_cast->GetTypeCheckKind()) { 462 case TypeCheckKind::kExactCheck: 463 case TypeCheckKind::kAbstractClassCheck: 464 case TypeCheckKind::kClassHierarchyCheck: 465 case TypeCheckKind::kArrayObjectCheck: 466 case TypeCheckKind::kInterfaceCheck: { 467 bool needs_read_barrier = 468 kEmitCompilerReadBarrier && !check_cast->GetTargetClass()->IsInBootImage(); 469 // We do not emit read barriers for HCheckCast, so we can get false negatives 470 // and the slow path shall re-check and simply return if the cast is actually OK. 471 return !needs_read_barrier; 472 } 473 case TypeCheckKind::kArrayCheck: 474 case TypeCheckKind::kUnresolvedCheck: 475 return false; 476 case TypeCheckKind::kBitstringCheck: 477 return true; 478 } 479 LOG(FATAL) << "Unreachable"; 480 UNREACHABLE(); 481 } 482 GetCheckCastCallKind(HCheckCast * check_cast)483 static LocationSummary::CallKind GetCheckCastCallKind(HCheckCast* check_cast) { 484 return (IsTypeCheckSlowPathFatal(check_cast) && !check_cast->CanThrowIntoCatchBlock()) 485 ? LocationSummary::kNoCall // In fact, call on a fatal (non-returning) slow path. 486 : LocationSummary::kCallOnSlowPath; 487 } 488 StoreNeedsWriteBarrier(DataType::Type type,HInstruction * value)489 static bool StoreNeedsWriteBarrier(DataType::Type type, HInstruction* value) { 490 // Check that null value is not represented as an integer constant. 491 DCHECK(type != DataType::Type::kReference || !value->IsIntConstant()); 492 return type == DataType::Type::kReference && !value->IsNullConstant(); 493 } 494 495 496 // Performs checks pertaining to an InvokeRuntime call. 497 void ValidateInvokeRuntime(QuickEntrypointEnum entrypoint, 498 HInstruction* instruction, 499 SlowPathCode* slow_path); 500 501 // Performs checks pertaining to an InvokeRuntimeWithoutRecordingPcInfo call. 502 static void ValidateInvokeRuntimeWithoutRecordingPcInfo(HInstruction* instruction, 503 SlowPathCode* slow_path); 504 AddAllocatedRegister(Location location)505 void AddAllocatedRegister(Location location) { 506 allocated_registers_.Add(location); 507 } 508 HasAllocatedRegister(bool is_core,int reg)509 bool HasAllocatedRegister(bool is_core, int reg) const { 510 return is_core 511 ? allocated_registers_.ContainsCoreRegister(reg) 512 : allocated_registers_.ContainsFloatingPointRegister(reg); 513 } 514 515 void AllocateLocations(HInstruction* instruction); 516 517 // Tells whether the stack frame of the compiled method is 518 // considered "empty", that is either actually having a size of zero, 519 // or just containing the saved return address register. HasEmptyFrame()520 bool HasEmptyFrame() const { 521 return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0); 522 } 523 GetInt8ValueOf(HConstant * constant)524 static int8_t GetInt8ValueOf(HConstant* constant) { 525 DCHECK(constant->IsIntConstant()); 526 return constant->AsIntConstant()->GetValue(); 527 } 528 GetInt16ValueOf(HConstant * constant)529 static int16_t GetInt16ValueOf(HConstant* constant) { 530 DCHECK(constant->IsIntConstant()); 531 return constant->AsIntConstant()->GetValue(); 532 } 533 GetInt32ValueOf(HConstant * constant)534 static int32_t GetInt32ValueOf(HConstant* constant) { 535 if (constant->IsIntConstant()) { 536 return constant->AsIntConstant()->GetValue(); 537 } else if (constant->IsNullConstant()) { 538 return 0; 539 } else { 540 DCHECK(constant->IsFloatConstant()); 541 return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue()); 542 } 543 } 544 GetInt64ValueOf(HConstant * constant)545 static int64_t GetInt64ValueOf(HConstant* constant) { 546 if (constant->IsIntConstant()) { 547 return constant->AsIntConstant()->GetValue(); 548 } else if (constant->IsNullConstant()) { 549 return 0; 550 } else if (constant->IsFloatConstant()) { 551 return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue()); 552 } else if (constant->IsLongConstant()) { 553 return constant->AsLongConstant()->GetValue(); 554 } else { 555 DCHECK(constant->IsDoubleConstant()); 556 return bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); 557 } 558 } 559 GetFirstRegisterSlotInSlowPath()560 size_t GetFirstRegisterSlotInSlowPath() const { 561 return first_register_slot_in_slow_path_; 562 } 563 FrameEntrySpillSize()564 uint32_t FrameEntrySpillSize() const { 565 return GetFpuSpillSize() + GetCoreSpillSize(); 566 } 567 568 virtual ParallelMoveResolver* GetMoveResolver() = 0; 569 570 static void CreateCommonInvokeLocationSummary( 571 HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor); 572 573 template <typename CriticalNativeCallingConventionVisitor, 574 size_t kNativeStackAlignment, 575 size_t GetCriticalNativeDirectCallFrameSize(const char* shorty, uint32_t shorty_len)> PrepareCriticalNativeCall(HInvokeStaticOrDirect * invoke)576 size_t PrepareCriticalNativeCall(HInvokeStaticOrDirect* invoke) { 577 DCHECK(!invoke->GetLocations()->Intrinsified()); 578 CriticalNativeCallingConventionVisitor calling_convention_visitor( 579 /*for_register_allocation=*/ false); 580 HParallelMove parallel_move(GetGraph()->GetAllocator()); 581 PrepareCriticalNativeArgumentMoves(invoke, &calling_convention_visitor, ¶llel_move); 582 size_t out_frame_size = 583 RoundUp(calling_convention_visitor.GetStackOffset(), kNativeStackAlignment); 584 if (kIsDebugBuild) { 585 uint32_t shorty_len; 586 const char* shorty = GetCriticalNativeShorty(invoke, &shorty_len); 587 DCHECK_EQ(GetCriticalNativeDirectCallFrameSize(shorty, shorty_len), out_frame_size); 588 } 589 if (out_frame_size != 0u) { 590 FinishCriticalNativeFrameSetup(out_frame_size, ¶llel_move); 591 } 592 return out_frame_size; 593 } 594 595 void GenerateInvokeStaticOrDirectRuntimeCall( 596 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path); 597 598 void GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke); 599 600 void GenerateInvokePolymorphicCall(HInvokePolymorphic* invoke); 601 602 void GenerateInvokeCustomCall(HInvokeCustom* invoke); 603 604 void CreateStringBuilderAppendLocations(HStringBuilderAppend* instruction, Location out); 605 606 void CreateUnresolvedFieldLocationSummary( 607 HInstruction* field_access, 608 DataType::Type field_type, 609 const FieldAccessCallingConvention& calling_convention); 610 611 void GenerateUnresolvedFieldAccess( 612 HInstruction* field_access, 613 DataType::Type field_type, 614 uint32_t field_index, 615 uint32_t dex_pc, 616 const FieldAccessCallingConvention& calling_convention); 617 618 static void CreateLoadClassRuntimeCallLocationSummary(HLoadClass* cls, 619 Location runtime_type_index_location, 620 Location runtime_return_location); 621 void GenerateLoadClassRuntimeCall(HLoadClass* cls); 622 623 static void CreateLoadMethodHandleRuntimeCallLocationSummary(HLoadMethodHandle* method_handle, 624 Location runtime_handle_index_location, 625 Location runtime_return_location); 626 void GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle); 627 628 static void CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type, 629 Location runtime_type_index_location, 630 Location runtime_return_location); 631 void GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type); 632 633 uint32_t GetBootImageOffset(HLoadClass* load_class); 634 uint32_t GetBootImageOffset(HLoadString* load_string); 635 uint32_t GetBootImageOffset(HInvokeStaticOrDirect* invoke); 636 637 static void CreateSystemArrayCopyLocationSummary(HInvoke* invoke); 638 SetDisassemblyInformation(DisassemblyInformation * info)639 void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; } GetDisassemblyInformation()640 DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; } 641 642 virtual void InvokeRuntime(QuickEntrypointEnum entrypoint, 643 HInstruction* instruction, 644 uint32_t dex_pc, 645 SlowPathCode* slow_path = nullptr) = 0; 646 647 // Check if the desired_string_load_kind is supported. If it is, return it, 648 // otherwise return a fall-back kind that should be used instead. 649 virtual HLoadString::LoadKind GetSupportedLoadStringKind( 650 HLoadString::LoadKind desired_string_load_kind) = 0; 651 652 // Check if the desired_class_load_kind is supported. If it is, return it, 653 // otherwise return a fall-back kind that should be used instead. 654 virtual HLoadClass::LoadKind GetSupportedLoadClassKind( 655 HLoadClass::LoadKind desired_class_load_kind) = 0; 656 GetLoadStringCallKind(HLoadString * load)657 static LocationSummary::CallKind GetLoadStringCallKind(HLoadString* load) { 658 switch (load->GetLoadKind()) { 659 case HLoadString::LoadKind::kBssEntry: 660 DCHECK(load->NeedsEnvironment()); 661 return LocationSummary::kCallOnSlowPath; 662 case HLoadString::LoadKind::kRuntimeCall: 663 DCHECK(load->NeedsEnvironment()); 664 return LocationSummary::kCallOnMainOnly; 665 case HLoadString::LoadKind::kJitTableAddress: 666 DCHECK(!load->NeedsEnvironment()); 667 return kEmitCompilerReadBarrier 668 ? LocationSummary::kCallOnSlowPath 669 : LocationSummary::kNoCall; 670 break; 671 default: 672 DCHECK(!load->NeedsEnvironment()); 673 return LocationSummary::kNoCall; 674 } 675 } 676 677 // Check if the desired_dispatch_info is supported. If it is, return it, 678 // otherwise return a fall-back info that should be used instead. 679 virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 680 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 681 ArtMethod* method) = 0; 682 683 // Generate a call to a static or direct method. 684 virtual void GenerateStaticOrDirectCall( 685 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) = 0; 686 // Generate a call to a virtual method. 687 virtual void GenerateVirtualCall( 688 HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) = 0; 689 690 // Copy the result of a call into the given target. 691 virtual void MoveFromReturnRegister(Location trg, DataType::Type type) = 0; 692 693 virtual void IncreaseFrame(size_t adjustment) = 0; 694 virtual void DecreaseFrame(size_t adjustment) = 0; 695 696 virtual void GenerateNop() = 0; 697 698 static QuickEntrypointEnum GetArrayAllocationEntrypoint(HNewArray* new_array); 699 700 protected: 701 // Patch info used for recording locations of required linker patches and their targets, 702 // i.e. target method, string, type or code identified by their dex file and index, 703 // or .data.bimg.rel.ro entries identified by the boot image offset. 704 template <typename LabelType> 705 struct PatchInfo { PatchInfoPatchInfo706 PatchInfo(const DexFile* dex_file, uint32_t off_or_idx) 707 : target_dex_file(dex_file), offset_or_index(off_or_idx), label() { } 708 709 // Target dex file or null for .data.bmig.rel.ro patches. 710 const DexFile* target_dex_file; 711 // Either the boot image offset (to write to .data.bmig.rel.ro) or string/type/method index. 712 uint32_t offset_or_index; 713 // Label for the instruction to patch. 714 LabelType label; 715 }; 716 717 CodeGenerator(HGraph* graph, 718 size_t number_of_core_registers, 719 size_t number_of_fpu_registers, 720 size_t number_of_register_pairs, 721 uint32_t core_callee_save_mask, 722 uint32_t fpu_callee_save_mask, 723 const CompilerOptions& compiler_options, 724 OptimizingCompilerStats* stats); 725 726 virtual HGraphVisitor* GetLocationBuilder() = 0; 727 virtual HGraphVisitor* GetInstructionVisitor() = 0; 728 729 // Returns the location of the first spilled entry for floating point registers, 730 // relative to the stack pointer. GetFpuSpillStart()731 uint32_t GetFpuSpillStart() const { 732 return GetFrameSize() - FrameEntrySpillSize(); 733 } 734 GetFpuSpillSize()735 uint32_t GetFpuSpillSize() const { 736 return POPCOUNT(fpu_spill_mask_) * GetCalleePreservedFPWidth(); 737 } 738 GetCoreSpillSize()739 uint32_t GetCoreSpillSize() const { 740 return POPCOUNT(core_spill_mask_) * GetWordSize(); 741 } 742 HasAllocatedCalleeSaveRegisters()743 virtual bool HasAllocatedCalleeSaveRegisters() const { 744 // We check the core registers against 1 because it always comprises the return PC. 745 return (POPCOUNT(allocated_registers_.GetCoreRegisters() & core_callee_save_mask_) != 1) 746 || (POPCOUNT(allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_) != 0); 747 } 748 CallPushesPC()749 bool CallPushesPC() const { 750 InstructionSet instruction_set = GetInstructionSet(); 751 return instruction_set == InstructionSet::kX86 || instruction_set == InstructionSet::kX86_64; 752 } 753 754 // Arm64 has its own type for a label, so we need to templatize these methods 755 // to share the logic. 756 757 template <typename LabelType> CommonInitializeLabels()758 LabelType* CommonInitializeLabels() { 759 // We use raw array allocations instead of ArenaVector<> because Labels are 760 // non-constructible and non-movable and as such cannot be held in a vector. 761 size_t size = GetGraph()->GetBlocks().size(); 762 LabelType* labels = 763 GetGraph()->GetAllocator()->AllocArray<LabelType>(size, kArenaAllocCodeGenerator); 764 for (size_t i = 0; i != size; ++i) { 765 new(labels + i) LabelType(); 766 } 767 return labels; 768 } 769 770 template <typename LabelType> CommonGetLabelOf(LabelType * raw_pointer_to_labels_array,HBasicBlock * block)771 LabelType* CommonGetLabelOf(LabelType* raw_pointer_to_labels_array, HBasicBlock* block) const { 772 block = FirstNonEmptyBlock(block); 773 return raw_pointer_to_labels_array + block->GetBlockId(); 774 } 775 GetCurrentSlowPath()776 SlowPathCode* GetCurrentSlowPath() { 777 return current_slow_path_; 778 } 779 780 StackMapStream* GetStackMapStream(); 781 782 void ReserveJitStringRoot(StringReference string_reference, Handle<mirror::String> string); 783 uint64_t GetJitStringRootIndex(StringReference string_reference); 784 void ReserveJitClassRoot(TypeReference type_reference, Handle<mirror::Class> klass); 785 uint64_t GetJitClassRootIndex(TypeReference type_reference); 786 787 // Emit the patches assocatied with JIT roots. Only applies to JIT compiled code. 788 virtual void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data); 789 790 // Frame size required for this method. 791 uint32_t frame_size_; 792 uint32_t core_spill_mask_; 793 uint32_t fpu_spill_mask_; 794 uint32_t first_register_slot_in_slow_path_; 795 796 // Registers that were allocated during linear scan. 797 RegisterSet allocated_registers_; 798 799 // Arrays used when doing register allocation to know which 800 // registers we can allocate. `SetupBlockedRegisters` updates the 801 // arrays. 802 bool* const blocked_core_registers_; 803 bool* const blocked_fpu_registers_; 804 size_t number_of_core_registers_; 805 size_t number_of_fpu_registers_; 806 size_t number_of_register_pairs_; 807 const uint32_t core_callee_save_mask_; 808 const uint32_t fpu_callee_save_mask_; 809 810 // The order to use for code generation. 811 const ArenaVector<HBasicBlock*>* block_order_; 812 813 DisassemblyInformation* disasm_info_; 814 815 private: 816 class CodeGenerationData; 817 818 void InitializeCodeGenerationData(); 819 size_t GetStackOffsetOfSavedRegister(size_t index); 820 void GenerateSlowPaths(); 821 void BlockIfInRegister(Location location, bool is_out = false) const; 822 void EmitEnvironment(HEnvironment* environment, 823 SlowPathCode* slow_path, 824 bool needs_vreg_info = true); 825 void EmitVRegInfo(HEnvironment* environment, SlowPathCode* slow_path); 826 827 static void PrepareCriticalNativeArgumentMoves( 828 HInvokeStaticOrDirect* invoke, 829 /*inout*/InvokeDexCallingConventionVisitor* visitor, 830 /*out*/HParallelMove* parallel_move); 831 832 void FinishCriticalNativeFrameSetup(size_t out_frame_size, /*inout*/HParallelMove* parallel_move); 833 834 static const char* GetCriticalNativeShorty(HInvokeStaticOrDirect* invoke, uint32_t* shorty_len); 835 836 OptimizingCompilerStats* stats_; 837 838 HGraph* const graph_; 839 const CompilerOptions& compiler_options_; 840 841 // The current slow-path that we're generating code for. 842 SlowPathCode* current_slow_path_; 843 844 // The current block index in `block_order_` of the block 845 // we are generating code for. 846 size_t current_block_index_; 847 848 // Whether the method is a leaf method. 849 bool is_leaf_; 850 851 // Whether an instruction in the graph accesses the current method. 852 // TODO: Rename: this actually indicates that some instruction in the method 853 // needs the environment including a valid stack frame. 854 bool requires_current_method_; 855 856 // The CodeGenerationData contains a ScopedArenaAllocator intended for reusing the 857 // ArenaStack memory allocated in previous passes instead of adding to the memory 858 // held by the ArenaAllocator. This ScopedArenaAllocator is created in 859 // CodeGenerator::Compile() and remains alive until the CodeGenerator is destroyed. 860 std::unique_ptr<CodeGenerationData> code_generation_data_; 861 862 friend class OptimizingCFITest; 863 ART_FRIEND_TEST(CodegenTest, ARM64FrameSizeSIMD); 864 ART_FRIEND_TEST(CodegenTest, ARM64FrameSizeNoSIMD); 865 866 DISALLOW_COPY_AND_ASSIGN(CodeGenerator); 867 }; 868 869 template <typename C, typename F> 870 class CallingConvention { 871 public: CallingConvention(const C * registers,size_t number_of_registers,const F * fpu_registers,size_t number_of_fpu_registers,PointerSize pointer_size)872 CallingConvention(const C* registers, 873 size_t number_of_registers, 874 const F* fpu_registers, 875 size_t number_of_fpu_registers, 876 PointerSize pointer_size) 877 : registers_(registers), 878 number_of_registers_(number_of_registers), 879 fpu_registers_(fpu_registers), 880 number_of_fpu_registers_(number_of_fpu_registers), 881 pointer_size_(pointer_size) {} 882 GetNumberOfRegisters()883 size_t GetNumberOfRegisters() const { return number_of_registers_; } GetNumberOfFpuRegisters()884 size_t GetNumberOfFpuRegisters() const { return number_of_fpu_registers_; } 885 GetRegisterAt(size_t index)886 C GetRegisterAt(size_t index) const { 887 DCHECK_LT(index, number_of_registers_); 888 return registers_[index]; 889 } 890 GetFpuRegisterAt(size_t index)891 F GetFpuRegisterAt(size_t index) const { 892 DCHECK_LT(index, number_of_fpu_registers_); 893 return fpu_registers_[index]; 894 } 895 GetStackOffsetOf(size_t index)896 size_t GetStackOffsetOf(size_t index) const { 897 // We still reserve the space for parameters passed by registers. 898 // Add space for the method pointer. 899 return static_cast<size_t>(pointer_size_) + index * kVRegSize; 900 } 901 902 private: 903 const C* registers_; 904 const size_t number_of_registers_; 905 const F* fpu_registers_; 906 const size_t number_of_fpu_registers_; 907 const PointerSize pointer_size_; 908 909 DISALLOW_COPY_AND_ASSIGN(CallingConvention); 910 }; 911 912 /** 913 * A templated class SlowPathGenerator with a templated method NewSlowPath() 914 * that can be used by any code generator to share equivalent slow-paths with 915 * the objective of reducing generated code size. 916 * 917 * InstructionType: instruction that requires SlowPathCodeType 918 * SlowPathCodeType: subclass of SlowPathCode, with constructor SlowPathCodeType(InstructionType *) 919 */ 920 template <typename InstructionType> 921 class SlowPathGenerator { 922 static_assert(std::is_base_of<HInstruction, InstructionType>::value, 923 "InstructionType is not a subclass of art::HInstruction"); 924 925 public: SlowPathGenerator(HGraph * graph,CodeGenerator * codegen)926 SlowPathGenerator(HGraph* graph, CodeGenerator* codegen) 927 : graph_(graph), 928 codegen_(codegen), 929 slow_path_map_(std::less<uint32_t>(), 930 graph->GetAllocator()->Adapter(kArenaAllocSlowPaths)) {} 931 932 // Creates and adds a new slow-path, if needed, or returns existing one otherwise. 933 // Templating the method (rather than the whole class) on the slow-path type enables 934 // keeping this code at a generic, non architecture-specific place. 935 // 936 // NOTE: This approach assumes each InstructionType only generates one SlowPathCodeType. 937 // To relax this requirement, we would need some RTTI on the stored slow-paths, 938 // or template the class as a whole on SlowPathType. 939 template <typename SlowPathCodeType> NewSlowPath(InstructionType * instruction)940 SlowPathCodeType* NewSlowPath(InstructionType* instruction) { 941 static_assert(std::is_base_of<SlowPathCode, SlowPathCodeType>::value, 942 "SlowPathCodeType is not a subclass of art::SlowPathCode"); 943 static_assert(std::is_constructible<SlowPathCodeType, InstructionType*>::value, 944 "SlowPathCodeType is not constructible from InstructionType*"); 945 // Iterate over potential candidates for sharing. Currently, only same-typed 946 // slow-paths with exactly the same dex-pc are viable candidates. 947 // TODO: pass dex-pc/slow-path-type to run-time to allow even more sharing? 948 const uint32_t dex_pc = instruction->GetDexPc(); 949 auto iter = slow_path_map_.find(dex_pc); 950 if (iter != slow_path_map_.end()) { 951 const ArenaVector<std::pair<InstructionType*, SlowPathCode*>>& candidates = iter->second; 952 for (const auto& it : candidates) { 953 InstructionType* other_instruction = it.first; 954 SlowPathCodeType* other_slow_path = down_cast<SlowPathCodeType*>(it.second); 955 // Determine if the instructions allow for slow-path sharing. 956 if (HaveSameLiveRegisters(instruction, other_instruction) && 957 HaveSameStackMap(instruction, other_instruction)) { 958 // Can share: reuse existing one. 959 return other_slow_path; 960 } 961 } 962 } else { 963 // First time this dex-pc is seen. 964 iter = slow_path_map_.Put(dex_pc, 965 {{}, {graph_->GetAllocator()->Adapter(kArenaAllocSlowPaths)}}); 966 } 967 // Cannot share: create and add new slow-path for this particular dex-pc. 968 SlowPathCodeType* slow_path = 969 new (codegen_->GetScopedAllocator()) SlowPathCodeType(instruction); 970 iter->second.emplace_back(std::make_pair(instruction, slow_path)); 971 codegen_->AddSlowPath(slow_path); 972 return slow_path; 973 } 974 975 private: 976 // Tests if both instructions have same set of live physical registers. This ensures 977 // the slow-path has exactly the same preamble on saving these registers to stack. HaveSameLiveRegisters(const InstructionType * i1,const InstructionType * i2)978 bool HaveSameLiveRegisters(const InstructionType* i1, const InstructionType* i2) const { 979 const uint32_t core_spill = ~codegen_->GetCoreSpillMask(); 980 const uint32_t fpu_spill = ~codegen_->GetFpuSpillMask(); 981 RegisterSet* live1 = i1->GetLocations()->GetLiveRegisters(); 982 RegisterSet* live2 = i2->GetLocations()->GetLiveRegisters(); 983 return (((live1->GetCoreRegisters() & core_spill) == 984 (live2->GetCoreRegisters() & core_spill)) && 985 ((live1->GetFloatingPointRegisters() & fpu_spill) == 986 (live2->GetFloatingPointRegisters() & fpu_spill))); 987 } 988 989 // Tests if both instructions have the same stack map. This ensures the interpreter 990 // will find exactly the same dex-registers at the same entries. HaveSameStackMap(const InstructionType * i1,const InstructionType * i2)991 bool HaveSameStackMap(const InstructionType* i1, const InstructionType* i2) const { 992 DCHECK(i1->HasEnvironment()); 993 DCHECK(i2->HasEnvironment()); 994 // We conservatively test if the two instructions find exactly the same instructions 995 // and location in each dex-register. This guarantees they will have the same stack map. 996 HEnvironment* e1 = i1->GetEnvironment(); 997 HEnvironment* e2 = i2->GetEnvironment(); 998 if (e1->GetParent() != e2->GetParent() || e1->Size() != e2->Size()) { 999 return false; 1000 } 1001 for (size_t i = 0, sz = e1->Size(); i < sz; ++i) { 1002 if (e1->GetInstructionAt(i) != e2->GetInstructionAt(i) || 1003 !e1->GetLocationAt(i).Equals(e2->GetLocationAt(i))) { 1004 return false; 1005 } 1006 } 1007 return true; 1008 } 1009 1010 HGraph* const graph_; 1011 CodeGenerator* const codegen_; 1012 1013 // Map from dex-pc to vector of already existing instruction/slow-path pairs. 1014 ArenaSafeMap<uint32_t, ArenaVector<std::pair<InstructionType*, SlowPathCode*>>> slow_path_map_; 1015 1016 DISALLOW_COPY_AND_ASSIGN(SlowPathGenerator); 1017 }; 1018 1019 class InstructionCodeGenerator : public HGraphVisitor { 1020 public: InstructionCodeGenerator(HGraph * graph,CodeGenerator * codegen)1021 InstructionCodeGenerator(HGraph* graph, CodeGenerator* codegen) 1022 : HGraphVisitor(graph), 1023 deopt_slow_paths_(graph, codegen) {} 1024 1025 protected: 1026 // Add slow-path generator for each instruction/slow-path combination that desires sharing. 1027 // TODO: under current regime, only deopt sharing make sense; extend later. 1028 SlowPathGenerator<HDeoptimize> deopt_slow_paths_; 1029 }; 1030 1031 } // namespace art 1032 1033 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_ 1034