5251b85fa91e212e7832ab5b96821adedad09f6a
[platform/framework/web/crosswalk.git] / src / v8 / src / arm / lithium-codegen-arm.h
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #ifndef V8_ARM_LITHIUM_CODEGEN_ARM_H_
29 #define V8_ARM_LITHIUM_CODEGEN_ARM_H_
30
31 #include "arm/lithium-arm.h"
32
33 #include "arm/lithium-gap-resolver-arm.h"
34 #include "deoptimizer.h"
35 #include "lithium-codegen.h"
36 #include "safepoint-table.h"
37 #include "scopes.h"
38 #include "v8utils.h"
39
40 namespace v8 {
41 namespace internal {
42
43 // Forward declarations.
44 class LDeferredCode;
45 class SafepointGenerator;
46
47 class LCodeGen: public LCodeGenBase {
48  public:
49   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
50       : LCodeGenBase(chunk, assembler, info),
51         deoptimizations_(4, info->zone()),
52         deopt_jump_table_(4, info->zone()),
53         deoptimization_literals_(8, info->zone()),
54         inlined_function_count_(0),
55         scope_(info->scope()),
56         translations_(info->zone()),
57         deferred_(8, info->zone()),
58         osr_pc_offset_(-1),
59         frame_is_built_(false),
60         safepoints_(info->zone()),
61         resolver_(this),
62         expected_safepoint_kind_(Safepoint::kSimple) {
63     PopulateDeoptimizationLiteralsWithInlinedFunctions();
64   }
65
66
67   int LookupDestination(int block_id) const {
68     return chunk()->LookupDestination(block_id);
69   }
70
71   bool IsNextEmittedBlock(int block_id) const {
72     return LookupDestination(block_id) == GetNextEmittedBlock();
73   }
74
75   bool NeedsEagerFrame() const {
76     return GetStackSlotCount() > 0 ||
77         info()->is_non_deferred_calling() ||
78         !info()->IsStub() ||
79         info()->requires_frame();
80   }
81   bool NeedsDeferredFrame() const {
82     return !NeedsEagerFrame() && info()->is_deferred_calling();
83   }
84
85   LinkRegisterStatus GetLinkRegisterState() const {
86     return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved;
87   }
88
89   // Support for converting LOperands to assembler types.
90   // LOperand must be a register.
91   Register ToRegister(LOperand* op) const;
92
93   // LOperand is loaded into scratch, unless already a register.
94   Register EmitLoadRegister(LOperand* op, Register scratch);
95
96   // LOperand must be a double register.
97   DwVfpRegister ToDoubleRegister(LOperand* op) const;
98
99   // LOperand is loaded into dbl_scratch, unless already a double register.
100   DwVfpRegister EmitLoadDoubleRegister(LOperand* op,
101                                        SwVfpRegister flt_scratch,
102                                        DwVfpRegister dbl_scratch);
103   int32_t ToRepresentation(LConstantOperand* op, const Representation& r) const;
104   int32_t ToInteger32(LConstantOperand* op) const;
105   Smi* ToSmi(LConstantOperand* op) const;
106   double ToDouble(LConstantOperand* op) const;
107   Operand ToOperand(LOperand* op);
108   MemOperand ToMemOperand(LOperand* op) const;
109   // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
110   MemOperand ToHighMemOperand(LOperand* op) const;
111
112   bool IsInteger32(LConstantOperand* op) const;
113   bool IsSmi(LConstantOperand* op) const;
114   Handle<Object> ToHandle(LConstantOperand* op) const;
115
116   // Try to generate code for the entire chunk, but it may fail if the
117   // chunk contains constructs we cannot handle. Returns true if the
118   // code generation attempt succeeded.
119   bool GenerateCode();
120
121   // Finish the code by setting stack height, safepoint, and bailout
122   // information on it.
123   void FinishCode(Handle<Code> code);
124
125   // Deferred code support.
126   void DoDeferredNumberTagD(LNumberTagD* instr);
127
128   enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
129   void DoDeferredNumberTagI(LInstruction* instr,
130                             LOperand* value,
131                             IntegerSignedness signedness);
132
133   void DoDeferredTaggedToI(LTaggedToI* instr);
134   void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
135   void DoDeferredStackCheck(LStackCheck* instr);
136   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
137   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
138   void DoDeferredAllocate(LAllocate* instr);
139   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
140                                        Label* map_check);
141   void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
142
143   // Parallel move support.
144   void DoParallelMove(LParallelMove* move);
145   void DoGap(LGap* instr);
146
147   MemOperand PrepareKeyedOperand(Register key,
148                                  Register base,
149                                  bool key_is_constant,
150                                  int constant_key,
151                                  int element_size,
152                                  int shift_size,
153                                  int additional_index,
154                                  int additional_offset);
155
156   // Emit frame translation commands for an environment.
157   void WriteTranslation(LEnvironment* environment, Translation* translation);
158
159   // Declare methods that deal with the individual node types.
160 #define DECLARE_DO(type) void Do##type(L##type* node);
161   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
162 #undef DECLARE_DO
163
164  private:
165   StrictModeFlag strict_mode_flag() const {
166     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
167   }
168
169   Scope* scope() const { return scope_; }
170
171   Register scratch0() { return r9; }
172   LowDwVfpRegister double_scratch0() { return kScratchDoubleReg; }
173
174   LInstruction* GetNextInstruction();
175
176   void EmitClassOfTest(Label* if_true,
177                        Label* if_false,
178                        Handle<String> class_name,
179                        Register input,
180                        Register temporary,
181                        Register temporary2);
182
183   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
184
185   void Abort(BailoutReason reason);
186
187   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
188
189   void SaveCallerDoubles();
190   void RestoreCallerDoubles();
191
192   // Code generation passes.  Returns true if code generation should
193   // continue.
194   bool GeneratePrologue();
195   bool GenerateDeferredCode();
196   bool GenerateDeoptJumpTable();
197   bool GenerateSafepointTable();
198
199   // Generates the custom OSR entrypoint and sets the osr_pc_offset.
200   void GenerateOsrPrologue();
201
202   enum SafepointMode {
203     RECORD_SIMPLE_SAFEPOINT,
204     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
205   };
206
207   void CallCode(
208       Handle<Code> code,
209       RelocInfo::Mode mode,
210       LInstruction* instr,
211       TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS);
212
213   void CallCodeGeneric(
214       Handle<Code> code,
215       RelocInfo::Mode mode,
216       LInstruction* instr,
217       SafepointMode safepoint_mode,
218       TargetAddressStorageMode storage_mode = CAN_INLINE_TARGET_ADDRESS);
219
220   void CallRuntime(const Runtime::Function* function,
221                    int num_arguments,
222                    LInstruction* instr,
223                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
224
225   void CallRuntime(Runtime::FunctionId id,
226                    int num_arguments,
227                    LInstruction* instr) {
228     const Runtime::Function* function = Runtime::FunctionForId(id);
229     CallRuntime(function, num_arguments, instr);
230   }
231
232   void LoadContextFromDeferred(LOperand* context);
233   void CallRuntimeFromDeferred(Runtime::FunctionId id,
234                                int argc,
235                                LInstruction* instr,
236                                LOperand* context);
237
238   enum R1State {
239     R1_UNINITIALIZED,
240     R1_CONTAINS_TARGET
241   };
242
243   // Generate a direct call to a known function.  Expects the function
244   // to be in r1.
245   void CallKnownFunction(Handle<JSFunction> function,
246                          int formal_parameter_count,
247                          int arity,
248                          LInstruction* instr,
249                          R1State r1_state);
250
251   void RecordSafepointWithLazyDeopt(LInstruction* instr,
252                                     SafepointMode safepoint_mode);
253
254   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
255                                             Safepoint::DeoptMode mode);
256   void DeoptimizeIf(Condition condition,
257                     LEnvironment* environment,
258                     Deoptimizer::BailoutType bailout_type);
259   void DeoptimizeIf(Condition condition, LEnvironment* environment);
260   void ApplyCheckIf(Condition condition, LBoundsCheck* check);
261
262   void AddToTranslation(LEnvironment* environment,
263                         Translation* translation,
264                         LOperand* op,
265                         bool is_tagged,
266                         bool is_uint32,
267                         int* object_index_pointer,
268                         int* dematerialized_index_pointer);
269   void PopulateDeoptimizationData(Handle<Code> code);
270   int DefineDeoptimizationLiteral(Handle<Object> literal);
271
272   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
273
274   Register ToRegister(int index) const;
275   DwVfpRegister ToDoubleRegister(int index) const;
276
277   MemOperand BuildSeqStringOperand(Register string,
278                                    LOperand* index,
279                                    String::Encoding encoding);
280
281   void EmitIntegerMathAbs(LMathAbs* instr);
282
283   // Support for recording safepoint and position information.
284   void RecordSafepoint(LPointerMap* pointers,
285                        Safepoint::Kind kind,
286                        int arguments,
287                        Safepoint::DeoptMode mode);
288   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
289   void RecordSafepoint(Safepoint::DeoptMode mode);
290   void RecordSafepointWithRegisters(LPointerMap* pointers,
291                                     int arguments,
292                                     Safepoint::DeoptMode mode);
293   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
294                                               int arguments,
295                                               Safepoint::DeoptMode mode);
296
297   void RecordAndWritePosition(int position) V8_OVERRIDE;
298
299   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
300   void EmitGoto(int block);
301
302   // EmitBranch expects to be the last instruction of a block.
303   template<class InstrType>
304   void EmitBranch(InstrType instr, Condition condition);
305   template<class InstrType>
306   void EmitFalseBranch(InstrType instr, Condition condition);
307   void EmitNumberUntagD(Register input,
308                         DwVfpRegister result,
309                         bool allow_undefined_as_nan,
310                         bool deoptimize_on_minus_zero,
311                         LEnvironment* env,
312                         NumberUntagDMode mode);
313
314   // Emits optimized code for typeof x == "y".  Modifies input register.
315   // Returns the condition on which a final split to
316   // true and false label should be made, to optimize fallthrough.
317   Condition EmitTypeofIs(Label* true_label,
318                          Label* false_label,
319                          Register input,
320                          Handle<String> type_name);
321
322   // Emits optimized code for %_IsObject(x).  Preserves input register.
323   // Returns the condition on which a final split to
324   // true and false label should be made, to optimize fallthrough.
325   Condition EmitIsObject(Register input,
326                          Register temp1,
327                          Label* is_not_object,
328                          Label* is_object);
329
330   // Emits optimized code for %_IsString(x).  Preserves input register.
331   // Returns the condition on which a final split to
332   // true and false label should be made, to optimize fallthrough.
333   Condition EmitIsString(Register input,
334                          Register temp1,
335                          Label* is_not_string,
336                          SmiCheck check_needed);
337
338   // Emits optimized code for %_IsConstructCall().
339   // Caller should branch on equal condition.
340   void EmitIsConstructCall(Register temp1, Register temp2);
341
342   // Emits optimized code to deep-copy the contents of statically known
343   // object graphs (e.g. object literal boilerplate).
344   void EmitDeepCopy(Handle<JSObject> object,
345                     Register result,
346                     Register source,
347                     int* offset,
348                     AllocationSiteMode mode);
349
350   // Emit optimized code for integer division.
351   // Inputs are signed.
352   // All registers are clobbered.
353   // If 'remainder' is no_reg, it is not computed.
354   void EmitSignedIntegerDivisionByConstant(Register result,
355                                            Register dividend,
356                                            int32_t divisor,
357                                            Register remainder,
358                                            Register scratch,
359                                            LEnvironment* environment);
360
361   void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE;
362   void DoLoadKeyedExternalArray(LLoadKeyed* instr);
363   void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
364   void DoLoadKeyedFixedArray(LLoadKeyed* instr);
365   void DoStoreKeyedExternalArray(LStoreKeyed* instr);
366   void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
367   void DoStoreKeyedFixedArray(LStoreKeyed* instr);
368
369   ZoneList<LEnvironment*> deoptimizations_;
370   ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
371   ZoneList<Handle<Object> > deoptimization_literals_;
372   int inlined_function_count_;
373   Scope* const scope_;
374   TranslationBuffer translations_;
375   ZoneList<LDeferredCode*> deferred_;
376   int osr_pc_offset_;
377   bool frame_is_built_;
378
379   // Builder that keeps track of safepoints in the code. The table
380   // itself is emitted at the end of the generated code.
381   SafepointTableBuilder safepoints_;
382
383   // Compiler from a set of parallel moves to a sequential list of moves.
384   LGapResolver resolver_;
385
386   Safepoint::Kind expected_safepoint_kind_;
387
388   class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED {
389    public:
390     PushSafepointRegistersScope(LCodeGen* codegen,
391                                 Safepoint::Kind kind)
392         : codegen_(codegen) {
393       ASSERT(codegen_->info()->is_calling());
394       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
395       codegen_->expected_safepoint_kind_ = kind;
396
397       switch (codegen_->expected_safepoint_kind_) {
398         case Safepoint::kWithRegisters:
399           codegen_->masm_->PushSafepointRegisters();
400           break;
401         case Safepoint::kWithRegistersAndDoubles:
402           codegen_->masm_->PushSafepointRegistersAndDoubles();
403           break;
404         default:
405           UNREACHABLE();
406       }
407     }
408
409     ~PushSafepointRegistersScope() {
410       Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
411       ASSERT((kind & Safepoint::kWithRegisters) != 0);
412       switch (kind) {
413         case Safepoint::kWithRegisters:
414           codegen_->masm_->PopSafepointRegisters();
415           break;
416         case Safepoint::kWithRegistersAndDoubles:
417           codegen_->masm_->PopSafepointRegistersAndDoubles();
418           break;
419         default:
420           UNREACHABLE();
421       }
422       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
423     }
424
425    private:
426     LCodeGen* codegen_;
427   };
428
429   friend class LDeferredCode;
430   friend class LEnvironment;
431   friend class SafepointGenerator;
432   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
433 };
434
435
436 class LDeferredCode : public ZoneObject {
437  public:
438   explicit LDeferredCode(LCodeGen* codegen)
439       : codegen_(codegen),
440         external_exit_(NULL),
441         instruction_index_(codegen->current_instruction_) {
442     codegen->AddDeferredCode(this);
443   }
444
445   virtual ~LDeferredCode() {}
446   virtual void Generate() = 0;
447   virtual LInstruction* instr() = 0;
448
449   void SetExit(Label* exit) { external_exit_ = exit; }
450   Label* entry() { return &entry_; }
451   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
452   int instruction_index() const { return instruction_index_; }
453
454  protected:
455   LCodeGen* codegen() const { return codegen_; }
456   MacroAssembler* masm() const { return codegen_->masm(); }
457
458  private:
459   LCodeGen* codegen_;
460   Label entry_;
461   Label exit_;
462   Label* external_exit_;
463   int instruction_index_;
464 };
465
466 } }  // namespace v8::internal
467
468 #endif  // V8_ARM_LITHIUM_CODEGEN_ARM_H_