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