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_X87_LITHIUM_CODEGEN_X87_H_ 6 #define V8_CRANKSHAFT_X87_LITHIUM_CODEGEN_X87_H_ 7 8 #include <map> 9 10 #include "src/ast/scopes.h" 11 #include "src/base/logging.h" 12 #include "src/crankshaft/lithium-codegen.h" 13 #include "src/crankshaft/x87/lithium-gap-resolver-x87.h" 14 #include "src/crankshaft/x87/lithium-x87.h" 15 #include "src/deoptimizer.h" 16 #include "src/safepoint-table.h" 17 #include "src/utils.h" 18 19 namespace v8 { 20 namespace internal { 21 22 // Forward declarations. 23 class LDeferredCode; 24 class LGapNode; 25 class SafepointGenerator; 26 27 class LCodeGen: public LCodeGenBase { 28 public: 29 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) 30 : LCodeGenBase(chunk, assembler, info), 31 jump_table_(4, info->zone()), 32 scope_(info->scope()), 33 deferred_(8, info->zone()), 34 dynamic_frame_alignment_(false), 35 support_aligned_spilled_doubles_(false), 36 frame_is_built_(false), 37 x87_stack_(assembler), 38 safepoints_(info->zone()), 39 resolver_(this), 40 expected_safepoint_kind_(Safepoint::kSimple) { 41 PopulateDeoptimizationLiteralsWithInlinedFunctions(); 42 } 43 44 int LookupDestination(int block_id) const { 45 return chunk()->LookupDestination(block_id); 46 } 47 48 bool IsNextEmittedBlock(int block_id) const { 49 return LookupDestination(block_id) == GetNextEmittedBlock(); 50 } 51 52 bool NeedsEagerFrame() const { 53 return GetStackSlotCount() > 0 || 54 info()->is_non_deferred_calling() || 55 !info()->IsStub() || 56 info()->requires_frame(); 57 } 58 bool NeedsDeferredFrame() const { 59 return !NeedsEagerFrame() && info()->is_deferred_calling(); 60 } 61 62 // Support for converting LOperands to assembler types. 63 Operand ToOperand(LOperand* op) const; 64 Register ToRegister(LOperand* op) const; 65 X87Register ToX87Register(LOperand* op) const; 66 67 bool IsInteger32(LConstantOperand* op) const; 68 bool IsSmi(LConstantOperand* op) const; 69 Immediate ToImmediate(LOperand* op, const Representation& r) const { 70 return Immediate(ToRepresentation(LConstantOperand::cast(op), r)); 71 } 72 double ToDouble(LConstantOperand* op) const; 73 74 // Support for non-sse2 (x87) floating point stack handling. 75 // These functions maintain the mapping of physical stack registers to our 76 // virtual registers between instructions. 77 enum X87OperandType { kX87DoubleOperand, kX87FloatOperand, kX87IntOperand }; 78 79 void X87Mov(X87Register reg, Operand src, 80 X87OperandType operand = kX87DoubleOperand); 81 void X87Mov(Operand src, X87Register reg, 82 X87OperandType operand = kX87DoubleOperand); 83 void X87Mov(X87Register reg, X87Register src, 84 X87OperandType operand = kX87DoubleOperand); 85 86 void X87PrepareBinaryOp( 87 X87Register left, X87Register right, X87Register result); 88 89 void X87LoadForUsage(X87Register reg); 90 void X87LoadForUsage(X87Register reg1, X87Register reg2); 91 void X87PrepareToWrite(X87Register reg) { x87_stack_.PrepareToWrite(reg); } 92 void X87CommitWrite(X87Register reg) { x87_stack_.CommitWrite(reg); } 93 94 void X87Fxch(X87Register reg, int other_slot = 0) { 95 x87_stack_.Fxch(reg, other_slot); 96 } 97 void X87Free(X87Register reg) { 98 x87_stack_.Free(reg); 99 } 100 101 102 bool X87StackEmpty() { 103 return x87_stack_.depth() == 0; 104 } 105 106 Handle<Object> ToHandle(LConstantOperand* op) const; 107 108 // The operand denoting the second word (the one with a higher address) of 109 // a double stack slot. 110 Operand HighOperand(LOperand* op); 111 112 // Try to generate code for the entire chunk, but it may fail if the 113 // chunk contains constructs we cannot handle. Returns true if the 114 // code generation attempt succeeded. 115 bool GenerateCode(); 116 117 // Finish the code by setting stack height, safepoint, and bailout 118 // information on it. 119 void FinishCode(Handle<Code> code); 120 121 // Deferred code support. 122 void DoDeferredNumberTagD(LNumberTagD* instr); 123 124 enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 }; 125 void DoDeferredNumberTagIU(LInstruction* instr, 126 LOperand* value, 127 LOperand* temp, 128 IntegerSignedness signedness); 129 130 void DoDeferredTaggedToI(LTaggedToI* instr, Label* done); 131 void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); 132 void DoDeferredStackCheck(LStackCheck* instr); 133 void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr); 134 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); 135 void DoDeferredStringCharFromCode(LStringCharFromCode* instr); 136 void DoDeferredAllocate(LAllocate* instr); 137 void DoDeferredInstanceMigration(LCheckMaps* instr, Register object); 138 void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, 139 Register object, 140 Register index); 141 142 // Parallel move support. 143 void DoParallelMove(LParallelMove* move); 144 void DoGap(LGap* instr); 145 146 // Emit frame translation commands for an environment. 147 void WriteTranslation(LEnvironment* environment, Translation* translation); 148 149 void EnsureRelocSpaceForDeoptimization(); 150 151 // Declare methods that deal with the individual node types. 152 #define DECLARE_DO(type) void Do##type(L##type* node); 153 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO) 154 #undef DECLARE_DO 155 156 private: 157 LanguageMode language_mode() const { return info()->language_mode(); } 158 159 Scope* scope() const { return scope_; } 160 161 void EmitClassOfTest(Label* if_true, 162 Label* if_false, 163 Handle<String> class_name, 164 Register input, 165 Register temporary, 166 Register temporary2); 167 168 int GetStackSlotCount() const { return chunk()->spill_slot_count(); } 169 170 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); } 171 172 // Code generation passes. Returns true if code generation should 173 // continue. 174 void GenerateBodyInstructionPre(LInstruction* instr) override; 175 void GenerateBodyInstructionPost(LInstruction* instr) override; 176 bool GeneratePrologue(); 177 bool GenerateDeferredCode(); 178 bool GenerateJumpTable(); 179 bool GenerateSafepointTable(); 180 181 // Generates the custom OSR entrypoint and sets the osr_pc_offset. 182 void GenerateOsrPrologue(); 183 184 enum SafepointMode { 185 RECORD_SIMPLE_SAFEPOINT, 186 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS 187 }; 188 189 void CallCode(Handle<Code> code, 190 RelocInfo::Mode mode, 191 LInstruction* instr); 192 193 void CallCodeGeneric(Handle<Code> code, 194 RelocInfo::Mode mode, 195 LInstruction* instr, 196 SafepointMode safepoint_mode); 197 198 void CallRuntime(const Runtime::Function* fun, int argc, LInstruction* instr, 199 SaveFPRegsMode save_doubles = kDontSaveFPRegs); 200 201 void CallRuntime(Runtime::FunctionId id, 202 int argc, 203 LInstruction* instr) { 204 const Runtime::Function* function = Runtime::FunctionForId(id); 205 CallRuntime(function, argc, instr); 206 } 207 208 void CallRuntime(Runtime::FunctionId id, LInstruction* instr) { 209 const Runtime::Function* function = Runtime::FunctionForId(id); 210 CallRuntime(function, function->nargs, instr); 211 } 212 213 void CallRuntimeFromDeferred(Runtime::FunctionId id, 214 int argc, 215 LInstruction* instr, 216 LOperand* context); 217 218 void LoadContextFromDeferred(LOperand* context); 219 220 // Generate a direct call to a known function. Expects the function 221 // to be in edi. 222 void CallKnownFunction(Handle<JSFunction> function, 223 int formal_parameter_count, int arity, 224 LInstruction* instr); 225 226 void RecordSafepointWithLazyDeopt(LInstruction* instr, 227 SafepointMode safepoint_mode); 228 229 void RegisterEnvironmentForDeoptimization(LEnvironment* environment, 230 Safepoint::DeoptMode mode); 231 void DeoptimizeIf(Condition cc, LInstruction* instr, 232 Deoptimizer::DeoptReason deopt_reason, 233 Deoptimizer::BailoutType bailout_type); 234 void DeoptimizeIf(Condition cc, LInstruction* instr, 235 Deoptimizer::DeoptReason deopt_reason); 236 237 bool DeoptEveryNTimes() { 238 return FLAG_deopt_every_n_times != 0 && !info()->IsStub(); 239 } 240 241 void AddToTranslation(LEnvironment* environment, 242 Translation* translation, 243 LOperand* op, 244 bool is_tagged, 245 bool is_uint32, 246 int* object_index_pointer, 247 int* dematerialized_index_pointer); 248 249 Register ToRegister(int index) const; 250 X87Register ToX87Register(int index) const; 251 int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const; 252 int32_t ToInteger32(LConstantOperand* op) const; 253 ExternalReference ToExternalReference(LConstantOperand* op) const; 254 255 Operand BuildFastArrayOperand(LOperand* elements_pointer, 256 LOperand* key, 257 Representation key_representation, 258 ElementsKind elements_kind, 259 uint32_t base_offset); 260 261 Operand BuildSeqStringOperand(Register string, 262 LOperand* index, 263 String::Encoding encoding); 264 265 void EmitIntegerMathAbs(LMathAbs* instr); 266 267 // Support for recording safepoint and position information. 268 void RecordSafepoint(LPointerMap* pointers, 269 Safepoint::Kind kind, 270 int arguments, 271 Safepoint::DeoptMode mode); 272 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode); 273 void RecordSafepoint(Safepoint::DeoptMode mode); 274 void RecordSafepointWithRegisters(LPointerMap* pointers, 275 int arguments, 276 Safepoint::DeoptMode mode); 277 278 void RecordAndWritePosition(int position) override; 279 280 static Condition TokenToCondition(Token::Value op, bool is_unsigned); 281 void EmitGoto(int block); 282 283 // EmitBranch expects to be the last instruction of a block. 284 template<class InstrType> 285 void EmitBranch(InstrType instr, Condition cc); 286 template <class InstrType> 287 void EmitTrueBranch(InstrType instr, Condition cc); 288 template <class InstrType> 289 void EmitFalseBranch(InstrType instr, Condition cc); 290 void EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input, 291 Register temp, X87Register res_reg, 292 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 Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input); 298 299 // Emits optimized code for %_IsString(x). Preserves input register. 300 // Returns the condition on which a final split to 301 // true and false label should be made, to optimize fallthrough. 302 Condition EmitIsString(Register input, 303 Register temp1, 304 Label* is_not_string, 305 SmiCheck check_needed); 306 307 // Emits optimized code to deep-copy the contents of statically known 308 // object graphs (e.g. object literal boilerplate). 309 void EmitDeepCopy(Handle<JSObject> object, 310 Register result, 311 Register source, 312 int* offset, 313 AllocationSiteMode mode); 314 315 void EnsureSpaceForLazyDeopt(int space_needed) override; 316 void DoLoadKeyedExternalArray(LLoadKeyed* instr); 317 void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr); 318 void DoLoadKeyedFixedArray(LLoadKeyed* instr); 319 void DoStoreKeyedExternalArray(LStoreKeyed* instr); 320 void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr); 321 void DoStoreKeyedFixedArray(LStoreKeyed* instr); 322 323 template <class T> 324 void EmitVectorLoadICRegisters(T* instr); 325 template <class T> 326 void EmitVectorStoreICRegisters(T* instr); 327 328 void EmitReturn(LReturn* instr, bool dynamic_frame_alignment); 329 330 // Emits code for pushing either a tagged constant, a (non-double) 331 // register, or a stack slot operand. 332 void EmitPushTaggedOperand(LOperand* operand); 333 334 void X87Fld(Operand src, X87OperandType opts); 335 336 void EmitFlushX87ForDeopt(); 337 void FlushX87StackIfNecessary(LInstruction* instr) { 338 x87_stack_.FlushIfNecessary(instr, this); 339 } 340 friend class LGapResolver; 341 342 #ifdef _MSC_VER 343 // On windows, you may not access the stack more than one page below 344 // the most recently mapped page. To make the allocated area randomly 345 // accessible, we write an arbitrary value to each page in range 346 // esp + offset - page_size .. esp in turn. 347 void MakeSureStackPagesMapped(int offset); 348 #endif 349 350 ZoneList<Deoptimizer::JumpTableEntry> jump_table_; 351 Scope* const scope_; 352 ZoneList<LDeferredCode*> deferred_; 353 bool dynamic_frame_alignment_; 354 bool support_aligned_spilled_doubles_; 355 bool frame_is_built_; 356 357 class X87Stack : public ZoneObject { 358 public: 359 explicit X87Stack(MacroAssembler* masm) 360 : stack_depth_(0), is_mutable_(true), masm_(masm) { } 361 explicit X87Stack(const X87Stack& other) 362 : stack_depth_(other.stack_depth_), is_mutable_(false), masm_(masm()) { 363 for (int i = 0; i < stack_depth_; i++) { 364 stack_[i] = other.stack_[i]; 365 } 366 } 367 bool operator==(const X87Stack& other) const { 368 if (stack_depth_ != other.stack_depth_) return false; 369 for (int i = 0; i < stack_depth_; i++) { 370 if (!stack_[i].is(other.stack_[i])) return false; 371 } 372 return true; 373 } 374 X87Stack& operator=(const X87Stack& other) { 375 stack_depth_ = other.stack_depth_; 376 for (int i = 0; i < stack_depth_; i++) { 377 stack_[i] = other.stack_[i]; 378 } 379 return *this; 380 } 381 bool Contains(X87Register reg); 382 void Fxch(X87Register reg, int other_slot = 0); 383 void Free(X87Register reg); 384 void PrepareToWrite(X87Register reg); 385 void CommitWrite(X87Register reg); 386 void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen); 387 void LeavingBlock(int current_block_id, LGoto* goto_instr, LCodeGen* cgen); 388 int depth() const { return stack_depth_; } 389 int GetLayout(); 390 int st(X87Register reg) { return st2idx(ArrayIndex(reg)); } 391 void pop() { 392 DCHECK(is_mutable_); 393 USE(is_mutable_); 394 stack_depth_--; 395 } 396 void push(X87Register reg) { 397 DCHECK(is_mutable_); 398 DCHECK(stack_depth_ < X87Register::kMaxNumAllocatableRegisters); 399 stack_[stack_depth_] = reg; 400 stack_depth_++; 401 } 402 403 MacroAssembler* masm() const { return masm_; } 404 Isolate* isolate() const { return masm_->isolate(); } 405 406 private: 407 int ArrayIndex(X87Register reg); 408 int st2idx(int pos); 409 410 X87Register stack_[X87Register::kMaxNumAllocatableRegisters]; 411 int stack_depth_; 412 bool is_mutable_; 413 MacroAssembler* masm_; 414 }; 415 X87Stack x87_stack_; 416 // block_id -> X87Stack*; 417 typedef std::map<int, X87Stack*> X87StackMap; 418 X87StackMap x87_stack_map_; 419 420 // Builder that keeps track of safepoints in the code. The table 421 // itself is emitted at the end of the generated code. 422 SafepointTableBuilder safepoints_; 423 424 // Compiler from a set of parallel moves to a sequential list of moves. 425 LGapResolver resolver_; 426 427 Safepoint::Kind expected_safepoint_kind_; 428 429 class PushSafepointRegistersScope final BASE_EMBEDDED { 430 public: 431 explicit PushSafepointRegistersScope(LCodeGen* codegen) 432 : codegen_(codegen) { 433 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple); 434 codegen_->masm_->PushSafepointRegisters(); 435 codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters; 436 DCHECK(codegen_->info()->is_calling()); 437 } 438 439 ~PushSafepointRegistersScope() { 440 DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters); 441 codegen_->masm_->PopSafepointRegisters(); 442 codegen_->expected_safepoint_kind_ = Safepoint::kSimple; 443 } 444 445 private: 446 LCodeGen* codegen_; 447 }; 448 449 friend class LDeferredCode; 450 friend class LEnvironment; 451 friend class SafepointGenerator; 452 friend class X87Stack; 453 DISALLOW_COPY_AND_ASSIGN(LCodeGen); 454 }; 455 456 457 class LDeferredCode : public ZoneObject { 458 public: 459 explicit LDeferredCode(LCodeGen* codegen, const LCodeGen::X87Stack& x87_stack) 460 : codegen_(codegen), 461 external_exit_(NULL), 462 instruction_index_(codegen->current_instruction_), 463 x87_stack_(x87_stack) { 464 codegen->AddDeferredCode(this); 465 } 466 467 virtual ~LDeferredCode() {} 468 virtual void Generate() = 0; 469 virtual LInstruction* instr() = 0; 470 471 void SetExit(Label* exit) { external_exit_ = exit; } 472 Label* entry() { return &entry_; } 473 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; } 474 Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); } 475 int instruction_index() const { return instruction_index_; } 476 const LCodeGen::X87Stack& x87_stack() const { return x87_stack_; } 477 478 protected: 479 LCodeGen* codegen() const { return codegen_; } 480 MacroAssembler* masm() const { return codegen_->masm(); } 481 482 private: 483 LCodeGen* codegen_; 484 Label entry_; 485 Label exit_; 486 Label* external_exit_; 487 Label done_; 488 int instruction_index_; 489 LCodeGen::X87Stack x87_stack_; 490 }; 491 492 } // namespace internal 493 } // namespace v8 494 495 #endif // V8_CRANKSHAFT_X87_LITHIUM_CODEGEN_X87_H_ 496