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