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
19namespace v8 {
20namespace internal {
21
22// Forward declarations.
23class LDeferredCode;
24class LGapNode;
25class SafepointGenerator;
26
27class 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        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
42  int LookupDestination(int block_id) const {
43    return chunk()->LookupDestination(block_id);
44  }
45
46  bool IsNextEmittedBlock(int block_id) const {
47    return LookupDestination(block_id) == GetNextEmittedBlock();
48  }
49
50  bool NeedsEagerFrame() const {
51    return HasAllocatedStackSlots() || info()->is_non_deferred_calling() ||
52           !info()->IsStub() || info()->requires_frame();
53  }
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;
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);
87  void X87PrepareToWrite(X87Register reg) { x87_stack_.PrepareToWrite(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  }
93  void X87Free(X87Register reg) {
94    x87_stack_.Free(reg);
95  }
96
97
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);
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
162  bool HasAllocatedStackSlots() const {
163    return chunk()->HasAllocatedStackSlots();
164  }
165  int GetStackSlotCount() const { return chunk()->GetSpillSlotCount(); }
166  int GetTotalFrameSlotCount() const {
167    return chunk()->GetTotalFrameSlotCount();
168  }
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  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                    Deoptimizer::DeoptReason deopt_reason,
236                    Deoptimizer::BailoutType bailout_type);
237  void DeoptimizeIf(Condition cc, LInstruction* instr,
238                    Deoptimizer::DeoptReason deopt_reason);
239
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 and position 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  void RecordAndWritePosition(int position) override;
282
283  static Condition TokenToCondition(Token::Value op, bool is_unsigned);
284  void EmitGoto(int block);
285
286  // EmitBranch expects to be the last instruction of a block.
287  template<class InstrType>
288  void EmitBranch(InstrType instr, Condition cc);
289  template <class InstrType>
290  void EmitTrueBranch(InstrType instr, Condition cc);
291  template <class InstrType>
292  void EmitFalseBranch(InstrType instr, Condition cc);
293  void EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input,
294                              Register temp, X87Register res_reg,
295                              NumberUntagDMode mode);
296
297  // Emits optimized code for typeof x == "y".  Modifies input register.
298  // Returns the condition on which a final split to
299  // true and false label should be made, to optimize fallthrough.
300  Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
301
302  // Emits optimized code for %_IsString(x).  Preserves 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 EmitIsString(Register input,
306                         Register temp1,
307                         Label* is_not_string,
308                         SmiCheck check_needed);
309
310  // Emits optimized code to deep-copy the contents of statically known
311  // object graphs (e.g. object literal boilerplate).
312  void EmitDeepCopy(Handle<JSObject> object,
313                    Register result,
314                    Register source,
315                    int* offset,
316                    AllocationSiteMode mode);
317
318  void EnsureSpaceForLazyDeopt(int space_needed) override;
319  void DoLoadKeyedExternalArray(LLoadKeyed* instr);
320  void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
321  void DoLoadKeyedFixedArray(LLoadKeyed* instr);
322  void DoStoreKeyedExternalArray(LStoreKeyed* instr);
323  void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
324  void DoStoreKeyedFixedArray(LStoreKeyed* instr);
325
326  template <class T>
327  void EmitVectorLoadICRegisters(T* instr);
328  template <class T>
329  void EmitVectorStoreICRegisters(T* instr);
330
331  void EmitReturn(LReturn* instr);
332
333  // Emits code for pushing either a tagged constant, a (non-double)
334  // register, or a stack slot operand.
335  void EmitPushTaggedOperand(LOperand* operand);
336
337  void X87Fld(Operand src, X87OperandType opts);
338
339  void EmitFlushX87ForDeopt();
340  void FlushX87StackIfNecessary(LInstruction* instr) {
341    x87_stack_.FlushIfNecessary(instr, this);
342  }
343  friend class LGapResolver;
344
345#ifdef _MSC_VER
346  // On windows, you may not access the stack more than one page below
347  // the most recently mapped page. To make the allocated area randomly
348  // accessible, we write an arbitrary value to each page in range
349  // esp + offset - page_size .. esp in turn.
350  void MakeSureStackPagesMapped(int offset);
351#endif
352
353  ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
354  Scope* const scope_;
355  ZoneList<LDeferredCode*> deferred_;
356  bool frame_is_built_;
357
358  class X87Stack : public ZoneObject {
359   public:
360    explicit X87Stack(MacroAssembler* masm)
361        : stack_depth_(0), is_mutable_(true), masm_(masm) { }
362    explicit X87Stack(const X87Stack& other)
363        : stack_depth_(other.stack_depth_), is_mutable_(false), masm_(masm()) {
364      for (int i = 0; i < stack_depth_; i++) {
365        stack_[i] = other.stack_[i];
366      }
367    }
368    bool operator==(const X87Stack& other) const {
369      if (stack_depth_ != other.stack_depth_) return false;
370      for (int i = 0; i < stack_depth_; i++) {
371        if (!stack_[i].is(other.stack_[i])) return false;
372      }
373      return true;
374    }
375    X87Stack& operator=(const X87Stack& other) {
376      stack_depth_ = other.stack_depth_;
377      for (int i = 0; i < stack_depth_; i++) {
378        stack_[i] = other.stack_[i];
379      }
380      return *this;
381    }
382    bool Contains(X87Register reg);
383    void Fxch(X87Register reg, int other_slot = 0);
384    void Free(X87Register reg);
385    void PrepareToWrite(X87Register reg);
386    void CommitWrite(X87Register reg);
387    void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen);
388    void LeavingBlock(int current_block_id, LGoto* goto_instr, LCodeGen* cgen);
389    int depth() const { return stack_depth_; }
390    int GetLayout();
391    int st(X87Register reg) { return st2idx(ArrayIndex(reg)); }
392    void pop() {
393      DCHECK(is_mutable_);
394      USE(is_mutable_);
395      stack_depth_--;
396    }
397    void push(X87Register reg) {
398      DCHECK(is_mutable_);
399      DCHECK(stack_depth_ < X87Register::kMaxNumAllocatableRegisters);
400      stack_[stack_depth_] = reg;
401      stack_depth_++;
402    }
403
404    MacroAssembler* masm() const { return masm_; }
405    Isolate* isolate() const { return masm_->isolate(); }
406
407   private:
408    int ArrayIndex(X87Register reg);
409    int st2idx(int pos);
410
411    X87Register stack_[X87Register::kMaxNumAllocatableRegisters];
412    int stack_depth_;
413    bool is_mutable_;
414    MacroAssembler* masm_;
415  };
416  X87Stack x87_stack_;
417  // block_id -> X87Stack*;
418  typedef std::map<int, X87Stack*> X87StackMap;
419  X87StackMap x87_stack_map_;
420
421  // Builder that keeps track of safepoints in the code. The table
422  // itself is emitted at the end of the generated code.
423  SafepointTableBuilder safepoints_;
424
425  // Compiler from a set of parallel moves to a sequential list of moves.
426  LGapResolver resolver_;
427
428  Safepoint::Kind expected_safepoint_kind_;
429
430  class PushSafepointRegistersScope final BASE_EMBEDDED {
431   public:
432    explicit PushSafepointRegistersScope(LCodeGen* codegen)
433        : codegen_(codegen) {
434      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
435      codegen_->masm_->PushSafepointRegisters();
436      codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
437      DCHECK(codegen_->info()->is_calling());
438    }
439
440    ~PushSafepointRegistersScope() {
441      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
442      codegen_->masm_->PopSafepointRegisters();
443      codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
444    }
445
446   private:
447    LCodeGen* codegen_;
448  };
449
450  friend class LDeferredCode;
451  friend class LEnvironment;
452  friend class SafepointGenerator;
453  friend class X87Stack;
454  DISALLOW_COPY_AND_ASSIGN(LCodeGen);
455};
456
457
458class LDeferredCode : public ZoneObject {
459 public:
460  explicit LDeferredCode(LCodeGen* codegen, const LCodeGen::X87Stack& x87_stack)
461      : codegen_(codegen),
462        external_exit_(NULL),
463        instruction_index_(codegen->current_instruction_),
464        x87_stack_(x87_stack) {
465    codegen->AddDeferredCode(this);
466  }
467
468  virtual ~LDeferredCode() {}
469  virtual void Generate() = 0;
470  virtual LInstruction* instr() = 0;
471
472  void SetExit(Label* exit) { external_exit_ = exit; }
473  Label* entry() { return &entry_; }
474  Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
475  Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); }
476  int instruction_index() const { return instruction_index_; }
477  const LCodeGen::X87Stack& x87_stack() const { return x87_stack_; }
478
479 protected:
480  LCodeGen* codegen() const { return codegen_; }
481  MacroAssembler* masm() const { return codegen_->masm(); }
482
483 private:
484  LCodeGen* codegen_;
485  Label entry_;
486  Label exit_;
487  Label* external_exit_;
488  Label done_;
489  int instruction_index_;
490  LCodeGen::X87Stack x87_stack_;
491};
492
493}  // namespace internal
494}  // namespace v8
495
496#endif  // V8_CRANKSHAFT_X87_LITHIUM_CODEGEN_X87_H_
497