• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "arm/lithium-gap-resolver-arm.h"
33 #include "deoptimizer.h"
34 #include "safepoint-table.h"
35 #include "scopes.h"
36 
37 namespace v8 {
38 namespace internal {
39 
40 // Forward declarations.
41 class LDeferredCode;
42 class SafepointGenerator;
43 
44 class LCodeGen BASE_EMBEDDED {
45  public:
LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)46   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
47       : chunk_(chunk),
48         masm_(assembler),
49         info_(info),
50         current_block_(-1),
51         current_instruction_(-1),
52         instructions_(chunk->instructions()),
53         deoptimizations_(4),
54         deopt_jump_table_(4),
55         deoptimization_literals_(8),
56         inlined_function_count_(0),
57         scope_(info->scope()),
58         status_(UNUSED),
59         deferred_(8),
60         osr_pc_offset_(-1),
61         last_lazy_deopt_pc_(0),
62         resolver_(this),
63         expected_safepoint_kind_(Safepoint::kSimple) {
64     PopulateDeoptimizationLiteralsWithInlinedFunctions();
65   }
66 
67 
68   // Simple accessors.
masm()69   MacroAssembler* masm() const { return masm_; }
info()70   CompilationInfo* info() const { return info_; }
isolate()71   Isolate* isolate() const { return info_->isolate(); }
factory()72   Factory* factory() const { return isolate()->factory(); }
heap()73   Heap* heap() const { return isolate()->heap(); }
74 
75   // Support for converting LOperands to assembler types.
76   // LOperand must be a register.
77   Register ToRegister(LOperand* op) const;
78 
79   // LOperand is loaded into scratch, unless already a register.
80   Register EmitLoadRegister(LOperand* op, Register scratch);
81 
82   // LOperand must be a double register.
83   DoubleRegister ToDoubleRegister(LOperand* op) const;
84 
85   // LOperand is loaded into dbl_scratch, unless already a double register.
86   DoubleRegister EmitLoadDoubleRegister(LOperand* op,
87                                         SwVfpRegister flt_scratch,
88                                         DoubleRegister dbl_scratch);
89   int ToInteger32(LConstantOperand* op) const;
90   double ToDouble(LConstantOperand* op) const;
91   Operand ToOperand(LOperand* op);
92   MemOperand ToMemOperand(LOperand* op) const;
93   // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
94   MemOperand ToHighMemOperand(LOperand* op) const;
95 
96   bool IsInteger32(LConstantOperand* op) const;
97   Handle<Object> ToHandle(LConstantOperand* op) const;
98 
99   // Try to generate code for the entire chunk, but it may fail if the
100   // chunk contains constructs we cannot handle. Returns true if the
101   // code generation attempt succeeded.
102   bool GenerateCode();
103 
104   // Finish the code by setting stack height, safepoint, and bailout
105   // information on it.
106   void FinishCode(Handle<Code> code);
107 
108   // Deferred code support.
109   template<int T>
110   void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
111                               Token::Value op);
112   void DoDeferredNumberTagD(LNumberTagD* instr);
113   void DoDeferredNumberTagI(LNumberTagI* instr);
114   void DoDeferredTaggedToI(LTaggedToI* instr);
115   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
116   void DoDeferredStackCheck(LStackCheck* instr);
117   void DoDeferredRandom(LRandom* instr);
118   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
119   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
120   void DoDeferredAllocateObject(LAllocateObject* instr);
121   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
122                                        Label* map_check);
123 
124   void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map,
125                         CompareMapMode mode, LEnvironment* env);
126 
127   // Parallel move support.
128   void DoParallelMove(LParallelMove* move);
129   void DoGap(LGap* instr);
130 
131   // Emit frame translation commands for an environment.
132   void WriteTranslation(LEnvironment* environment, Translation* translation);
133 
134   // Declare methods that deal with the individual node types.
135 #define DECLARE_DO(type) void Do##type(L##type* node);
136   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
137 #undef DECLARE_DO
138 
139  private:
140   enum Status {
141     UNUSED,
142     GENERATING,
143     DONE,
144     ABORTED
145   };
146 
is_unused()147   bool is_unused() const { return status_ == UNUSED; }
is_generating()148   bool is_generating() const { return status_ == GENERATING; }
is_done()149   bool is_done() const { return status_ == DONE; }
is_aborted()150   bool is_aborted() const { return status_ == ABORTED; }
151 
strict_mode_flag()152   StrictModeFlag strict_mode_flag() const {
153     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
154   }
155 
chunk()156   LChunk* chunk() const { return chunk_; }
scope()157   Scope* scope() const { return scope_; }
graph()158   HGraph* graph() const { return chunk_->graph(); }
159 
scratch0()160   Register scratch0() { return r9; }
double_scratch0()161   DwVfpRegister double_scratch0() { return kScratchDoubleReg; }
162 
163   int GetNextEmittedBlock(int block);
164   LInstruction* GetNextInstruction();
165 
166   void EmitClassOfTest(Label* if_true,
167                        Label* if_false,
168                        Handle<String> class_name,
169                        Register input,
170                        Register temporary,
171                        Register temporary2);
172 
GetStackSlotCount()173   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
GetParameterCount()174   int GetParameterCount() const { return scope()->num_parameters(); }
175 
176   void Abort(const char* format, ...);
177   void Comment(const char* format, ...);
178 
AddDeferredCode(LDeferredCode * code)179   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
180 
181   // Code generation passes.  Returns true if code generation should
182   // continue.
183   bool GeneratePrologue();
184   bool GenerateBody();
185   bool GenerateDeferredCode();
186   bool GenerateDeoptJumpTable();
187   bool GenerateSafepointTable();
188 
189   enum SafepointMode {
190     RECORD_SIMPLE_SAFEPOINT,
191     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
192   };
193 
194   void CallCode(Handle<Code> code,
195                 RelocInfo::Mode mode,
196                 LInstruction* instr);
197 
198   void CallCodeGeneric(Handle<Code> code,
199                        RelocInfo::Mode mode,
200                        LInstruction* instr,
201                        SafepointMode safepoint_mode);
202 
203   void CallRuntime(const Runtime::Function* function,
204                    int num_arguments,
205                    LInstruction* instr);
206 
CallRuntime(Runtime::FunctionId id,int num_arguments,LInstruction * instr)207   void CallRuntime(Runtime::FunctionId id,
208                    int num_arguments,
209                    LInstruction* instr) {
210     const Runtime::Function* function = Runtime::FunctionForId(id);
211     CallRuntime(function, num_arguments, instr);
212   }
213 
214   void CallRuntimeFromDeferred(Runtime::FunctionId id,
215                                int argc,
216                                LInstruction* instr);
217 
218   // Generate a direct call to a known function.  Expects the function
219   // to be in r1.
220   void CallKnownFunction(Handle<JSFunction> function,
221                          int arity,
222                          LInstruction* instr,
223                          CallKind call_kind);
224 
225   void LoadHeapObject(Register result, Handle<HeapObject> object);
226 
227   void RecordSafepointWithLazyDeopt(LInstruction* instr,
228                                     SafepointMode safepoint_mode);
229 
230   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
231                                             Safepoint::DeoptMode mode);
232   void DeoptimizeIf(Condition cc, LEnvironment* environment);
233 
234   void AddToTranslation(Translation* translation,
235                         LOperand* op,
236                         bool is_tagged);
237   void PopulateDeoptimizationData(Handle<Code> code);
238   int DefineDeoptimizationLiteral(Handle<Object> literal);
239 
240   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
241 
242   Register ToRegister(int index) const;
243   DoubleRegister ToDoubleRegister(int index) const;
244 
245   // Specific math operations - used from DoUnaryMathOperation.
246   void EmitIntegerMathAbs(LUnaryMathOperation* instr);
247   void DoMathAbs(LUnaryMathOperation* instr);
248   void DoMathFloor(LUnaryMathOperation* instr);
249   void DoMathRound(LUnaryMathOperation* instr);
250   void DoMathSqrt(LUnaryMathOperation* instr);
251   void DoMathPowHalf(LUnaryMathOperation* instr);
252   void DoMathLog(LUnaryMathOperation* instr);
253   void DoMathTan(LUnaryMathOperation* instr);
254   void DoMathCos(LUnaryMathOperation* instr);
255   void DoMathSin(LUnaryMathOperation* instr);
256 
257   // Support for recording safepoint and position information.
258   void RecordSafepoint(LPointerMap* pointers,
259                        Safepoint::Kind kind,
260                        int arguments,
261                        Safepoint::DeoptMode mode);
262   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
263   void RecordSafepoint(Safepoint::DeoptMode mode);
264   void RecordSafepointWithRegisters(LPointerMap* pointers,
265                                     int arguments,
266                                     Safepoint::DeoptMode mode);
267   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
268                                               int arguments,
269                                               Safepoint::DeoptMode mode);
270   void RecordPosition(int position);
271 
272   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
273   void EmitGoto(int block);
274   void EmitBranch(int left_block, int right_block, Condition cc);
275   void EmitNumberUntagD(Register input,
276                         DoubleRegister result,
277                         bool deoptimize_on_undefined,
278                         bool deoptimize_on_minus_zero,
279                         LEnvironment* env);
280 
281   // Emits optimized code for typeof x == "y".  Modifies input register.
282   // Returns the condition on which a final split to
283   // true and false label should be made, to optimize fallthrough.
284   Condition EmitTypeofIs(Label* true_label,
285                          Label* false_label,
286                          Register input,
287                          Handle<String> type_name);
288 
289   // Emits optimized code for %_IsObject(x).  Preserves input register.
290   // Returns the condition on which a final split to
291   // true and false label should be made, to optimize fallthrough.
292   Condition EmitIsObject(Register input,
293                          Register temp1,
294                          Label* is_not_object,
295                          Label* is_object);
296 
297   // Emits optimized code for %_IsString(x).  Preserves input register.
298   // Returns the condition on which a final split to
299   // true and false label should be made, to optimize fallthrough.
300   Condition EmitIsString(Register input,
301                          Register temp1,
302                          Label* is_not_string);
303 
304   // Emits optimized code for %_IsConstructCall().
305   // Caller should branch on equal condition.
306   void EmitIsConstructCall(Register temp1, Register temp2);
307 
308   void EmitLoadFieldOrConstantFunction(Register result,
309                                        Register object,
310                                        Handle<Map> type,
311                                        Handle<String> name);
312 
313   // Emits optimized code to deep-copy the contents of statically known
314   // object graphs (e.g. object literal boilerplate).
315   void EmitDeepCopy(Handle<JSObject> object,
316                     Register result,
317                     Register source,
318                     int* offset);
319 
320   struct JumpTableEntry {
JumpTableEntryJumpTableEntry321     explicit inline JumpTableEntry(Address entry)
322         : label(),
323           address(entry) { }
324     Label label;
325     Address address;
326   };
327 
328   void EnsureSpaceForLazyDeopt();
329 
330   LChunk* const chunk_;
331   MacroAssembler* const masm_;
332   CompilationInfo* const info_;
333 
334   int current_block_;
335   int current_instruction_;
336   const ZoneList<LInstruction*>* instructions_;
337   ZoneList<LEnvironment*> deoptimizations_;
338   ZoneList<JumpTableEntry> deopt_jump_table_;
339   ZoneList<Handle<Object> > deoptimization_literals_;
340   int inlined_function_count_;
341   Scope* const scope_;
342   Status status_;
343   TranslationBuffer translations_;
344   ZoneList<LDeferredCode*> deferred_;
345   int osr_pc_offset_;
346   int last_lazy_deopt_pc_;
347 
348   // Builder that keeps track of safepoints in the code. The table
349   // itself is emitted at the end of the generated code.
350   SafepointTableBuilder safepoints_;
351 
352   // Compiler from a set of parallel moves to a sequential list of moves.
353   LGapResolver resolver_;
354 
355   Safepoint::Kind expected_safepoint_kind_;
356 
357   class PushSafepointRegistersScope BASE_EMBEDDED {
358    public:
PushSafepointRegistersScope(LCodeGen * codegen,Safepoint::Kind kind)359     PushSafepointRegistersScope(LCodeGen* codegen,
360                                 Safepoint::Kind kind)
361         : codegen_(codegen) {
362       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
363       codegen_->expected_safepoint_kind_ = kind;
364 
365       switch (codegen_->expected_safepoint_kind_) {
366         case Safepoint::kWithRegisters:
367           codegen_->masm_->PushSafepointRegisters();
368           break;
369         case Safepoint::kWithRegistersAndDoubles:
370           codegen_->masm_->PushSafepointRegistersAndDoubles();
371           break;
372         default:
373           UNREACHABLE();
374       }
375     }
376 
~PushSafepointRegistersScope()377     ~PushSafepointRegistersScope() {
378       Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
379       ASSERT((kind & Safepoint::kWithRegisters) != 0);
380       switch (kind) {
381         case Safepoint::kWithRegisters:
382           codegen_->masm_->PopSafepointRegisters();
383           break;
384         case Safepoint::kWithRegistersAndDoubles:
385           codegen_->masm_->PopSafepointRegistersAndDoubles();
386           break;
387         default:
388           UNREACHABLE();
389       }
390       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
391     }
392 
393    private:
394     LCodeGen* codegen_;
395   };
396 
397   friend class LDeferredCode;
398   friend class LEnvironment;
399   friend class SafepointGenerator;
400   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
401 };
402 
403 
404 class LDeferredCode: public ZoneObject {
405  public:
LDeferredCode(LCodeGen * codegen)406   explicit LDeferredCode(LCodeGen* codegen)
407       : codegen_(codegen),
408         external_exit_(NULL),
409         instruction_index_(codegen->current_instruction_) {
410     codegen->AddDeferredCode(this);
411   }
412 
~LDeferredCode()413   virtual ~LDeferredCode() { }
414   virtual void Generate() = 0;
415   virtual LInstruction* instr() = 0;
416 
SetExit(Label * exit)417   void SetExit(Label* exit) { external_exit_ = exit; }
entry()418   Label* entry() { return &entry_; }
exit()419   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
instruction_index()420   int instruction_index() const { return instruction_index_; }
421 
422  protected:
codegen()423   LCodeGen* codegen() const { return codegen_; }
masm()424   MacroAssembler* masm() const { return codegen_->masm(); }
425 
426  private:
427   LCodeGen* codegen_;
428   Label entry_;
429   Label exit_;
430   Label* external_exit_;
431   int instruction_index_;
432 };
433 
434 } }  // namespace v8::internal
435 
436 #endif  // V8_ARM_LITHIUM_CODEGEN_ARM_H_
437