blob: 1110ea6a49651a8d1ef1d5ef08d21e6f87fd9e16 [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),
54 deoptimization_literals_(8),
55 inlined_function_count_(0),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010056 scope_(info->scope()),
Ben Murdochb0fe1622011-05-05 13:52:32 +010057 status_(UNUSED),
58 deferred_(8),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010059 osr_pc_offset_(-1),
Ben Murdoch8b112d22011-06-08 16:22:53 +010060 resolver_(this),
61 expected_safepoint_kind_(Safepoint::kSimple) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010062 PopulateDeoptimizationLiteralsWithInlinedFunctions();
63 }
64
Ben Murdoche0cee9b2011-05-25 10:26:03 +010065
66 // Simple accessors.
67 MacroAssembler* masm() const { return masm_; }
68 CompilationInfo* info() const { return info_; }
Steve Block44f0eee2011-05-26 01:26:41 +010069 Isolate* isolate() const { return info_->isolate(); }
70 Factory* factory() const { return isolate()->factory(); }
71 Heap* heap() const { return isolate()->heap(); }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010072
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
Ben Murdochb0fe1622011-05-05 13:52:32 +010093 // 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.
Steve Block1e0659c2011-05-24 12:43:12 +0100103 template<int T>
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100104 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
105 Token::Value op);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100106 void DoDeferredNumberTagD(LNumberTagD* instr);
107 void DoDeferredNumberTagI(LNumberTagI* instr);
108 void DoDeferredTaggedToI(LTaggedToI* instr);
109 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
110 void DoDeferredStackCheck(LGoto* instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100111 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100112 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
Steve Block1e0659c2011-05-24 12:43:12 +0100113 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
114 Label* map_check);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100115
116 // Parallel move support.
117 void DoParallelMove(LParallelMove* move);
118
Ben Murdochb8e0da22011-05-16 14:20:40 +0100119 // Emit frame translation commands for an environment.
120 void WriteTranslation(LEnvironment* environment, Translation* translation);
121
Ben Murdochb0fe1622011-05-05 13:52:32 +0100122 // Declare methods that deal with the individual node types.
123#define DECLARE_DO(type) void Do##type(L##type* node);
124 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
125#undef DECLARE_DO
126
127 private:
128 enum Status {
129 UNUSED,
130 GENERATING,
131 DONE,
132 ABORTED
133 };
134
135 bool is_unused() const { return status_ == UNUSED; }
136 bool is_generating() const { return status_ == GENERATING; }
137 bool is_done() const { return status_ == DONE; }
138 bool is_aborted() const { return status_ == ABORTED; }
139
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100140 int strict_mode_flag() const {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100141 return info()->is_strict_mode() ? kStrictMode : kNonStrictMode;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100142 }
143
Ben Murdochb0fe1622011-05-05 13:52:32 +0100144 LChunk* chunk() const { return chunk_; }
145 Scope* scope() const { return scope_; }
146 HGraph* graph() const { return chunk_->graph(); }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100147
Steve Block9fac8402011-05-12 15:51:54 +0100148 Register scratch0() { return r9; }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100149 DwVfpRegister double_scratch0() { return d0; }
Steve Block9fac8402011-05-12 15:51:54 +0100150
Ben Murdochb0fe1622011-05-05 13:52:32 +0100151 int GetNextEmittedBlock(int block);
152 LInstruction* GetNextInstruction();
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
Ben Murdoch8b112d22011-06-08 16:22:53 +0100161 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
162 int GetParameterCount() const { return scope()->num_parameters(); }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100163
164 void Abort(const char* format, ...);
165 void Comment(const char* format, ...);
166
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 bool GenerateSafepointTable();
175
Ben Murdoch8b112d22011-06-08 16:22:53 +0100176 enum SafepointMode {
177 RECORD_SIMPLE_SAFEPOINT,
178 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
179 };
180
Ben Murdochb0fe1622011-05-05 13:52:32 +0100181 void CallCode(Handle<Code> code,
182 RelocInfo::Mode mode,
183 LInstruction* instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100184
185 void CallCodeGeneric(Handle<Code> code,
186 RelocInfo::Mode mode,
187 LInstruction* instr,
188 SafepointMode safepoint_mode);
189
Steve Block44f0eee2011-05-26 01:26:41 +0100190 void CallRuntime(const Runtime::Function* function,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100191 int num_arguments,
192 LInstruction* instr);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100193
Ben Murdochb0fe1622011-05-05 13:52:32 +0100194 void CallRuntime(Runtime::FunctionId id,
195 int num_arguments,
196 LInstruction* instr) {
Steve Block44f0eee2011-05-26 01:26:41 +0100197 const Runtime::Function* function = Runtime::FunctionForId(id);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100198 CallRuntime(function, num_arguments, instr);
199 }
200
Ben Murdoch8b112d22011-06-08 16:22:53 +0100201 void CallRuntimeFromDeferred(Runtime::FunctionId id,
202 int argc,
203 LInstruction* instr);
204
Ben Murdochb0fe1622011-05-05 13:52:32 +0100205 // Generate a direct call to a known function. Expects the function
206 // to be in edi.
207 void CallKnownFunction(Handle<JSFunction> function,
208 int arity,
209 LInstruction* instr);
210
Ben Murdochb8e0da22011-05-16 14:20:40 +0100211 void LoadHeapObject(Register result, Handle<HeapObject> object);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212
Ben Murdoch8b112d22011-06-08 16:22:53 +0100213 void RegisterLazyDeoptimization(LInstruction* instr,
214 SafepointMode safepoint_mode);
215
Ben Murdochb0fe1622011-05-05 13:52:32 +0100216 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
217 void DeoptimizeIf(Condition cc, LEnvironment* environment);
218
219 void AddToTranslation(Translation* translation,
220 LOperand* op,
221 bool is_tagged);
222 void PopulateDeoptimizationData(Handle<Code> code);
223 int DefineDeoptimizationLiteral(Handle<Object> literal);
224
225 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
226
227 Register ToRegister(int index) const;
228 DoubleRegister ToDoubleRegister(int index) const;
229
Ben Murdochb0fe1622011-05-05 13:52:32 +0100230 // Specific math operations - used from DoUnaryMathOperation.
Steve Block1e0659c2011-05-24 12:43:12 +0100231 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100232 void DoMathAbs(LUnaryMathOperation* instr);
233 void DoMathFloor(LUnaryMathOperation* instr);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100234 void DoMathRound(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100235 void DoMathSqrt(LUnaryMathOperation* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100236 void DoMathPowHalf(LUnaryMathOperation* instr);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100237 void DoMathLog(LUnaryMathOperation* instr);
238 void DoMathCos(LUnaryMathOperation* instr);
239 void DoMathSin(LUnaryMathOperation* instr);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100240
241 // Support for recording safepoint and position information.
Steve Block1e0659c2011-05-24 12:43:12 +0100242 void RecordSafepoint(LPointerMap* pointers,
243 Safepoint::Kind kind,
244 int arguments,
245 int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100246 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100247 void RecordSafepoint(int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100248 void RecordSafepointWithRegisters(LPointerMap* pointers,
249 int arguments,
250 int deoptimization_index);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100251 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
252 int arguments,
253 int deoptimization_index);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100254 void RecordPosition(int position);
Steve Block44f0eee2011-05-26 01:26:41 +0100255 int LastSafepointEnd() {
256 return static_cast<int>(safepoints_.GetPcAfterGap());
257 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100258
259 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
260 void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
261 void EmitBranch(int left_block, int right_block, Condition cc);
262 void EmitCmpI(LOperand* left, LOperand* right);
263 void EmitNumberUntagD(Register input,
264 DoubleRegister result,
265 LEnvironment* env);
266
267 // Emits optimized code for typeof x == "y". Modifies input register.
268 // Returns the condition on which a final split to
269 // true and false label should be made, to optimize fallthrough.
270 Condition EmitTypeofIs(Label* true_label, Label* false_label,
271 Register input, Handle<String> type_name);
272
273 // Emits optimized code for %_IsObject(x). Preserves input register.
274 // Returns the condition on which a final split to
275 // true and false label should be made, to optimize fallthrough.
276 Condition EmitIsObject(Register input,
277 Register temp1,
278 Register temp2,
279 Label* is_not_object,
280 Label* is_object);
281
Steve Block1e0659c2011-05-24 12:43:12 +0100282 // Emits optimized code for %_IsConstructCall().
283 // Caller should branch on equal condition.
284 void EmitIsConstructCall(Register temp1, Register temp2);
285
Steve Block44f0eee2011-05-26 01:26:41 +0100286 void EmitLoadField(Register result,
287 Register object,
288 Handle<Map> type,
289 Handle<String> name);
290
Ben Murdochb0fe1622011-05-05 13:52:32 +0100291 LChunk* const chunk_;
292 MacroAssembler* const masm_;
293 CompilationInfo* const info_;
294
295 int current_block_;
296 int current_instruction_;
297 const ZoneList<LInstruction*>* instructions_;
298 ZoneList<LEnvironment*> deoptimizations_;
299 ZoneList<Handle<Object> > deoptimization_literals_;
300 int inlined_function_count_;
301 Scope* const scope_;
302 Status status_;
303 TranslationBuffer translations_;
304 ZoneList<LDeferredCode*> deferred_;
305 int osr_pc_offset_;
306
307 // Builder that keeps track of safepoints in the code. The table
308 // itself is emitted at the end of the generated code.
309 SafepointTableBuilder safepoints_;
310
Ben Murdochb8e0da22011-05-16 14:20:40 +0100311 // Compiler from a set of parallel moves to a sequential list of moves.
312 LGapResolver resolver_;
313
Ben Murdoch8b112d22011-06-08 16:22:53 +0100314 Safepoint::Kind expected_safepoint_kind_;
315
316 class PushSafepointRegistersScope BASE_EMBEDDED {
317 public:
318 PushSafepointRegistersScope(LCodeGen* codegen,
319 Safepoint::Kind kind)
320 : codegen_(codegen) {
321 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
322 codegen_->expected_safepoint_kind_ = kind;
323
324 switch (codegen_->expected_safepoint_kind_) {
325 case Safepoint::kWithRegisters:
326 codegen_->masm_->PushSafepointRegisters();
327 break;
328 case Safepoint::kWithRegistersAndDoubles:
329 codegen_->masm_->PushSafepointRegistersAndDoubles();
330 break;
331 default:
332 UNREACHABLE();
333 }
334 }
335
336 ~PushSafepointRegistersScope() {
337 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
338 ASSERT((kind & Safepoint::kWithRegisters) != 0);
339 switch (kind) {
340 case Safepoint::kWithRegisters:
341 codegen_->masm_->PopSafepointRegisters();
342 break;
343 case Safepoint::kWithRegistersAndDoubles:
344 codegen_->masm_->PopSafepointRegistersAndDoubles();
345 break;
346 default:
347 UNREACHABLE();
348 }
349 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
350 }
351
352 private:
353 LCodeGen* codegen_;
354 };
355
Ben Murdochb0fe1622011-05-05 13:52:32 +0100356 friend class LDeferredCode;
357 friend class LEnvironment;
358 friend class SafepointGenerator;
359 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
360};
361
362
363class LDeferredCode: public ZoneObject {
364 public:
365 explicit LDeferredCode(LCodeGen* codegen)
366 : codegen_(codegen), external_exit_(NULL) {
367 codegen->AddDeferredCode(this);
368 }
369
370 virtual ~LDeferredCode() { }
371 virtual void Generate() = 0;
372
373 void SetExit(Label *exit) { external_exit_ = exit; }
374 Label* entry() { return &entry_; }
375 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
376
377 protected:
378 LCodeGen* codegen() const { return codegen_; }
379 MacroAssembler* masm() const { return codegen_->masm(); }
380
381 private:
382 LCodeGen* codegen_;
383 Label entry_;
384 Label exit_;
385 Label* external_exit_;
386};
387
388} } // namespace v8::internal
389
390#endif // V8_ARM_LITHIUM_CODEGEN_ARM_H_