blob: 23e0c44b42bba499ee674b501a0328a0d9495981 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// 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"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000032#include "arm/lithium-gap-resolver-arm.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "deoptimizer.h"
34#include "safepoint-table.h"
35#include "scopes.h"
36
37namespace v8 {
38namespace internal {
39
40// Forward declarations.
41class LDeferredCode;
42class SafepointGenerator;
43
kasperl@chromium.orga5551262010-12-07 12:49:48 +000044class LCodeGen BASE_EMBEDDED {
45 public:
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 deoptimization_literals_(8),
55 inlined_function_count_(0),
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000056 scope_(info->scope()),
kasperl@chromium.orga5551262010-12-07 12:49:48 +000057 status_(UNUSED),
58 deferred_(8),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000059 osr_pc_offset_(-1),
60 resolver_(this) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000061 PopulateDeoptimizationLiteralsWithInlinedFunctions();
62 }
63
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000064
65 // Simple accessors.
66 MacroAssembler* masm() const { return masm_; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000067 CompilationInfo* info() const { return info_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000068
69 // Support for converting LOperands to assembler types.
70 // LOperand must be a register.
71 Register ToRegister(LOperand* op) const;
72
73 // LOperand is loaded into scratch, unless already a register.
74 Register EmitLoadRegister(LOperand* op, Register scratch);
75
76 // LOperand must be a double register.
77 DoubleRegister ToDoubleRegister(LOperand* op) const;
78
79 // LOperand is loaded into dbl_scratch, unless already a double register.
80 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
81 SwVfpRegister flt_scratch,
82 DoubleRegister dbl_scratch);
83 int ToInteger32(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
kasperl@chromium.orga5551262010-12-07 12:49:48 +000089 // Try to generate code for the entire chunk, but it may fail if the
90 // chunk contains constructs we cannot handle. Returns true if the
91 // code generation attempt succeeded.
92 bool GenerateCode();
93
94 // Finish the code by setting stack height, safepoint, and bailout
95 // information on it.
96 void FinishCode(Handle<Code> code);
97
98 // Deferred code support.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000099 template<int T>
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000100 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
101 Token::Value op);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000102 void DoDeferredNumberTagD(LNumberTagD* instr);
103 void DoDeferredNumberTagI(LNumberTagI* instr);
104 void DoDeferredTaggedToI(LTaggedToI* instr);
105 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
106 void DoDeferredStackCheck(LGoto* instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000107 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
108 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
109 Label* map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000110
111 // Parallel move support.
112 void DoParallelMove(LParallelMove* move);
113
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000114 // Emit frame translation commands for an environment.
115 void WriteTranslation(LEnvironment* environment, Translation* translation);
116
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000117 // Declare methods that deal with the individual node types.
118#define DECLARE_DO(type) void Do##type(L##type* node);
119 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
120#undef DECLARE_DO
121
122 private:
123 enum Status {
124 UNUSED,
125 GENERATING,
126 DONE,
127 ABORTED
128 };
129
130 bool is_unused() const { return status_ == UNUSED; }
131 bool is_generating() const { return status_ == GENERATING; }
132 bool is_done() const { return status_ == DONE; }
133 bool is_aborted() const { return status_ == ABORTED; }
134
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000135 int strict_mode_flag() const {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000136 return info()->is_strict() ? kStrictMode : kNonStrictMode;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000137 }
138
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000139 LChunk* chunk() const { return chunk_; }
140 Scope* scope() const { return scope_; }
141 HGraph* graph() const { return chunk_->graph(); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000142
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000143 Register scratch0() { return r9; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000144 DwVfpRegister double_scratch0() { return d0; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000145
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000146 int GetNextEmittedBlock(int block);
147 LInstruction* GetNextInstruction();
148
149 void EmitClassOfTest(Label* if_true,
150 Label* if_false,
151 Handle<String> class_name,
152 Register input,
153 Register temporary,
154 Register temporary2);
155
156 int StackSlotCount() const { return chunk()->spill_slot_count(); }
157 int ParameterCount() const { return scope()->num_parameters(); }
158
159 void Abort(const char* format, ...);
160 void Comment(const char* format, ...);
161
162 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
163
164 // Code generation passes. Returns true if code generation should
165 // continue.
166 bool GeneratePrologue();
167 bool GenerateBody();
168 bool GenerateDeferredCode();
169 bool GenerateSafepointTable();
170
171 void CallCode(Handle<Code> code,
172 RelocInfo::Mode mode,
173 LInstruction* instr);
174 void CallRuntime(Runtime::Function* function,
175 int num_arguments,
176 LInstruction* instr);
177 void CallRuntime(Runtime::FunctionId id,
178 int num_arguments,
179 LInstruction* instr) {
180 Runtime::Function* function = Runtime::FunctionForId(id);
181 CallRuntime(function, num_arguments, instr);
182 }
183
184 // Generate a direct call to a known function. Expects the function
185 // to be in edi.
186 void CallKnownFunction(Handle<JSFunction> function,
187 int arity,
188 LInstruction* instr);
189
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000190 void LoadHeapObject(Register result, Handle<HeapObject> object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000191
192 void RegisterLazyDeoptimization(LInstruction* instr);
193 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
194 void DeoptimizeIf(Condition cc, LEnvironment* environment);
195
196 void AddToTranslation(Translation* translation,
197 LOperand* op,
198 bool is_tagged);
199 void PopulateDeoptimizationData(Handle<Code> code);
200 int DefineDeoptimizationLiteral(Handle<Object> literal);
201
202 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
203
204 Register ToRegister(int index) const;
205 DoubleRegister ToDoubleRegister(int index) const;
206
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000207 // Specific math operations - used from DoUnaryMathOperation.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000208 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000209 void DoMathAbs(LUnaryMathOperation* instr);
210 void DoMathFloor(LUnaryMathOperation* instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000211 void DoMathRound(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000212 void DoMathSqrt(LUnaryMathOperation* instr);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000213 void DoMathLog(LUnaryMathOperation* instr);
214 void DoMathCos(LUnaryMathOperation* instr);
215 void DoMathSin(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000216
217 // Support for recording safepoint and position information.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000218 void RecordSafepoint(LPointerMap* pointers,
219 Safepoint::Kind kind,
220 int arguments,
221 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000222 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000223 void RecordSafepoint(int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000224 void RecordSafepointWithRegisters(LPointerMap* pointers,
225 int arguments,
226 int deoptimization_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000227 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
228 int arguments,
229 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000230 void RecordPosition(int position);
231
232 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
233 void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
234 void EmitBranch(int left_block, int right_block, Condition cc);
235 void EmitCmpI(LOperand* left, LOperand* right);
236 void EmitNumberUntagD(Register input,
237 DoubleRegister result,
238 LEnvironment* env);
239
240 // Emits optimized code for typeof x == "y". Modifies input register.
241 // Returns the condition on which a final split to
242 // true and false label should be made, to optimize fallthrough.
243 Condition EmitTypeofIs(Label* true_label, Label* false_label,
244 Register input, Handle<String> type_name);
245
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000246 // Emits optimized code for %_IsObject(x). Preserves input register.
247 // Returns the condition on which a final split to
248 // true and false label should be made, to optimize fallthrough.
249 Condition EmitIsObject(Register input,
250 Register temp1,
251 Register temp2,
252 Label* is_not_object,
253 Label* is_object);
254
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000255 // Emits optimized code for %_IsConstructCall().
256 // Caller should branch on equal condition.
257 void EmitIsConstructCall(Register temp1, Register temp2);
258
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000259 LChunk* const chunk_;
260 MacroAssembler* const masm_;
261 CompilationInfo* const info_;
262
263 int current_block_;
264 int current_instruction_;
265 const ZoneList<LInstruction*>* instructions_;
266 ZoneList<LEnvironment*> deoptimizations_;
267 ZoneList<Handle<Object> > deoptimization_literals_;
268 int inlined_function_count_;
269 Scope* const scope_;
270 Status status_;
271 TranslationBuffer translations_;
272 ZoneList<LDeferredCode*> deferred_;
273 int osr_pc_offset_;
274
275 // Builder that keeps track of safepoints in the code. The table
276 // itself is emitted at the end of the generated code.
277 SafepointTableBuilder safepoints_;
278
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000279 // Compiler from a set of parallel moves to a sequential list of moves.
280 LGapResolver resolver_;
281
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000282 friend class LDeferredCode;
283 friend class LEnvironment;
284 friend class SafepointGenerator;
285 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
286};
287
288
289class LDeferredCode: public ZoneObject {
290 public:
291 explicit LDeferredCode(LCodeGen* codegen)
292 : codegen_(codegen), external_exit_(NULL) {
293 codegen->AddDeferredCode(this);
294 }
295
296 virtual ~LDeferredCode() { }
297 virtual void Generate() = 0;
298
299 void SetExit(Label *exit) { external_exit_ = exit; }
300 Label* entry() { return &entry_; }
301 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
302
303 protected:
304 LCodeGen* codegen() const { return codegen_; }
305 MacroAssembler* masm() const { return codegen_->masm(); }
306
307 private:
308 LCodeGen* codegen_;
309 Label entry_;
310 Label exit_;
311 Label* external_exit_;
312};
313
314} } // namespace v8::internal
315
316#endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_