• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_X64_LITHIUM_CODEGEN_X64_H_
6 #define V8_CRANKSHAFT_X64_LITHIUM_CODEGEN_X64_H_
7 
8 
9 #include "src/ast/scopes.h"
10 #include "src/base/logging.h"
11 #include "src/crankshaft/lithium-codegen.h"
12 #include "src/crankshaft/x64/lithium-gap-resolver-x64.h"
13 #include "src/crankshaft/x64/lithium-x64.h"
14 #include "src/deoptimizer.h"
15 #include "src/safepoint-table.h"
16 #include "src/utils.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 // Forward declarations.
22 class LDeferredCode;
23 class SafepointGenerator;
24 
25 class LCodeGen: public LCodeGenBase {
26  public:
LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)27   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
28       : LCodeGenBase(chunk, assembler, info),
29         jump_table_(4, info->zone()),
30         scope_(info->scope()),
31         deferred_(8, info->zone()),
32         frame_is_built_(false),
33         safepoints_(info->zone()),
34         resolver_(this),
35         expected_safepoint_kind_(Safepoint::kSimple) {
36     PopulateDeoptimizationLiteralsWithInlinedFunctions();
37   }
38 
LookupDestination(int block_id)39   int LookupDestination(int block_id) const {
40     return chunk()->LookupDestination(block_id);
41   }
42 
IsNextEmittedBlock(int block_id)43   bool IsNextEmittedBlock(int block_id) const {
44     return LookupDestination(block_id) == GetNextEmittedBlock();
45   }
46 
NeedsEagerFrame()47   bool NeedsEagerFrame() const {
48     return GetStackSlotCount() > 0 ||
49         info()->is_non_deferred_calling() ||
50         !info()->IsStub() ||
51         info()->requires_frame();
52   }
NeedsDeferredFrame()53   bool NeedsDeferredFrame() const {
54     return !NeedsEagerFrame() && info()->is_deferred_calling();
55   }
56 
57   // Support for converting LOperands to assembler types.
58   Register ToRegister(LOperand* op) const;
59   XMMRegister ToDoubleRegister(LOperand* op) const;
60   bool IsInteger32Constant(LConstantOperand* op) const;
61   bool IsExternalConstant(LConstantOperand* op) const;
62   bool IsDehoistedKeyConstant(LConstantOperand* op) const;
63   bool IsSmiConstant(LConstantOperand* op) const;
64   int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
65   int32_t ToInteger32(LConstantOperand* op) const;
66   Smi* ToSmi(LConstantOperand* op) const;
67   double ToDouble(LConstantOperand* op) const;
68   ExternalReference ToExternalReference(LConstantOperand* op) const;
69   Handle<Object> ToHandle(LConstantOperand* op) const;
70   Operand ToOperand(LOperand* op) const;
71 
72   // Try to generate code for the entire chunk, but it may fail if the
73   // chunk contains constructs we cannot handle. Returns true if the
74   // code generation attempt succeeded.
75   bool GenerateCode();
76 
77   // Finish the code by setting stack height, safepoint, and bailout
78   // information on it.
79   void FinishCode(Handle<Code> code);
80 
81   // Deferred code support.
82   void DoDeferredNumberTagD(LNumberTagD* instr);
83 
84   enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
85   void DoDeferredNumberTagIU(LInstruction* instr,
86                              LOperand* value,
87                              LOperand* temp1,
88                              LOperand* temp2,
89                              IntegerSignedness signedness);
90 
91   void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
92   void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
93   void DoDeferredStackCheck(LStackCheck* instr);
94   void DoDeferredMaybeGrowElements(LMaybeGrowElements* instr);
95   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
96   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
97   void DoDeferredAllocate(LAllocate* instr);
98   void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
99   void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
100                                    Register object,
101                                    Register index);
102 
103 // Parallel move support.
104   void DoParallelMove(LParallelMove* move);
105   void DoGap(LGap* instr);
106 
107   // Emit frame translation commands for an environment.
108   void WriteTranslation(LEnvironment* environment, Translation* translation);
109 
110   // Declare methods that deal with the individual node types.
111 #define DECLARE_DO(type) void Do##type(L##type* node);
LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)112   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
113 #undef DECLARE_DO
114 
115  private:
116   LanguageMode language_mode() const { return info()->language_mode(); }
117 
chunk()118   LPlatformChunk* chunk() const { return chunk_; }
scope()119   Scope* scope() const { return scope_; }
graph()120   HGraph* graph() const { return chunk()->graph(); }
121 
double_scratch0()122   XMMRegister double_scratch0() const { return xmm0; }
123 
124   void EmitClassOfTest(Label* if_true,
125                        Label* if_false,
126                        Handle<String> class_name,
127                        Register input,
128                        Register temporary,
129                        Register scratch);
130 
GetStackSlotCount()131   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
132 
AddDeferredCode(LDeferredCode * code)133   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
134 
135 
136   void SaveCallerDoubles();
137   void RestoreCallerDoubles();
138 
139   // Code generation passes.  Returns true if code generation should
140   // continue.
141   void GenerateBodyInstructionPre(LInstruction* instr) override;
142   void GenerateBodyInstructionPost(LInstruction* instr) override;
143   bool GeneratePrologue();
144   bool GenerateDeferredCode();
145   bool GenerateJumpTable();
146   bool GenerateSafepointTable();
147 
148   // Generates the custom OSR entrypoint and sets the osr_pc_offset.
149   void GenerateOsrPrologue();
150 
151   enum SafepointMode {
152     RECORD_SIMPLE_SAFEPOINT,
153     RECORD_SAFEPOINT_WITH_REGISTERS
154   };
155 
156   void CallCodeGeneric(Handle<Code> code,
157                        RelocInfo::Mode mode,
158                        LInstruction* instr,
159                        SafepointMode safepoint_mode,
160                        int argc);
161 
162 
163   void CallCode(Handle<Code> code,
164                 RelocInfo::Mode mode,
165                 LInstruction* instr);
166 
167   void CallRuntime(const Runtime::Function* function,
168                    int num_arguments,
169                    LInstruction* instr,
170                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
171 
CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)172   void CallRuntime(Runtime::FunctionId id,
173                    int num_arguments,
174                    LInstruction* instr) {
175     const Runtime::Function* function = Runtime::FunctionForId(id);
176     CallRuntime(function, num_arguments, instr);
177   }
178 
CallRuntime(Runtime::FunctionId id,LInstruction * instr)179   void CallRuntime(Runtime::FunctionId id, LInstruction* instr) {
180     const Runtime::Function* function = Runtime::FunctionForId(id);
181     CallRuntime(function, function->nargs, instr);
182   }
183 
184   void CallRuntimeFromDeferred(Runtime::FunctionId id,
185                                int argc,
186                                LInstruction* instr,
187                                LOperand* context);
188 
189   void LoadContextFromDeferred(LOperand* context);
190 
191   // Generate a direct call to a known function.  Expects the function
192   // to be in rdi.
193   void CallKnownFunction(Handle<JSFunction> function,
194                          int formal_parameter_count, int arity,
195                          LInstruction* instr);
196 
197   void RecordSafepointWithLazyDeopt(LInstruction* instr,
198                                     SafepointMode safepoint_mode,
199                                     int argc);
200   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
201                                             Safepoint::DeoptMode mode);
202   void DeoptimizeIf(Condition cc, LInstruction* instr,
203                     Deoptimizer::DeoptReason deopt_reason,
204                     Deoptimizer::BailoutType bailout_type);
205   void DeoptimizeIf(Condition cc, LInstruction* instr,
206                     Deoptimizer::DeoptReason deopt_reason);
207 
DeoptEveryNTimes()208   bool DeoptEveryNTimes() {
209     return FLAG_deopt_every_n_times != 0 && !info()->IsStub();
210   }
211 
212   void AddToTranslation(LEnvironment* environment,
213                         Translation* translation,
214                         LOperand* op,
215                         bool is_tagged,
216                         bool is_uint32,
217                         int* object_index_pointer,
218                         int* dematerialized_index_pointer);
219 
220   Register ToRegister(int index) const;
221   XMMRegister ToDoubleRegister(int index) const;
222   Operand BuildFastArrayOperand(
223       LOperand* elements_pointer,
224       LOperand* key,
225       Representation key_representation,
226       ElementsKind elements_kind,
227       uint32_t base_offset);
228 
229   Operand BuildSeqStringOperand(Register string,
230                                 LOperand* index,
231                                 String::Encoding encoding);
232 
233   void EmitIntegerMathAbs(LMathAbs* instr);
234   void EmitSmiMathAbs(LMathAbs* instr);
235 
236   // Support for recording safepoint and position information.
237   void RecordSafepoint(LPointerMap* pointers,
238                        Safepoint::Kind kind,
239                        int arguments,
240                        Safepoint::DeoptMode mode);
241   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
242   void RecordSafepoint(Safepoint::DeoptMode mode);
243   void RecordSafepointWithRegisters(LPointerMap* pointers,
244                                     int arguments,
245                                     Safepoint::DeoptMode mode);
246   void RecordAndWritePosition(int position) override;
247 
248   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
249   void EmitGoto(int block);
250 
251   // EmitBranch expects to be the last instruction of a block.
252   template<class InstrType>
253   void EmitBranch(InstrType instr, Condition cc);
254   template <class InstrType>
255   void EmitTrueBranch(InstrType instr, Condition cc);
256   template <class InstrType>
257   void EmitFalseBranch(InstrType instr, Condition cc);
258   void EmitNumberUntagD(LNumberUntagD* instr, Register input,
259                         XMMRegister result, NumberUntagDMode mode);
260 
261   // Emits optimized code for typeof x == "y".  Modifies input register.
262   // Returns the condition on which a final split to
263   // true and false label should be made, to optimize fallthrough.
264   Condition EmitTypeofIs(LTypeofIsAndBranch* instr, Register input);
265 
266   // Emits optimized code for %_IsString(x).  Preserves input register.
267   // Returns the condition on which a final split to
268   // true and false label should be made, to optimize fallthrough.
269   Condition EmitIsString(Register input,
270                          Register temp1,
271                          Label* is_not_string,
272                          SmiCheck check_needed);
273 
274   // Emits code for pushing either a tagged constant, a (non-double)
275   // register, or a stack slot operand.
276   void EmitPushTaggedOperand(LOperand* operand);
277 
278   // Emits optimized code to deep-copy the contents of statically known
279   // object graphs (e.g. object literal boilerplate).
280   void EmitDeepCopy(Handle<JSObject> object,
281                     Register result,
282                     Register source,
283                     int* offset,
284                     AllocationSiteMode mode);
285 
286   void EnsureSpaceForLazyDeopt(int space_needed) override;
287   void DoLoadKeyedExternalArray(LLoadKeyed* instr);
288   void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
289   void DoLoadKeyedFixedArray(LLoadKeyed* instr);
290   void DoStoreKeyedExternalArray(LStoreKeyed* instr);
291   void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
292   void DoStoreKeyedFixedArray(LStoreKeyed* instr);
293 
294   template <class T>
295   void EmitVectorLoadICRegisters(T* instr);
296   template <class T>
297   void EmitVectorStoreICRegisters(T* instr);
298 
299 #ifdef _MSC_VER
300   // On windows, you may not access the stack more than one page below
301   // the most recently mapped page. To make the allocated area randomly
302   // accessible, we write an arbitrary value to each page in range
303   // rsp + offset - page_size .. rsp in turn.
304   void MakeSureStackPagesMapped(int offset);
305 #endif
306 
307   ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
308   Scope* const scope_;
309   ZoneList<LDeferredCode*> deferred_;
310   bool frame_is_built_;
311 
312   // Builder that keeps track of safepoints in the code. The table
313   // itself is emitted at the end of the generated code.
314   SafepointTableBuilder safepoints_;
315 
316   // Compiler from a set of parallel moves to a sequential list of moves.
317   LGapResolver resolver_;
318 
319   Safepoint::Kind expected_safepoint_kind_;
320 
321   class PushSafepointRegistersScope final BASE_EMBEDDED {
322    public:
PushSafepointRegistersScope(LCodeGen * codegen)323     explicit PushSafepointRegistersScope(LCodeGen* codegen)
324         : codegen_(codegen) {
325       DCHECK(codegen_->info()->is_calling());
326       DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
327       codegen_->masm_->PushSafepointRegisters();
328       codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
329     }
330 
~PushSafepointRegistersScope()331     ~PushSafepointRegistersScope() {
332       DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
333       codegen_->masm_->PopSafepointRegisters();
334       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
335     }
336 
337    private:
338     LCodeGen* codegen_;
339   };
340 
341   friend class LDeferredCode;
342   friend class LEnvironment;
343   friend class SafepointGenerator;
344   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
345 };
346 
347 
348 class LDeferredCode: public ZoneObject {
349  public:
LDeferredCode(LCodeGen * codegen)350   explicit LDeferredCode(LCodeGen* codegen)
351       : codegen_(codegen),
352         external_exit_(NULL),
353         instruction_index_(codegen->current_instruction_) {
354     codegen->AddDeferredCode(this);
355   }
356 
~LDeferredCode()357   virtual ~LDeferredCode() {}
358   virtual void Generate() = 0;
359   virtual LInstruction* instr() = 0;
360 
SetExit(Label * exit)361   void SetExit(Label* exit) { external_exit_ = exit; }
entry()362   Label* entry() { return &entry_; }
exit()363   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
done()364   Label* done() { return codegen_->NeedsDeferredFrame() ? &done_ : exit(); }
instruction_index()365   int instruction_index() const { return instruction_index_; }
366 
367  protected:
codegen()368   LCodeGen* codegen() const { return codegen_; }
masm()369   MacroAssembler* masm() const { return codegen_->masm(); }
370 
371  private:
372   LCodeGen* codegen_;
373   Label entry_;
374   Label exit_;
375   Label done_;
376   Label* external_exit_;
377   int instruction_index_;
378 };
379 
380 }  // namespace internal
381 }  // namespace v8
382 
383 #endif  // V8_CRANKSHAFT_X64_LITHIUM_CODEGEN_X64_H_
384