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