• 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_IA32_LITHIUM_CODEGEN_IA32_H_
29 #define V8_IA32_LITHIUM_CODEGEN_IA32_H_
30 
31 #include "ia32/lithium-ia32.h"
32 
33 #include "checks.h"
34 #include "deoptimizer.h"
35 #include "safepoint-table.h"
36 #include "scopes.h"
37 #include "ia32/lithium-gap-resolver-ia32.h"
38 
39 namespace v8 {
40 namespace internal {
41 
42 // Forward declarations.
43 class LDeferredCode;
44 class LGapNode;
45 class SafepointGenerator;
46 
47 class LCodeGen BASE_EMBEDDED {
48  public:
LCodeGen(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)49   LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
50       : chunk_(chunk),
51         masm_(assembler),
52         info_(info),
53         current_block_(-1),
54         current_instruction_(-1),
55         instructions_(chunk->instructions()),
56         deoptimizations_(4),
57         deoptimization_literals_(8),
58         inlined_function_count_(0),
59         scope_(info->scope()),
60         status_(UNUSED),
61         deferred_(8),
62         osr_pc_offset_(-1),
63         last_lazy_deopt_pc_(0),
64         resolver_(this),
65         expected_safepoint_kind_(Safepoint::kSimple) {
66     PopulateDeoptimizationLiteralsWithInlinedFunctions();
67   }
68 
69   // Simple accessors.
masm()70   MacroAssembler* masm() const { return masm_; }
info()71   CompilationInfo* info() const { return info_; }
isolate()72   Isolate* isolate() const { return info_->isolate(); }
factory()73   Factory* factory() const { return isolate()->factory(); }
heap()74   Heap* heap() const { return isolate()->heap(); }
75 
76   // Support for converting LOperands to assembler types.
77   Operand ToOperand(LOperand* op) const;
78   Register ToRegister(LOperand* op) const;
79   XMMRegister ToDoubleRegister(LOperand* op) const;
80 
81   bool IsInteger32(LConstantOperand* op) const;
ToInteger32Immediate(LOperand * op)82   Immediate ToInteger32Immediate(LOperand* op) const {
83     return Immediate(ToInteger32(LConstantOperand::cast(op)));
84   }
85 
86   Handle<Object> ToHandle(LConstantOperand* op) const;
87 
88   // The operand denoting the second word (the one with a higher address) of
89   // a double stack slot.
90   Operand HighOperand(LOperand* op);
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   void DoDeferredNumberTagI(LNumberTagI* instr);
104   void DoDeferredTaggedToI(LTaggedToI* instr);
105   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
106   void DoDeferredStackCheck(LStackCheck* instr);
107   void DoDeferredRandom(LRandom* instr);
108   void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
109   void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
110   void DoDeferredAllocateObject(LAllocateObject* instr);
111   void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
112                                        Label* map_check);
113 
114   void DoCheckMapCommon(Register reg, Handle<Map> map,
115                         CompareMapMode mode, LEnvironment* env);
116 
117   // Parallel move support.
118   void DoParallelMove(LParallelMove* move);
119   void DoGap(LGap* instr);
120 
121   // Emit frame translation commands for an environment.
122   void WriteTranslation(LEnvironment* environment, Translation* translation);
123 
124   void EnsureRelocSpaceForDeoptimization();
125 
126   // Declare methods that deal with the individual node types.
127 #define DECLARE_DO(type) void Do##type(L##type* node);
128   LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
129 #undef DECLARE_DO
130 
131  private:
132   enum Status {
133     UNUSED,
134     GENERATING,
135     DONE,
136     ABORTED
137   };
138 
is_unused()139   bool is_unused() const { return status_ == UNUSED; }
is_generating()140   bool is_generating() const { return status_ == GENERATING; }
is_done()141   bool is_done() const { return status_ == DONE; }
is_aborted()142   bool is_aborted() const { return status_ == ABORTED; }
143 
strict_mode_flag()144   StrictModeFlag strict_mode_flag() const {
145     return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
146   }
147 
chunk()148   LChunk* chunk() const { return chunk_; }
scope()149   Scope* scope() const { return scope_; }
graph()150   HGraph* graph() const { return chunk_->graph(); }
151 
152   int GetNextEmittedBlock(int block);
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 
GetStackSlotCount()161   int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
GetParameterCount()162   int GetParameterCount() const { return scope()->num_parameters(); }
163 
164   void Abort(const char* format, ...);
165   void Comment(const char* format, ...);
166 
AddDeferredCode(LDeferredCode * code)167   void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
168 
169   // Code generation passes.  Returns true if code generation should
170   // continue.
171   bool GeneratePrologue();
172   bool GenerateBody();
173   bool GenerateDeferredCode();
174   // Pad the reloc info to ensure that we have enough space to patch during
175   // deoptimization.
176   bool GenerateRelocPadding();
177   bool GenerateSafepointTable();
178 
179   enum SafepointMode {
180     RECORD_SIMPLE_SAFEPOINT,
181     RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
182   };
183 
184   void CallCode(Handle<Code> code,
185                 RelocInfo::Mode mode,
186                 LInstruction* instr);
187 
188   void CallCodeGeneric(Handle<Code> code,
189                        RelocInfo::Mode mode,
190                        LInstruction* instr,
191                        SafepointMode safepoint_mode);
192 
193   void CallRuntime(const Runtime::Function* fun,
194                    int argc,
195                    LInstruction* instr);
196 
CallRuntime(Runtime::FunctionId id,int argc,LInstruction * instr)197   void CallRuntime(Runtime::FunctionId id,
198                    int argc,
199                    LInstruction* instr) {
200     const Runtime::Function* function = Runtime::FunctionForId(id);
201     CallRuntime(function, argc, instr);
202   }
203 
204   void CallRuntimeFromDeferred(Runtime::FunctionId id,
205                                int argc,
206                                LInstruction* instr,
207                                LOperand* context);
208 
209   // Generate a direct call to a known function.  Expects the function
210   // to be in edi.
211   void CallKnownFunction(Handle<JSFunction> function,
212                          int arity,
213                          LInstruction* instr,
214                          CallKind call_kind);
215 
216   void RecordSafepointWithLazyDeopt(LInstruction* instr,
217                                     SafepointMode safepoint_mode);
218 
219   void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
220                                             Safepoint::DeoptMode mode);
221   void DeoptimizeIf(Condition cc, LEnvironment* environment);
222 
223   void AddToTranslation(Translation* translation,
224                         LOperand* op,
225                         bool is_tagged);
226   void PopulateDeoptimizationData(Handle<Code> code);
227   int DefineDeoptimizationLiteral(Handle<Object> literal);
228 
229   void PopulateDeoptimizationLiteralsWithInlinedFunctions();
230 
231   Register ToRegister(int index) const;
232   XMMRegister ToDoubleRegister(int index) const;
233   int ToInteger32(LConstantOperand* op) const;
234 
235   double ToDouble(LConstantOperand* op) const;
236   Operand BuildFastArrayOperand(LOperand* elements_pointer,
237                                 LOperand* key,
238                                 ElementsKind elements_kind,
239                                 uint32_t offset);
240 
241   // Specific math operations - used from DoUnaryMathOperation.
242   void EmitIntegerMathAbs(LUnaryMathOperation* instr);
243   void DoMathAbs(LUnaryMathOperation* instr);
244   void DoMathFloor(LUnaryMathOperation* instr);
245   void DoMathRound(LUnaryMathOperation* instr);
246   void DoMathSqrt(LUnaryMathOperation* instr);
247   void DoMathLog(LUnaryMathOperation* instr);
248   void DoMathTan(LUnaryMathOperation* instr);
249   void DoMathCos(LUnaryMathOperation* instr);
250   void DoMathSin(LUnaryMathOperation* instr);
251 
252   // Support for recording safepoint and position information.
253   void RecordSafepoint(LPointerMap* pointers,
254                        Safepoint::Kind kind,
255                        int arguments,
256                        Safepoint::DeoptMode mode);
257   void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
258   void RecordSafepoint(Safepoint::DeoptMode mode);
259   void RecordSafepointWithRegisters(LPointerMap* pointers,
260                                     int arguments,
261                                     Safepoint::DeoptMode mode);
262   void RecordPosition(int position);
263 
264   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
265   void EmitGoto(int block);
266   void EmitBranch(int left_block, int right_block, Condition cc);
267   void EmitNumberUntagD(Register input,
268                         Register temp,
269                         XMMRegister result,
270                         bool deoptimize_on_undefined,
271                         bool deoptimize_on_minus_zero,
272                         LEnvironment* env);
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(Label* true_label,
278                          Label* false_label,
279                          Register input,
280                          Handle<String> type_name);
281 
282   // Emits optimized code for %_IsObject(x).  Preserves input register.
283   // Returns the condition on which a final split to
284   // true and false label should be made, to optimize fallthrough.
285   Condition EmitIsObject(Register input,
286                          Register temp1,
287                          Label* is_not_object,
288                          Label* is_object);
289 
290   // Emits optimized code for %_IsString(x).  Preserves input register.
291   // Returns the condition on which a final split to
292   // true and false label should be made, to optimize fallthrough.
293   Condition EmitIsString(Register input,
294                          Register temp1,
295                          Label* is_not_string);
296 
297   // Emits optimized code for %_IsConstructCall().
298   // Caller should branch on equal condition.
299   void EmitIsConstructCall(Register temp);
300 
301   void EmitLoadFieldOrConstantFunction(Register result,
302                                        Register object,
303                                        Handle<Map> type,
304                                        Handle<String> name);
305 
306   // Emits optimized code to deep-copy the contents of statically known
307   // object graphs (e.g. object literal boilerplate).
308   void EmitDeepCopy(Handle<JSObject> object,
309                     Register result,
310                     Register source,
311                     int* offset);
312 
313   void EnsureSpaceForLazyDeopt();
314 
315   // Emits code for pushing either a tagged constant, a (non-double)
316   // register, or a stack slot operand.
317   void EmitPushTaggedOperand(LOperand* operand);
318 
319   LChunk* const chunk_;
320   MacroAssembler* const masm_;
321   CompilationInfo* const info_;
322 
323   int current_block_;
324   int current_instruction_;
325   const ZoneList<LInstruction*>* instructions_;
326   ZoneList<LEnvironment*> deoptimizations_;
327   ZoneList<Handle<Object> > deoptimization_literals_;
328   int inlined_function_count_;
329   Scope* const scope_;
330   Status status_;
331   TranslationBuffer translations_;
332   ZoneList<LDeferredCode*> deferred_;
333   int osr_pc_offset_;
334   int last_lazy_deopt_pc_;
335 
336   // Builder that keeps track of safepoints in the code. The table
337   // itself is emitted at the end of the generated code.
338   SafepointTableBuilder safepoints_;
339 
340   // Compiler from a set of parallel moves to a sequential list of moves.
341   LGapResolver resolver_;
342 
343   Safepoint::Kind expected_safepoint_kind_;
344 
345   class PushSafepointRegistersScope BASE_EMBEDDED {
346    public:
PushSafepointRegistersScope(LCodeGen * codegen)347     explicit PushSafepointRegistersScope(LCodeGen* codegen)
348         : codegen_(codegen) {
349       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
350       codegen_->masm_->PushSafepointRegisters();
351       codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
352     }
353 
~PushSafepointRegistersScope()354     ~PushSafepointRegistersScope() {
355       ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
356       codegen_->masm_->PopSafepointRegisters();
357       codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
358     }
359 
360    private:
361     LCodeGen* codegen_;
362   };
363 
364   friend class LDeferredCode;
365   friend class LEnvironment;
366   friend class SafepointGenerator;
367   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
368 };
369 
370 
371 class LDeferredCode: public ZoneObject {
372  public:
LDeferredCode(LCodeGen * codegen)373   explicit LDeferredCode(LCodeGen* codegen)
374       : codegen_(codegen),
375         external_exit_(NULL),
376         instruction_index_(codegen->current_instruction_) {
377     codegen->AddDeferredCode(this);
378   }
379 
~LDeferredCode()380   virtual ~LDeferredCode() { }
381   virtual void Generate() = 0;
382   virtual LInstruction* instr() = 0;
383 
SetExit(Label * exit)384   void SetExit(Label* exit) { external_exit_ = exit; }
entry()385   Label* entry() { return &entry_; }
exit()386   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
instruction_index()387   int instruction_index() const { return instruction_index_; }
388 
389  protected:
codegen()390   LCodeGen* codegen() const { return codegen_; }
masm()391   MacroAssembler* masm() const { return codegen_->masm(); }
392 
393  private:
394   LCodeGen* codegen_;
395   Label entry_;
396   Label exit_;
397   Label* external_exit_;
398   int instruction_index_;
399 };
400 
401 } }  // namespace v8::internal
402 
403 #endif  // V8_IA32_LITHIUM_CODEGEN_IA32_H_
404