blob: 5dfb8e0bf9f0d044612402da55cc8177eef000b7 [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),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000060 resolver_(this),
61 expected_safepoint_kind_(Safepoint::kSimple) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000062 PopulateDeoptimizationLiteralsWithInlinedFunctions();
63 }
64
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000065
66 // Simple accessors.
67 MacroAssembler* masm() const { return masm_; }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000068 CompilationInfo* info() const { return info_; }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000069 Isolate* isolate() const { return info_->isolate(); }
70 Factory* factory() const { return isolate()->factory(); }
71 Heap* heap() const { return isolate()->heap(); }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000072
73 // Support for converting LOperands to assembler types.
74 // LOperand must be a register.
75 Register ToRegister(LOperand* op) const;
76
77 // LOperand is loaded into scratch, unless already a register.
78 Register EmitLoadRegister(LOperand* op, Register scratch);
79
80 // LOperand must be a double register.
81 DoubleRegister ToDoubleRegister(LOperand* op) const;
82
83 // LOperand is loaded into dbl_scratch, unless already a double register.
84 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
85 SwVfpRegister flt_scratch,
86 DoubleRegister dbl_scratch);
87 int ToInteger32(LConstantOperand* op) const;
88 Operand ToOperand(LOperand* op);
89 MemOperand ToMemOperand(LOperand* op) const;
90 // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
91 MemOperand ToHighMemOperand(LOperand* op) const;
92
kasperl@chromium.orga5551262010-12-07 12:49:48 +000093 // 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 // Deferred code support.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000103 template<int T>
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000104 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
105 Token::Value op);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000106 void DoDeferredNumberTagD(LNumberTagD* instr);
107 void DoDeferredNumberTagI(LNumberTagI* instr);
108 void DoDeferredTaggedToI(LTaggedToI* instr);
109 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
110 void DoDeferredStackCheck(LGoto* instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000111 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000112 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000113 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
114 Label* map_check);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000115
116 // Parallel move support.
117 void DoParallelMove(LParallelMove* move);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000118 void DoGap(LGap* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000119
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000120 // Emit frame translation commands for an environment.
121 void WriteTranslation(LEnvironment* environment, Translation* translation);
122
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000123 // Declare methods that deal with the individual node types.
124#define DECLARE_DO(type) void Do##type(L##type* node);
125 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
126#undef DECLARE_DO
127
128 private:
129 enum Status {
130 UNUSED,
131 GENERATING,
132 DONE,
133 ABORTED
134 };
135
136 bool is_unused() const { return status_ == UNUSED; }
137 bool is_generating() const { return status_ == GENERATING; }
138 bool is_done() const { return status_ == DONE; }
139 bool is_aborted() const { return status_ == ABORTED; }
140
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000141 int strict_mode_flag() const {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000142 return info()->is_strict_mode() ? kStrictMode : kNonStrictMode;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000143 }
144
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000145 LChunk* chunk() const { return chunk_; }
146 Scope* scope() const { return scope_; }
147 HGraph* graph() const { return chunk_->graph(); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000148
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000149 Register scratch0() { return r9; }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000150 DwVfpRegister double_scratch0() { return d0; }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000151
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000152 int GetNextEmittedBlock(int block);
153 LInstruction* GetNextInstruction();
154
155 void EmitClassOfTest(Label* if_true,
156 Label* if_false,
157 Handle<String> class_name,
158 Register input,
159 Register temporary,
160 Register temporary2);
161
danno@chromium.org160a7b02011-04-18 15:51:38 +0000162 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
163 int GetParameterCount() const { return scope()->num_parameters(); }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000164
165 void Abort(const char* format, ...);
166 void Comment(const char* format, ...);
167
168 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
169
170 // Code generation passes. Returns true if code generation should
171 // continue.
172 bool GeneratePrologue();
173 bool GenerateBody();
174 bool GenerateDeferredCode();
175 bool GenerateSafepointTable();
176
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000177 enum SafepointMode {
178 RECORD_SIMPLE_SAFEPOINT,
179 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
180 };
181
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000182 void CallCode(Handle<Code> code,
183 RelocInfo::Mode mode,
184 LInstruction* instr);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000185
186 void CallCodeGeneric(Handle<Code> code,
187 RelocInfo::Mode mode,
188 LInstruction* instr,
189 SafepointMode safepoint_mode);
190
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 void CallRuntime(const Runtime::Function* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000192 int num_arguments,
193 LInstruction* instr);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000194
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000195 void CallRuntime(Runtime::FunctionId id,
196 int num_arguments,
197 LInstruction* instr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000198 const Runtime::Function* function = Runtime::FunctionForId(id);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000199 CallRuntime(function, num_arguments, instr);
200 }
201
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000202 void CallRuntimeFromDeferred(Runtime::FunctionId id,
203 int argc,
204 LInstruction* instr);
205
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000206 // Generate a direct call to a known function. Expects the function
207 // to be in edi.
208 void CallKnownFunction(Handle<JSFunction> function,
209 int arity,
210 LInstruction* instr);
211
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000212 void LoadHeapObject(Register result, Handle<HeapObject> object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000213
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000214 void RegisterLazyDeoptimization(LInstruction* instr,
215 SafepointMode safepoint_mode);
216
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000217 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
218 void DeoptimizeIf(Condition cc, LEnvironment* environment);
219
220 void AddToTranslation(Translation* translation,
221 LOperand* op,
222 bool is_tagged);
223 void PopulateDeoptimizationData(Handle<Code> code);
224 int DefineDeoptimizationLiteral(Handle<Object> literal);
225
226 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
227
228 Register ToRegister(int index) const;
229 DoubleRegister ToDoubleRegister(int index) const;
230
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000231 // Specific math operations - used from DoUnaryMathOperation.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000232 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000233 void DoMathAbs(LUnaryMathOperation* instr);
234 void DoMathFloor(LUnaryMathOperation* instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000235 void DoMathRound(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000236 void DoMathSqrt(LUnaryMathOperation* instr);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000237 void DoMathPowHalf(LUnaryMathOperation* instr);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000238 void DoMathLog(LUnaryMathOperation* instr);
239 void DoMathCos(LUnaryMathOperation* instr);
240 void DoMathSin(LUnaryMathOperation* instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000241
242 // Support for recording safepoint and position information.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000243 void RecordSafepoint(LPointerMap* pointers,
244 Safepoint::Kind kind,
245 int arguments,
246 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000247 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000248 void RecordSafepoint(int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000249 void RecordSafepointWithRegisters(LPointerMap* pointers,
250 int arguments,
251 int deoptimization_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000252 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
253 int arguments,
254 int deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000255 void RecordPosition(int position);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000256 int LastSafepointEnd() {
257 return static_cast<int>(safepoints_.GetPcAfterGap());
258 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000259
260 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
261 void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
262 void EmitBranch(int left_block, int right_block, Condition cc);
263 void EmitCmpI(LOperand* left, LOperand* right);
264 void EmitNumberUntagD(Register input,
265 DoubleRegister result,
266 LEnvironment* env);
267
268 // Emits optimized code for typeof x == "y". Modifies input register.
269 // Returns the condition on which a final split to
270 // true and false label should be made, to optimize fallthrough.
271 Condition EmitTypeofIs(Label* true_label, Label* false_label,
272 Register input, Handle<String> type_name);
273
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000274 // Emits optimized code for %_IsObject(x). Preserves 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 EmitIsObject(Register input,
278 Register temp1,
279 Register temp2,
280 Label* is_not_object,
281 Label* is_object);
282
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000283 // Emits optimized code for %_IsConstructCall().
284 // Caller should branch on equal condition.
285 void EmitIsConstructCall(Register temp1, Register temp2);
286
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000287 void EmitLoadField(Register result,
288 Register object,
289 Handle<Map> type,
290 Handle<String> name);
291
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292 LChunk* const chunk_;
293 MacroAssembler* const masm_;
294 CompilationInfo* const info_;
295
296 int current_block_;
297 int current_instruction_;
298 const ZoneList<LInstruction*>* instructions_;
299 ZoneList<LEnvironment*> deoptimizations_;
300 ZoneList<Handle<Object> > deoptimization_literals_;
301 int inlined_function_count_;
302 Scope* const scope_;
303 Status status_;
304 TranslationBuffer translations_;
305 ZoneList<LDeferredCode*> deferred_;
306 int osr_pc_offset_;
307
308 // Builder that keeps track of safepoints in the code. The table
309 // itself is emitted at the end of the generated code.
310 SafepointTableBuilder safepoints_;
311
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000312 // Compiler from a set of parallel moves to a sequential list of moves.
313 LGapResolver resolver_;
314
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000315 Safepoint::Kind expected_safepoint_kind_;
316
317 class PushSafepointRegistersScope BASE_EMBEDDED {
318 public:
319 PushSafepointRegistersScope(LCodeGen* codegen,
320 Safepoint::Kind kind)
321 : codegen_(codegen) {
322 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
323 codegen_->expected_safepoint_kind_ = kind;
324
325 switch (codegen_->expected_safepoint_kind_) {
326 case Safepoint::kWithRegisters:
327 codegen_->masm_->PushSafepointRegisters();
328 break;
329 case Safepoint::kWithRegistersAndDoubles:
330 codegen_->masm_->PushSafepointRegistersAndDoubles();
331 break;
332 default:
333 UNREACHABLE();
334 }
335 }
336
337 ~PushSafepointRegistersScope() {
338 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
339 ASSERT((kind & Safepoint::kWithRegisters) != 0);
340 switch (kind) {
341 case Safepoint::kWithRegisters:
342 codegen_->masm_->PopSafepointRegisters();
343 break;
344 case Safepoint::kWithRegistersAndDoubles:
345 codegen_->masm_->PopSafepointRegistersAndDoubles();
346 break;
347 default:
348 UNREACHABLE();
349 }
350 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
351 }
352
353 private:
354 LCodeGen* codegen_;
355 };
356
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000357 friend class LDeferredCode;
358 friend class LEnvironment;
359 friend class SafepointGenerator;
360 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
361};
362
363
364class LDeferredCode: public ZoneObject {
365 public:
366 explicit LDeferredCode(LCodeGen* codegen)
367 : codegen_(codegen), external_exit_(NULL) {
368 codegen->AddDeferredCode(this);
369 }
370
371 virtual ~LDeferredCode() { }
372 virtual void Generate() = 0;
373
374 void SetExit(Label *exit) { external_exit_ = exit; }
375 Label* entry() { return &entry_; }
376 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
377
378 protected:
379 LCodeGen* codegen() const { return codegen_; }
380 MacroAssembler* masm() const { return codegen_->masm(); }
381
382 private:
383 LCodeGen* codegen_;
384 Label entry_;
385 Label exit_;
386 Label* external_exit_;
387};
388
389} } // namespace v8::internal
390
391#endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_