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