• 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_MIPS_LITHIUM_CODEGEN_MIPS_H_
6 #define V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
7 
8 #include "src/deoptimizer.h"
9 #include "src/lithium-codegen.h"
10 #include "src/mips64/lithium-gap-resolver-mips64.h"
11 #include "src/mips64/lithium-mips64.h"
12 #include "src/safepoint-table.h"
13 #include "src/scopes.h"
14 #include "src/utils.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 // Forward declarations.
20 class LDeferredCode;
21 class SafepointGenerator;
22 
23 class LCodeGen: public LCodeGenBase {
24  public:
LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)25   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
26       : LCodeGenBase(chunk, assembler, info),
27         deoptimizations_(4, info->zone()),
28         jump_table_(4, info->zone()),
29         deoptimization_literals_(8, 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 
LookupDestination(int block_id)43   int LookupDestination(int block_id) const {
44     return chunk()->LookupDestination(block_id);
45   }
46 
IsNextEmittedBlock(int block_id)47   bool IsNextEmittedBlock(int block_id) const {
48     return LookupDestination(block_id) == GetNextEmittedBlock();
49   }
50 
NeedsEagerFrame()51   bool NeedsEagerFrame() const {
52     return GetStackSlotCount() > 0 ||
53         info()->is_non_deferred_calling() ||
54         !info()->IsStub() ||
55         info()->requires_frame();
56   }
NeedsDeferredFrame()57   bool NeedsDeferredFrame() const {
58     return !NeedsEagerFrame() && info()->is_deferred_calling();
59   }
60 
GetRAState()61   RAStatus GetRAState() const {
62     return frame_is_built_ ? kRAHasBeenSaved : kRAHasNotBeenSaved;
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   DoubleRegister ToDoubleRegister(LOperand* op) const;
74 
75   // LOperand is loaded into dbl_scratch, unless already a double register.
76   DoubleRegister EmitLoadDoubleRegister(LOperand* op,
77                                         FloatRegister flt_scratch,
78                                         DoubleRegister dbl_scratch);
79   int32_t ToRepresentation_donotuse(LConstantOperand* op,
80                                     const Representation& r) const;
81   int32_t ToInteger32(LConstantOperand* op) const;
82   Smi* ToSmi(LConstantOperand* op) const;
83   double ToDouble(LConstantOperand* op) const;
84   Operand ToOperand(LOperand* op);
85   MemOperand ToMemOperand(LOperand* op) const;
86   // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
87   MemOperand ToHighMemOperand(LOperand* op) const;
88 
89   bool IsInteger32(LConstantOperand* op) const;
90   bool IsSmi(LConstantOperand* op) const;
91   Handle<Object> ToHandle(LConstantOperand* op) const;
92 
93   // Try to generate code for the entire chunk, but it may fail if the
94   // chunk contains constructs we cannot handle. Returns true if the
95   // code generation attempt succeeded.
96   bool GenerateCode();
97 
98   // Finish the code by setting stack height, safepoint, and bailout
99   // information on it.
100   void FinishCode(Handle<Code> code);
101 
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 DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
115   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
116   void DoDeferredAllocate(LAllocate* instr);
117   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
118                                        Label* map_check);
119 
120   void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
121   void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
122                                    Register result,
123                                    Register object,
124                                    Register index);
125 
126   // Parallel move support.
127   void DoParallelMove(LParallelMove* move);
128   void DoGap(LGap* instr);
129 
130   MemOperand PrepareKeyedOperand(Register key,
131                                  Register base,
132                                  bool key_is_constant,
133                                  int constant_key,
134                                  int element_size,
135                                  int shift_size,
136                                  int base_offset);
137 
138   // Emit frame translation commands for an environment.
139   void WriteTranslation(LEnvironment* environment, Translation* translation);
140 
141   // Declare methods that deal with the individual node types.
142 #define DECLARE_DO(type) void Do##type(L##type* node);
LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)143   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
144 #undef DECLARE_DO
145 
146  private:
147   StrictMode strict_mode() const { return info()->strict_mode(); }
148 
scope()149   Scope* scope() const { return scope_; }
150 
scratch0()151   Register scratch0() { return kLithiumScratchReg; }
scratch1()152   Register scratch1() { return kLithiumScratchReg2; }
double_scratch0()153   DoubleRegister double_scratch0() { return kLithiumScratchDouble; }
154 
155   LInstruction* GetNextInstruction();
156 
157   void EmitClassOfTest(Label* if_true,
158                        Label* if_false,
159                        Handle<String> class_name,
160                        Register input,
161                        Register temporary,
162                        Register temporary2);
163 
GetStackSlotCount()164   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
165 
AddDeferredCode(LDeferredCode * code)166   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
167 
168   void SaveCallerDoubles();
169   void RestoreCallerDoubles();
170 
171   // Code generation passes.  Returns true if code generation should
172   // continue.
173   void GenerateBodyInstructionPre(LInstruction* instr) OVERRIDE;
174   bool GeneratePrologue();
175   bool GenerateDeferredCode();
176   bool GenerateJumpTable();
177   bool GenerateSafepointTable();
178 
179   // Generates the custom OSR entrypoint and sets the osr_pc_offset.
180   void GenerateOsrPrologue();
181 
182   enum SafepointMode {
183     RECORD_SIMPLE_SAFEPOINT,
184     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
185   };
186 
187   void CallCode(Handle<Code> code,
188                 RelocInfo::Mode mode,
189                 LInstruction* instr);
190 
191   void CallCodeGeneric(Handle<Code> code,
192                        RelocInfo::Mode mode,
193                        LInstruction* instr,
194                        SafepointMode safepoint_mode);
195 
196   void CallRuntime(const Runtime::Function* function,
197                    int num_arguments,
198                    LInstruction* instr,
199                    SaveFPRegsMode save_doubles = kDontSaveFPRegs);
200 
CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)201   void CallRuntime(Runtime::FunctionId id,
202                    int num_arguments,
203                    LInstruction* instr) {
204     const Runtime::Function* function = Runtime::FunctionForId(id);
205     CallRuntime(function, num_arguments, instr);
206   }
207 
208   void LoadContextFromDeferred(LOperand* context);
209   void CallRuntimeFromDeferred(Runtime::FunctionId id,
210                                int argc,
211                                LInstruction* instr,
212                                LOperand* context);
213 
214   enum A1State {
215     A1_UNINITIALIZED,
216     A1_CONTAINS_TARGET
217   };
218 
219   // Generate a direct call to a known function.  Expects the function
220   // to be in a1.
221   void CallKnownFunction(Handle<JSFunction> function,
222                          int formal_parameter_count,
223                          int arity,
224                          LInstruction* instr,
225                          A1State a1_state);
226 
227   void RecordSafepointWithLazyDeopt(LInstruction* instr,
228                                     SafepointMode safepoint_mode);
229 
230   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
231                                             Safepoint::DeoptMode mode);
232   void DeoptimizeIf(Condition condition, LInstruction* instr,
233                     Deoptimizer::BailoutType bailout_type,
234                     Register src1 = zero_reg,
235                     const Operand& src2 = Operand(zero_reg),
236                     const char* detail = NULL);
237   void DeoptimizeIf(Condition condition, LInstruction* instr,
238                     Register src1 = zero_reg,
239                     const Operand& src2 = Operand(zero_reg),
240                     const char* detail = NULL);
241 
242   void AddToTranslation(LEnvironment* environment,
243                         Translation* translation,
244                         LOperand* op,
245                         bool is_tagged,
246                         bool is_uint32,
247                         int* object_index_pointer,
248                         int* dematerialized_index_pointer);
249   void PopulateDeoptimizationData(Handle<Code> code);
250   int DefineDeoptimizationLiteral(Handle<Object> literal);
251 
252   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
253 
254   Register ToRegister(int index) const;
255   DoubleRegister ToDoubleRegister(int index) const;
256 
257   MemOperand BuildSeqStringOperand(Register string,
258                                    LOperand* index,
259                                    String::Encoding encoding);
260 
261   void EmitIntegerMathAbs(LMathAbs* instr);
262 
263   // Support for recording safepoint and position information.
264   void RecordSafepoint(LPointerMap* pointers,
265                        Safepoint::Kind kind,
266                        int arguments,
267                        Safepoint::DeoptMode mode);
268   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
269   void RecordSafepoint(Safepoint::DeoptMode mode);
270   void RecordSafepointWithRegisters(LPointerMap* pointers,
271                                     int arguments,
272                                     Safepoint::DeoptMode mode);
273 
274   void RecordAndWritePosition(int position) OVERRIDE;
275 
276   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
277   void EmitGoto(int block);
278 
279   // EmitBranch expects to be the last instruction of a block.
280   template<class InstrType>
281   void EmitBranch(InstrType instr,
282                   Condition condition,
283                   Register src1,
284                   const Operand& src2);
285   template<class InstrType>
286   void EmitBranchF(InstrType instr,
287                    Condition condition,
288                    FPURegister src1,
289                    FPURegister src2);
290   template<class InstrType>
291   void EmitFalseBranch(InstrType instr,
292                        Condition condition,
293                        Register src1,
294                        const Operand& src2);
295   template<class InstrType>
296   void EmitFalseBranchF(InstrType instr,
297                         Condition condition,
298                         FPURegister src1,
299                         FPURegister src2);
300   void EmitCmpI(LOperand* left, LOperand* right);
301   void EmitNumberUntagD(LNumberUntagD* instr, Register input,
302                         DoubleRegister result, NumberUntagDMode mode);
303 
304   // Emits optimized code for typeof x == "y".  Modifies input register.
305   // Returns the condition on which a final split to
306   // true and false label should be made, to optimize fallthrough.
307   // Returns two registers in cmp1 and cmp2 that can be used in the
308   // Branch instruction after EmitTypeofIs.
309   Condition EmitTypeofIs(Label* true_label,
310                          Label* false_label,
311                          Register input,
312                          Handle<String> type_name,
313                          Register* cmp1,
314                          Operand* cmp2);
315 
316   // Emits optimized code for %_IsObject(x).  Preserves input register.
317   // Returns the condition on which a final split to
318   // true and false label should be made, to optimize fallthrough.
319   Condition EmitIsObject(Register input,
320                          Register temp1,
321                          Register temp2,
322                          Label* is_not_object,
323                          Label* is_object);
324 
325   // Emits optimized code for %_IsString(x).  Preserves input register.
326   // Returns the condition on which a final split to
327   // true and false label should be made, to optimize fallthrough.
328   Condition EmitIsString(Register input,
329                          Register temp1,
330                          Label* is_not_string,
331                          SmiCheck check_needed);
332 
333   // Emits optimized code for %_IsConstructCall().
334   // Caller should branch on equal condition.
335   void EmitIsConstructCall(Register temp1, Register temp2);
336 
337   // Emits optimized code to deep-copy the contents of statically known
338   // object graphs (e.g. object literal boilerplate).
339   void EmitDeepCopy(Handle<JSObject> object,
340                     Register result,
341                     Register source,
342                     int* offset,
343                     AllocationSiteMode mode);
344   // Emit optimized code for integer division.
345   // Inputs are signed.
346   // All registers are clobbered.
347   // If 'remainder' is no_reg, it is not computed.
348   void EmitSignedIntegerDivisionByConstant(Register result,
349                                            Register dividend,
350                                            int32_t divisor,
351                                            Register remainder,
352                                            Register scratch,
353                                            LEnvironment* environment);
354 
355 
356   void EnsureSpaceForLazyDeopt(int space_needed) OVERRIDE;
357   void DoLoadKeyedExternalArray(LLoadKeyed* instr);
358   void DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr);
359   void DoLoadKeyedFixedArray(LLoadKeyed* instr);
360   void DoStoreKeyedExternalArray(LStoreKeyed* instr);
361   void DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr);
362   void DoStoreKeyedFixedArray(LStoreKeyed* instr);
363 
364   template <class T>
365   void EmitVectorLoadICRegisters(T* instr);
366 
367   ZoneList<LEnvironment*> deoptimizations_;
368   ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
369   ZoneList<Handle<Object> > deoptimization_literals_;
370   int inlined_function_count_;
371   Scope* const scope_;
372   TranslationBuffer translations_;
373   ZoneList<LDeferredCode*> deferred_;
374   int osr_pc_offset_;
375   bool frame_is_built_;
376 
377   // Builder that keeps track of safepoints in the code. The table
378   // itself is emitted at the end of the generated code.
379   SafepointTableBuilder safepoints_;
380 
381   // Compiler from a set of parallel moves to a sequential list of moves.
382   LGapResolver resolver_;
383 
384   Safepoint::Kind expected_safepoint_kind_;
385 
386   class PushSafepointRegistersScope FINAL BASE_EMBEDDED {
387    public:
PushSafepointRegistersScope(LCodeGen * codegen)388     explicit PushSafepointRegistersScope(LCodeGen* codegen)
389         : codegen_(codegen) {
390       DCHECK(codegen_->info()->is_calling());
391       DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
392       codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
393 
394       StoreRegistersStateStub stub(codegen_->isolate());
395       codegen_->masm_->push(ra);
396       codegen_->masm_->CallStub(&stub);
397     }
398 
~PushSafepointRegistersScope()399     ~PushSafepointRegistersScope() {
400       DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
401       RestoreRegistersStateStub stub(codegen_->isolate());
402       codegen_->masm_->push(ra);
403       codegen_->masm_->CallStub(&stub);
404       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
405     }
406 
407    private:
408     LCodeGen* codegen_;
409   };
410 
411   friend class LDeferredCode;
412   friend class LEnvironment;
413   friend class SafepointGenerator;
414   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
415 };
416 
417 
418 class LDeferredCode : public ZoneObject {
419  public:
LDeferredCode(LCodeGen * codegen)420   explicit LDeferredCode(LCodeGen* codegen)
421       : codegen_(codegen),
422         external_exit_(NULL),
423         instruction_index_(codegen->current_instruction_) {
424     codegen->AddDeferredCode(this);
425   }
426 
~LDeferredCode()427   virtual ~LDeferredCode() {}
428   virtual void Generate() = 0;
429   virtual LInstruction* instr() = 0;
430 
SetExit(Label * exit)431   void SetExit(Label* exit) { external_exit_ = exit; }
entry()432   Label* entry() { return &entry_; }
exit()433   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
instruction_index()434   int instruction_index() const { return instruction_index_; }
435 
436  protected:
codegen()437   LCodeGen* codegen() const { return codegen_; }
masm()438   MacroAssembler* masm() const { return codegen_->masm(); }
439 
440  private:
441   LCodeGen* codegen_;
442   Label entry_;
443   Label exit_;
444   Label* external_exit_;
445   int instruction_index_;
446 };
447 
448 } }  // namespace v8::internal
449 
450 #endif  // V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
451