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