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