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