blob: 7bc6689f76379dccbb8b9d916d4ffd4350d0279d [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"
32
33#include "deoptimizer.h"
34#include "safepoint-table.h"
35#include "scopes.h"
36
37namespace v8 {
38namespace internal {
39
40// Forward declarations.
41class LDeferredCode;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000042class LGapNode;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000043class SafepointGenerator;
44
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000045class LGapResolver BASE_EMBEDDED {
46 public:
47 LGapResolver();
48 const ZoneList<LMoveOperands>* Resolve(const ZoneList<LMoveOperands>* moves,
49 LOperand* marker_operand);
50
51 private:
52 LGapNode* LookupNode(LOperand* operand);
53 bool CanReach(LGapNode* a, LGapNode* b, int visited_id);
54 bool CanReach(LGapNode* a, LGapNode* b);
55 void RegisterMove(LMoveOperands move);
56 void AddResultMove(LOperand* from, LOperand* to);
57 void AddResultMove(LGapNode* from, LGapNode* to);
58 void ResolveCycle(LGapNode* start, LOperand* marker_operand);
59
60 ZoneList<LGapNode*> nodes_;
61 ZoneList<LGapNode*> identified_cycles_;
62 ZoneList<LMoveOperands> result_;
63 int next_visited_id_;
64};
65
kasperl@chromium.orga5551262010-12-07 12:49:48 +000066
67class LCodeGen BASE_EMBEDDED {
68 public:
69 LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
70 : chunk_(chunk),
71 masm_(assembler),
72 info_(info),
73 current_block_(-1),
74 current_instruction_(-1),
75 instructions_(chunk->instructions()),
76 deoptimizations_(4),
77 deoptimization_literals_(8),
78 inlined_function_count_(0),
79 scope_(chunk->graph()->info()->scope()),
80 status_(UNUSED),
81 deferred_(8),
82 osr_pc_offset_(-1) {
83 PopulateDeoptimizationLiteralsWithInlinedFunctions();
84 }
85
86 // Try to generate code for the entire chunk, but it may fail if the
87 // chunk contains constructs we cannot handle. Returns true if the
88 // code generation attempt succeeded.
89 bool GenerateCode();
90
91 // Finish the code by setting stack height, safepoint, and bailout
92 // information on it.
93 void FinishCode(Handle<Code> code);
94
95 // Deferred code support.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000096 template<int T>
97 void DoDeferredGenericBinaryStub(LTemplateInstruction<1, 2, T>* instr,
98 Token::Value op);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000099 void DoDeferredNumberTagD(LNumberTagD* instr);
100 void DoDeferredNumberTagI(LNumberTagI* instr);
101 void DoDeferredTaggedToI(LTaggedToI* instr);
102 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
103 void DoDeferredStackCheck(LGoto* instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000104 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
105 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
106 Label* map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000107
108 // Parallel move support.
109 void DoParallelMove(LParallelMove* move);
110
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000111 // Emit frame translation commands for an environment.
112 void WriteTranslation(LEnvironment* environment, Translation* translation);
113
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000114 // Declare methods that deal with the individual node types.
115#define DECLARE_DO(type) void Do##type(L##type* node);
116 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
117#undef DECLARE_DO
118
119 private:
120 enum Status {
121 UNUSED,
122 GENERATING,
123 DONE,
124 ABORTED
125 };
126
127 bool is_unused() const { return status_ == UNUSED; }
128 bool is_generating() const { return status_ == GENERATING; }
129 bool is_done() const { return status_ == DONE; }
130 bool is_aborted() const { return status_ == ABORTED; }
131
132 LChunk* chunk() const { return chunk_; }
133 Scope* scope() const { return scope_; }
134 HGraph* graph() const { return chunk_->graph(); }
135 MacroAssembler* masm() const { return masm_; }
136
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000137 Register scratch0() { return r9; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000138 DwVfpRegister double_scratch0() { return d0; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000139
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000140 int GetNextEmittedBlock(int block);
141 LInstruction* GetNextInstruction();
142
143 void EmitClassOfTest(Label* if_true,
144 Label* if_false,
145 Handle<String> class_name,
146 Register input,
147 Register temporary,
148 Register temporary2);
149
150 int StackSlotCount() const { return chunk()->spill_slot_count(); }
151 int ParameterCount() const { return scope()->num_parameters(); }
152
153 void Abort(const char* format, ...);
154 void Comment(const char* format, ...);
155
156 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
157
158 // Code generation passes. Returns true if code generation should
159 // continue.
160 bool GeneratePrologue();
161 bool GenerateBody();
162 bool GenerateDeferredCode();
163 bool GenerateSafepointTable();
164
165 void CallCode(Handle<Code> code,
166 RelocInfo::Mode mode,
167 LInstruction* instr);
168 void CallRuntime(Runtime::Function* function,
169 int num_arguments,
170 LInstruction* instr);
171 void CallRuntime(Runtime::FunctionId id,
172 int num_arguments,
173 LInstruction* instr) {
174 Runtime::Function* function = Runtime::FunctionForId(id);
175 CallRuntime(function, num_arguments, instr);
176 }
177
178 // Generate a direct call to a known function. Expects the function
179 // to be in edi.
180 void CallKnownFunction(Handle<JSFunction> function,
181 int arity,
182 LInstruction* instr);
183
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000184 void LoadHeapObject(Register result, Handle<HeapObject> object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000185
186 void RegisterLazyDeoptimization(LInstruction* instr);
187 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
188 void DeoptimizeIf(Condition cc, LEnvironment* environment);
189
190 void AddToTranslation(Translation* translation,
191 LOperand* op,
192 bool is_tagged);
193 void PopulateDeoptimizationData(Handle<Code> code);
194 int DefineDeoptimizationLiteral(Handle<Object> literal);
195
196 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
197
198 Register ToRegister(int index) const;
199 DoubleRegister ToDoubleRegister(int index) const;
200
201 // LOperand must be a register.
202 Register ToRegister(LOperand* op) const;
203
204 // LOperand is loaded into scratch, unless already a register.
205 Register EmitLoadRegister(LOperand* op, Register scratch);
206
207 // LOperand must be a double register.
208 DoubleRegister ToDoubleRegister(LOperand* op) const;
209
210 // LOperand is loaded into dbl_scratch, unless already a double register.
211 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
212 SwVfpRegister flt_scratch,
213 DoubleRegister dbl_scratch);
214
215 int ToInteger32(LConstantOperand* op) const;
216 Operand ToOperand(LOperand* op);
217 MemOperand ToMemOperand(LOperand* op) const;
218
219 // Specific math operations - used from DoUnaryMathOperation.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000220 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000221 void DoMathAbs(LUnaryMathOperation* instr);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000222 void EmitVFPTruncate(VFPRoundingMode rounding_mode,
223 SwVfpRegister result,
224 DwVfpRegister double_input,
225 Register scratch1,
226 Register scratch2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000227 void DoMathFloor(LUnaryMathOperation* instr);
228 void DoMathSqrt(LUnaryMathOperation* instr);
229
230 // Support for recording safepoint and position information.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000231 void RecordSafepoint(LPointerMap* pointers,
232 Safepoint::Kind kind,
233 int arguments,
234 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000235 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
236 void RecordSafepointWithRegisters(LPointerMap* pointers,
237 int arguments,
238 int deoptimization_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000239 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
240 int arguments,
241 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000242 void RecordPosition(int position);
243
244 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
245 void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
246 void EmitBranch(int left_block, int right_block, Condition cc);
247 void EmitCmpI(LOperand* left, LOperand* right);
248 void EmitNumberUntagD(Register input,
249 DoubleRegister result,
250 LEnvironment* env);
251
252 // Emits optimized code for typeof x == "y". Modifies input register.
253 // Returns the condition on which a final split to
254 // true and false label should be made, to optimize fallthrough.
255 Condition EmitTypeofIs(Label* true_label, Label* false_label,
256 Register input, Handle<String> type_name);
257
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000258 // Emits optimized code for %_IsObject(x). Preserves input register.
259 // Returns the condition on which a final split to
260 // true and false label should be made, to optimize fallthrough.
261 Condition EmitIsObject(Register input,
262 Register temp1,
263 Register temp2,
264 Label* is_not_object,
265 Label* is_object);
266
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000267 // Emits optimized code for %_IsConstructCall().
268 // Caller should branch on equal condition.
269 void EmitIsConstructCall(Register temp1, Register temp2);
270
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000271 LChunk* const chunk_;
272 MacroAssembler* const masm_;
273 CompilationInfo* const info_;
274
275 int current_block_;
276 int current_instruction_;
277 const ZoneList<LInstruction*>* instructions_;
278 ZoneList<LEnvironment*> deoptimizations_;
279 ZoneList<Handle<Object> > deoptimization_literals_;
280 int inlined_function_count_;
281 Scope* const scope_;
282 Status status_;
283 TranslationBuffer translations_;
284 ZoneList<LDeferredCode*> deferred_;
285 int osr_pc_offset_;
286
287 // Builder that keeps track of safepoints in the code. The table
288 // itself is emitted at the end of the generated code.
289 SafepointTableBuilder safepoints_;
290
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000291 // Compiler from a set of parallel moves to a sequential list of moves.
292 LGapResolver resolver_;
293
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 friend class LDeferredCode;
295 friend class LEnvironment;
296 friend class SafepointGenerator;
297 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
298};
299
300
301class LDeferredCode: public ZoneObject {
302 public:
303 explicit LDeferredCode(LCodeGen* codegen)
304 : codegen_(codegen), external_exit_(NULL) {
305 codegen->AddDeferredCode(this);
306 }
307
308 virtual ~LDeferredCode() { }
309 virtual void Generate() = 0;
310
311 void SetExit(Label *exit) { external_exit_ = exit; }
312 Label* entry() { return &entry_; }
313 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
314
315 protected:
316 LCodeGen* codegen() const { return codegen_; }
317 MacroAssembler* masm() const { return codegen_->masm(); }
318
319 private:
320 LCodeGen* codegen_;
321 Label entry_;
322 Label exit_;
323 Label* external_exit_;
324};
325
326} } // namespace v8::internal
327
328#endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_