1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_ 6 #define V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_ 7 8 #include "src/ast/scopes.h" 9 #include "src/crankshaft/lithium-codegen.h" 10 #include "src/crankshaft/mips64/lithium-gap-resolver-mips64.h" 11 #include "src/crankshaft/mips64/lithium-mips64.h" 12 #include "src/deoptimizer.h" 13 #include "src/safepoint-table.h" 14 #include "src/utils.h" 15 16 namespace v8 { 17 namespace internal { 18 19 // Forward declarations. 20 class LDeferredCode; 21 class SafepointGenerator; 22 23 class LCodeGen: public LCodeGenBase { 24 public: 25 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 26 : LCodeGenBase(chunk, assembler, info), 27 jump_table_(4, info->zone()), 28 scope_(info->scope()), 29 deferred_(8, info->zone()), 30 frame_is_built_(false), 31 safepoints_(info->zone()), 32 resolver_(this), 33 expected_safepoint_kind_(Safepoint::kSimple) { 34 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 35 } 36 37 38 int LookupDestination(int block_id) const { 39 return chunk()->LookupDestination(block_id); 40 } 41 42 bool IsNextEmittedBlock(int block_id) const { 43 return LookupDestination(block_id) == GetNextEmittedBlock(); 44 } 45 46 bool NeedsEagerFrame() const { 47 return GetStackSlotCount() > 0 || 48 info()->is_non_deferred_calling() || 49 !info()->IsStub() || 50 info()->requires_frame(); 51 } 52 bool NeedsDeferredFrame() const { 53 return !NeedsEagerFrame() && info()->is_deferred_calling(); 54 } 55 56 RAStatus GetRAState() const { 57 return frame_is_built_ ? kRAHasBeenSaved : kRAHasNotBeenSaved; 58 } 59 60 // Support for converting LOperands to assembler types. 61 // LOperand must be a register. 62 Register ToRegister(LOperand* op) const; 63 64 // LOperand is loaded into scratch, unless already a register. 65 Register EmitLoadRegister(LOperand* op, Register scratch); 66 67 // LOperand must be a double register. 68 DoubleRegister ToDoubleRegister(LOperand* op) const; 69 70 // LOperand is loaded into dbl_scratch, unless already a double register. 71 DoubleRegister EmitLoadDoubleRegister(LOperand* op, 72 FloatRegister flt_scratch, 73 DoubleRegister dbl_scratch); 74 int64_t ToRepresentation_donotuse(LConstantOperand* op, 75 const Representation& r) const; 76 int32_t ToInteger32(LConstantOperand* op) const; 77 Smi* ToSmi(LConstantOperand* op) const; 78 double ToDouble(LConstantOperand* op) const; 79 Operand ToOperand(LOperand* op); 80 MemOperand ToMemOperand(LOperand* op) const; 81 // Returns a MemOperand pointing to the high word of a DoubleStackSlot. 82 MemOperand ToHighMemOperand(LOperand* op) const; 83 84 bool IsInteger32(LConstantOperand* op) const; 85 bool IsSmi(LConstantOperand* op) const; 86 Handle<Object> ToHandle(LConstantOperand* op) const; 87 88 // Try to generate code for the entire chunk, but it may fail if the 89 // chunk contains constructs we cannot handle. Returns true if the 90 // code generation attempt succeeded. 91 bool GenerateCode(); 92 93 // Finish the code by setting stack height, safepoint, and bailout 94 // information on it. 95 void FinishCode(Handle<Code> code); 96 97 void DoDeferredNumberTagD(LNumberTagD* instr); 98 99 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; 100 void DoDeferredNumberTagIU(LInstruction* instr, 101 LOperand* value, 102 LOperand* temp1, 103 LOperand* temp2, 104 IntegerSignedness signedness); 105 106 void DoDeferredTaggedToI(LTaggedToI* instr); 107 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 108 void DoDeferredStackCheck(LStackCheck* instr); 109 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr); 110 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 111 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 112 void DoDeferredAllocate(LAllocate* instr); 113 114 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 115 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, 116 Register result, 117 Register object, 118 Register index); 119 120 // Parallel move support. 121 void DoParallelMove(LParallelMove* move); 122 void DoGap(LGap* instr); 123 124 MemOperand PrepareKeyedOperand(Register key, 125 Register base, 126 bool key_is_constant, 127 int constant_key, 128 int element_size, 129 int shift_size, 130 int base_offset); 131 132 // Emit frame translation commands for an environment. 133 void WriteTranslation(LEnvironment* environment, Translation* translation); 134 135 // Declare methods that deal with the individual node types. 136 #define DECLARE_DO(type) void Do##type(L##type* node); 137 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 138 #undef DECLARE_DO 139 140 private: 141 LanguageMode language_mode() const { return info()->language_mode(); } 142 143 Scope* scope() const { return scope_; } 144 145 Register scratch0() { return kLithiumScratchReg; } 146 Register scratch1() { return kLithiumScratchReg2; } 147 DoubleRegister double_scratch0() { return kLithiumScratchDouble; } 148 149 LInstruction* GetNextInstruction(); 150 151 void EmitClassOfTest(Label* if_true, 152 Label* if_false, 153 Handle<String> class_name, 154 Register input, 155 Register temporary, 156 Register temporary2); 157 158 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 159 160 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 161 162 void SaveCallerDoubles(); 163 void RestoreCallerDoubles(); 164 165 // Code generation passes. Returns true if code generation should 166 // continue. 167 void GenerateBodyInstructionPre(LInstruction* instr) override; 168 bool GeneratePrologue(); 169 bool GenerateDeferredCode(); 170 bool GenerateJumpTable(); 171 bool GenerateSafepointTable(); 172 173 // Generates the custom OSR entrypoint and sets the osr_pc_offset. 174 void GenerateOsrPrologue(); 175 176 enum SafepointMode { 177 RECORD_SIMPLE_SAFEPOINT, 178 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 179 }; 180 181 void CallCode(Handle<Code> code, 182 RelocInfo::Mode mode, 183 LInstruction* instr); 184 185 void CallCodeGeneric(Handle<Code> code, 186 RelocInfo::Mode mode, 187 LInstruction* instr, 188 SafepointMode safepoint_mode); 189 190 void CallRuntime(const Runtime::Function* function, 191 int num_arguments, 192 LInstruction* instr, 193 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 194 195 void CallRuntime(Runtime::FunctionId id, 196 int num_arguments, 197 LInstruction* instr) { 198 const Runtime::Function* function = Runtime::FunctionForId(id); 199 CallRuntime(function, num_arguments, instr); 200 } 201 202 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) { 203 const Runtime::Function* function = Runtime::FunctionForId(id); 204 CallRuntime(function, function->nargs, instr); 205 } 206 207 void LoadContextFromDeferred(LOperand* context); 208 void CallRuntimeFromDeferred(Runtime::FunctionId id, 209 int argc, 210 LInstruction* instr, 211 LOperand* context); 212 213 // Generate a direct call to a known function. Expects the function 214 // to be in a1. 215 void CallKnownFunction(Handle<JSFunction> function, 216 int formal_parameter_count, int arity, 217 LInstruction* instr); 218 219 void RecordSafepointWithLazyDeopt(LInstruction* instr, 220 SafepointMode safepoint_mode); 221 222 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 223 Safepoint::DeoptMode mode); 224 void DeoptimizeIf(Condition condition, LInstruction* instr, 225 Deoptimizer::DeoptReason deopt_reason, 226 Deoptimizer::BailoutType bailout_type, 227 Register src1 = zero_reg, 228 const Operand& src2 = Operand(zero_reg)); 229 void DeoptimizeIf( 230 Condition condition, LInstruction* instr, 231 Deoptimizer::DeoptReason deopt_reason = Deoptimizer::kNoReason, 232 Register src1 = zero_reg, const Operand& src2 = Operand(zero_reg)); 233 234 void AddToTranslation(LEnvironment* environment, 235 Translation* translation, 236 LOperand* op, 237 bool is_tagged, 238 bool is_uint32, 239 int* object_index_pointer, 240 int* dematerialized_index_pointer); 241 242 Register ToRegister(int index) const; 243 DoubleRegister ToDoubleRegister(int index) const; 244 245 MemOperand BuildSeqStringOperand(Register string, 246 LOperand* index, 247 String::Encoding encoding); 248 249 void EmitIntegerMathAbs(LMathAbs* instr); 250 void EmitSmiMathAbs(LMathAbs* instr); 251 252 // Support for recording safepoint and position information. 253 void RecordSafepoint(LPointerMap* pointers, 254 Safepoint::Kind kind, 255 int arguments, 256 Safepoint::DeoptMode mode); 257 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 258 void RecordSafepoint(Safepoint::DeoptMode mode); 259 void RecordSafepointWithRegisters(LPointerMap* pointers, 260 int arguments, 261 Safepoint::DeoptMode mode); 262 263 void RecordAndWritePosition(int position) override; 264 265 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 266 void EmitGoto(int block); 267 268 // EmitBranch expects to be the last instruction of a block. 269 template<class InstrType> 270 void EmitBranch(InstrType instr, 271 Condition condition, 272 Register src1, 273 const Operand& src2); 274 template<class InstrType> 275 void EmitBranchF(InstrType instr, 276 Condition condition, 277 FPURegister src1, 278 FPURegister src2); 279 template <class InstrType> 280 void EmitTrueBranch(InstrType instr, Condition condition, Register src1, 281 const Operand& src2); 282 template <class InstrType> 283 void EmitFalseBranch(InstrType instr, Condition condition, Register src1, 284 const Operand& src2); 285 template<class InstrType> 286 void EmitFalseBranchF(InstrType instr, 287 Condition condition, 288 FPURegister src1, 289 FPURegister src2); 290 void EmitCmpI(LOperand* left, LOperand* right); 291 void EmitNumberUntagD(LNumberUntagD* instr, Register input, 292 DoubleRegister result, NumberUntagDMode mode); 293 294 // Emits optimized code for typeof x == "y". Modifies input register. 295 // Returns the condition on which a final split to 296 // true and false label should be made, to optimize fallthrough. 297 // Returns two registers in cmp1 and cmp2 that can be used in the 298 // Branch instruction after EmitTypeofIs. 299 Condition EmitTypeofIs(Label* true_label, 300 Label* false_label, 301 Register input, 302 Handle<String> type_name, 303 Register* cmp1, 304 Operand* cmp2); 305 306 // Emits optimized code for %_IsString(x). Preserves input register. 307 // Returns the condition on which a final split to 308 // true and false label should be made, to optimize fallthrough. 309 Condition EmitIsString(Register input, 310 Register temp1, 311 Label* is_not_string, 312 SmiCheck check_needed); 313 314 // Emits optimized code to deep-copy the contents of statically known 315 // object graphs (e.g. object literal boilerplate). 316 void EmitDeepCopy(Handle<JSObject> object, 317 Register result, 318 Register source, 319 int* offset, 320 AllocationSiteMode mode); 321 // Emit optimized code for integer division. 322 // Inputs are signed. 323 // All registers are clobbered. 324 // If 'remainder' is no_reg, it is not computed. 325 void EmitSignedIntegerDivisionByConstant(Register result, 326 Register dividend, 327 int32_t divisor, 328 Register remainder, 329 Register scratch, 330 LEnvironment* environment); 331 332 333 void EnsureSpaceForLazyDeopt(int space_needed) override; 334 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 335 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 336 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 337 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 338 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 339 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 340 341 template <class T> 342 void EmitVectorLoadICRegisters(T* instr); 343 template <class T> 344 void EmitVectorStoreICRegisters(T* instr); 345 346 ZoneList<Deoptimizer::JumpTableEntry*> jump_table_; 347 Scope* const scope_; 348 ZoneList<LDeferredCode*> deferred_; 349 bool frame_is_built_; 350 351 // Builder that keeps track of safepoints in the code. The table 352 // itself is emitted at the end of the generated code. 353 SafepointTableBuilder safepoints_; 354 355 // Compiler from a set of parallel moves to a sequential list of moves. 356 LGapResolver resolver_; 357 358 Safepoint::Kind expected_safepoint_kind_; 359 360 class PushSafepointRegistersScope final BASE_EMBEDDED { 361 public: 362 explicit PushSafepointRegistersScope(LCodeGen* codegen) 363 : codegen_(codegen) { 364 DCHECK(codegen_->info()->is_calling()); 365 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 366 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 367 368 StoreRegistersStateStub stub(codegen_->isolate()); 369 codegen_->masm_->push(ra); 370 codegen_->masm_->CallStub(&stub); 371 } 372 373 ~PushSafepointRegistersScope() { 374 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 375 RestoreRegistersStateStub stub(codegen_->isolate()); 376 codegen_->masm_->push(ra); 377 codegen_->masm_->CallStub(&stub); 378 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 379 } 380 381 private: 382 LCodeGen* codegen_; 383 }; 384 385 friend class LDeferredCode; 386 friend class LEnvironment; 387 friend class SafepointGenerator; 388 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 389 }; 390 391 392 class LDeferredCode : public ZoneObject { 393 public: 394 explicit LDeferredCode(LCodeGen* codegen) 395 : codegen_(codegen), 396 external_exit_(NULL), 397 instruction_index_(codegen->current_instruction_) { 398 codegen->AddDeferredCode(this); 399 } 400 401 virtual ~LDeferredCode() {} 402 virtual void Generate() = 0; 403 virtual LInstruction* instr() = 0; 404 405 void SetExit(Label* exit) { external_exit_ = exit; } 406 Label* entry() { return &entry_; } 407 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } 408 int instruction_index() const { return instruction_index_; } 409 410 protected: 411 LCodeGen* codegen() const { return codegen_; } 412 MacroAssembler* masm() const { return codegen_->masm(); } 413 414 private: 415 LCodeGen* codegen_; 416 Label entry_; 417 Label exit_; 418 Label* external_exit_; 419 int instruction_index_; 420 }; 421 422 } // namespace internal 423 } // namespace v8 424 425 #endif // V8_CRANKSHAFT_MIPS64_LITHIUM_CODEGEN_MIPS_H_ 426