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