blob: ead84890346403d48e5170c35fec8fea93339a3a [file] [log] [blame]
Ben Murdochb8e0da22011-05-16 14:20:40 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002// 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"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010032#include "arm/lithium-gap-resolver-arm.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#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
Ben Murdochb0fe1622011-05-05 13:52:32 +010044class 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),
Ben Murdoch257744e2011-11-30 15:57:28 +000054 deopt_jump_table_(4),
Ben Murdochb0fe1622011-05-05 13:52:32 +010055 deoptimization_literals_(8),
56 inlined_function_count_(0),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010057 scope_(info->scope()),
Ben Murdochb0fe1622011-05-05 13:52:32 +010058 status_(UNUSED),
59 deferred_(8),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010060 osr_pc_offset_(-1),
Ben Murdoch8b112d22011-06-08 16:22:53 +010061 resolver_(this),
62 expected_safepoint_kind_(Safepoint::kSimple) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010063 PopulateDeoptimizationLiteralsWithInlinedFunctions();
64 }
65
Ben Murdoche0cee9b2011-05-25 10:26:03 +010066
67 // Simple accessors.
68 MacroAssembler* masm() const { return masm_; }
69 CompilationInfo* info() const { return info_; }
Steve Block44f0eee2011-05-26 01:26:41 +010070 Isolate* isolate() const { return info_->isolate(); }
71 Factory* factory() const { return isolate()->factory(); }
72 Heap* heap() const { return isolate()->heap(); }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010073
74 // Support for converting LOperands to assembler types.
75 // LOperand must be a register.
76 Register ToRegister(LOperand* op) const;
77
78 // LOperand is loaded into scratch, unless already a register.
79 Register EmitLoadRegister(LOperand* op, Register scratch);
80
81 // LOperand must be a double register.
82 DoubleRegister ToDoubleRegister(LOperand* op) const;
83
84 // LOperand is loaded into dbl_scratch, unless already a double register.
85 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
86 SwVfpRegister flt_scratch,
87 DoubleRegister dbl_scratch);
88 int ToInteger32(LConstantOperand* op) const;
89 Operand ToOperand(LOperand* op);
90 MemOperand ToMemOperand(LOperand* op) const;
91 // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
92 MemOperand ToHighMemOperand(LOperand* op) const;
93
Ben Murdochb0fe1622011-05-05 13:52:32 +010094 // Try to generate code for the entire chunk, but it may fail if the
95 // chunk contains constructs we cannot handle. Returns true if the
96 // code generation attempt succeeded.
97 bool GenerateCode();
98
99 // Finish the code by setting stack height, safepoint, and bailout
100 // information on it.
101 void FinishCode(Handle<Code> code);
102
103 // Deferred code support.
Steve Block1e0659c2011-05-24 12:43:12 +0100104 template<int T>
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100105 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
106 Token::Value op);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100107 void DoDeferredNumberTagD(LNumberTagD* instr);
108 void DoDeferredNumberTagI(LNumberTagI* instr);
109 void DoDeferredTaggedToI(LTaggedToI* instr);
110 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000111 void DoDeferredStackCheck(LStackCheck* instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100112 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100113 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100114 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
115 Label* map_check);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100116
117 // Parallel move support.
118 void DoParallelMove(LParallelMove* move);
Ben Murdoch257744e2011-11-30 15:57:28 +0000119 void DoGap(LGap* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100120
Ben Murdochb8e0da22011-05-16 14:20:40 +0100121 // Emit frame translation commands for an environment.
122 void WriteTranslation(LEnvironment* environment, Translation* translation);
123
Ben Murdochb0fe1622011-05-05 13:52:32 +0100124 // Declare methods that deal with the individual node types.
125#define DECLARE_DO(type) void Do##type(L##type* node);
126 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
127#undef DECLARE_DO
128
129 private:
130 enum Status {
131 UNUSED,
132 GENERATING,
133 DONE,
134 ABORTED
135 };
136
137 bool is_unused() const { return status_ == UNUSED; }
138 bool is_generating() const { return status_ == GENERATING; }
139 bool is_done() const { return status_ == DONE; }
140 bool is_aborted() const { return status_ == ABORTED; }
141
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100142 int strict_mode_flag() const {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100143 return info()->is_strict_mode() ? kStrictMode : kNonStrictMode;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100144 }
145
Ben Murdochb0fe1622011-05-05 13:52:32 +0100146 LChunk* chunk() const { return chunk_; }
147 Scope* scope() const { return scope_; }
148 HGraph* graph() const { return chunk_->graph(); }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100149
Steve Block9fac8402011-05-12 15:51:54 +0100150 Register scratch0() { return r9; }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000151 DwVfpRegister double_scratch0() { return d15; }
Steve Block9fac8402011-05-12 15:51:54 +0100152
Ben Murdochb0fe1622011-05-05 13:52:32 +0100153 int GetNextEmittedBlock(int block);
154 LInstruction* GetNextInstruction();
155
156 void EmitClassOfTest(Label* if_true,
157 Label* if_false,
158 Handle<String> class_name,
159 Register input,
160 Register temporary,
161 Register temporary2);
162
Ben Murdoch257744e2011-11-30 15:57:28 +0000163 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
164 int GetParameterCount() const { return scope()->num_parameters(); }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100165
166 void Abort(const char* format, ...);
167 void Comment(const char* format, ...);
168
169 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
170
171 // Code generation passes. Returns true if code generation should
172 // continue.
173 bool GeneratePrologue();
174 bool GenerateBody();
175 bool GenerateDeferredCode();
Ben Murdoch257744e2011-11-30 15:57:28 +0000176 bool GenerateDeoptJumpTable();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177 bool GenerateSafepointTable();
178
Ben Murdoch8b112d22011-06-08 16:22:53 +0100179 enum SafepointMode {
180 RECORD_SIMPLE_SAFEPOINT,
181 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
182 };
183
Ben Murdochb0fe1622011-05-05 13:52:32 +0100184 void CallCode(Handle<Code> code,
185 RelocInfo::Mode mode,
186 LInstruction* instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100187
188 void CallCodeGeneric(Handle<Code> code,
189 RelocInfo::Mode mode,
190 LInstruction* instr,
191 SafepointMode safepoint_mode);
192
Steve Block44f0eee2011-05-26 01:26:41 +0100193 void CallRuntime(const Runtime::Function* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100194 int num_arguments,
195 LInstruction* instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100196
Ben Murdochb0fe1622011-05-05 13:52:32 +0100197 void CallRuntime(Runtime::FunctionId id,
198 int num_arguments,
199 LInstruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100200 const Runtime::Function* function = Runtime::FunctionForId(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100201 CallRuntime(function, num_arguments, instr);
202 }
203
Ben Murdoch8b112d22011-06-08 16:22:53 +0100204 void CallRuntimeFromDeferred(Runtime::FunctionId id,
205 int argc,
206 LInstruction* instr);
207
Ben Murdochb0fe1622011-05-05 13:52:32 +0100208 // Generate a direct call to a known function. Expects the function
209 // to be in edi.
210 void CallKnownFunction(Handle<JSFunction> function,
211 int arity,
Ben Murdoch257744e2011-11-30 15:57:28 +0000212 LInstruction* instr,
213 CallKind call_kind);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100214
Ben Murdochb8e0da22011-05-16 14:20:40 +0100215 void LoadHeapObject(Register result, Handle<HeapObject> object);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100216
Ben Murdoch8b112d22011-06-08 16:22:53 +0100217 void RegisterLazyDeoptimization(LInstruction* instr,
218 SafepointMode safepoint_mode);
219
Ben Murdochb0fe1622011-05-05 13:52:32 +0100220 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
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 DoubleRegister ToDoubleRegister(int index) const;
233
Ben Murdochb0fe1622011-05-05 13:52:32 +0100234 // Specific math operations - used from DoUnaryMathOperation.
Steve Block1e0659c2011-05-24 12:43:12 +0100235 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100236 void DoMathAbs(LUnaryMathOperation* instr);
237 void DoMathFloor(LUnaryMathOperation* instr);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100238 void DoMathRound(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100239 void DoMathSqrt(LUnaryMathOperation* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100240 void DoMathPowHalf(LUnaryMathOperation* instr);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100241 void DoMathLog(LUnaryMathOperation* instr);
242 void DoMathCos(LUnaryMathOperation* instr);
243 void DoMathSin(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100244
245 // Support for recording safepoint and position information.
Steve Block1e0659c2011-05-24 12:43:12 +0100246 void RecordSafepoint(LPointerMap* pointers,
247 Safepoint::Kind kind,
248 int arguments,
249 int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100250 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100251 void RecordSafepoint(int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100252 void RecordSafepointWithRegisters(LPointerMap* pointers,
253 int arguments,
254 int deoptimization_index);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100255 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
256 int arguments,
257 int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100258 void RecordPosition(int position);
Steve Block44f0eee2011-05-26 01:26:41 +0100259 int LastSafepointEnd() {
260 return static_cast<int>(safepoints_.GetPcAfterGap());
261 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100262
263 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000264 void EmitGoto(int block);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100265 void EmitBranch(int left_block, int right_block, Condition cc);
266 void EmitCmpI(LOperand* left, LOperand* right);
267 void EmitNumberUntagD(Register input,
268 DoubleRegister result,
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100269 bool deoptimize_on_undefined,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100270 LEnvironment* env);
271
272 // Emits optimized code for typeof x == "y". Modifies input register.
273 // Returns the condition on which a final split to
274 // true and false label should be made, to optimize fallthrough.
275 Condition EmitTypeofIs(Label* true_label, Label* false_label,
276 Register input, Handle<String> type_name);
277
278 // Emits optimized code for %_IsObject(x). Preserves input register.
279 // Returns the condition on which a final split to
280 // true and false label should be made, to optimize fallthrough.
281 Condition EmitIsObject(Register input,
282 Register temp1,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100283 Label* is_not_object,
284 Label* is_object);
285
Steve Block1e0659c2011-05-24 12:43:12 +0100286 // Emits optimized code for %_IsConstructCall().
287 // Caller should branch on equal condition.
288 void EmitIsConstructCall(Register temp1, Register temp2);
289
Ben Murdoch257744e2011-11-30 15:57:28 +0000290 void EmitLoadFieldOrConstantFunction(Register result,
291 Register object,
292 Handle<Map> type,
293 Handle<String> name);
294
295 struct JumpTableEntry {
296 explicit inline JumpTableEntry(Address entry)
297 : label(),
298 address(entry) { }
299 Label label;
300 Address address;
301 };
Steve Block44f0eee2011-05-26 01:26:41 +0100302
Ben Murdochb0fe1622011-05-05 13:52:32 +0100303 LChunk* const chunk_;
304 MacroAssembler* const masm_;
305 CompilationInfo* const info_;
306
307 int current_block_;
308 int current_instruction_;
309 const ZoneList<LInstruction*>* instructions_;
310 ZoneList<LEnvironment*> deoptimizations_;
Ben Murdoch257744e2011-11-30 15:57:28 +0000311 ZoneList<JumpTableEntry> deopt_jump_table_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100312 ZoneList<Handle<Object> > deoptimization_literals_;
313 int inlined_function_count_;
314 Scope* const scope_;
315 Status status_;
316 TranslationBuffer translations_;
317 ZoneList<LDeferredCode*> deferred_;
318 int osr_pc_offset_;
319
320 // Builder that keeps track of safepoints in the code. The table
321 // itself is emitted at the end of the generated code.
322 SafepointTableBuilder safepoints_;
323
Ben Murdochb8e0da22011-05-16 14:20:40 +0100324 // Compiler from a set of parallel moves to a sequential list of moves.
325 LGapResolver resolver_;
326
Ben Murdoch8b112d22011-06-08 16:22:53 +0100327 Safepoint::Kind expected_safepoint_kind_;
328
329 class PushSafepointRegistersScope BASE_EMBEDDED {
330 public:
331 PushSafepointRegistersScope(LCodeGen* codegen,
332 Safepoint::Kind kind)
333 : codegen_(codegen) {
334 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
335 codegen_->expected_safepoint_kind_ = kind;
336
337 switch (codegen_->expected_safepoint_kind_) {
338 case Safepoint::kWithRegisters:
339 codegen_->masm_->PushSafepointRegisters();
340 break;
341 case Safepoint::kWithRegistersAndDoubles:
342 codegen_->masm_->PushSafepointRegistersAndDoubles();
343 break;
344 default:
345 UNREACHABLE();
346 }
347 }
348
349 ~PushSafepointRegistersScope() {
350 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
351 ASSERT((kind & Safepoint::kWithRegisters) != 0);
352 switch (kind) {
353 case Safepoint::kWithRegisters:
354 codegen_->masm_->PopSafepointRegisters();
355 break;
356 case Safepoint::kWithRegistersAndDoubles:
357 codegen_->masm_->PopSafepointRegistersAndDoubles();
358 break;
359 default:
360 UNREACHABLE();
361 }
362 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
363 }
364
365 private:
366 LCodeGen* codegen_;
367 };
368
Ben Murdochb0fe1622011-05-05 13:52:32 +0100369 friend class LDeferredCode;
370 friend class LEnvironment;
371 friend class SafepointGenerator;
372 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
373};
374
375
376class LDeferredCode: public ZoneObject {
377 public:
378 explicit LDeferredCode(LCodeGen* codegen)
379 : codegen_(codegen), external_exit_(NULL) {
380 codegen->AddDeferredCode(this);
381 }
382
383 virtual ~LDeferredCode() { }
384 virtual void Generate() = 0;
385
386 void SetExit(Label *exit) { external_exit_ = exit; }
387 Label* entry() { return &entry_; }
388 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
389
390 protected:
391 LCodeGen* codegen() const { return codegen_; }
392 MacroAssembler* masm() const { return codegen_->masm(); }
393
394 private:
395 LCodeGen* codegen_;
396 Label entry_;
397 Label exit_;
398 Label* external_exit_;
399};
400
401} } // namespace v8::internal
402
403#endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_