blob: f9c013c1f5d2bb4cbf8f7cf1cd2ec60c4e0508d6 [file] [log] [blame]
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +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
lrn@chromium.org7516f052011-03-30 08:52:27 +000028#ifndef V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
29#define V8_MIPS_LITHIUM_CODEGEN_MIPS_H_
ager@chromium.org5c838252010-02-19 08:53:10 +000030
lrn@chromium.org7516f052011-03-30 08:52:27 +000031#include "mips/lithium-mips.h"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000032#include "mips/lithium-gap-resolver-mips.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000033#include "deoptimizer.h"
34#include "safepoint-table.h"
35#include "scopes.h"
36
ager@chromium.org5c838252010-02-19 08:53:10 +000037namespace v8 {
38namespace internal {
39
lrn@chromium.org7516f052011-03-30 08:52:27 +000040// Forward declarations.
41class LDeferredCode;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000042class SafepointGenerator;
ager@chromium.org5c838252010-02-19 08:53:10 +000043
lrn@chromium.org7516f052011-03-30 08:52:27 +000044class LCodeGen BASE_EMBEDDED {
45 public:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000046 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 deopt_jump_table_(4),
55 deoptimization_literals_(8),
56 inlined_function_count_(0),
57 scope_(info->scope()),
58 status_(UNUSED),
59 deferred_(8),
60 osr_pc_offset_(-1),
61 resolver_(this),
62 expected_safepoint_kind_(Safepoint::kSimple) {
63 PopulateDeoptimizationLiteralsWithInlinedFunctions();
64 }
65
66
67 // Simple accessors.
68 MacroAssembler* masm() const { return masm_; }
69 CompilationInfo* info() const { return info_; }
70 Isolate* isolate() const { return info_->isolate(); }
71 Factory* factory() const { return isolate()->factory(); }
72 Heap* heap() const { return isolate()->heap(); }
73
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 FloatRegister flt_scratch,
87 DoubleRegister dbl_scratch);
88 int ToInteger32(LConstantOperand* op) const;
89 double ToDouble(LConstantOperand* op) const;
90 Operand ToOperand(LOperand* op);
91 MemOperand ToMemOperand(LOperand* op) const;
92 // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
93 MemOperand ToHighMemOperand(LOperand* op) const;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000094
lrn@chromium.org7516f052011-03-30 08:52:27 +000095 // Try to generate code for the entire chunk, but it may fail if the
96 // chunk contains constructs we cannot handle. Returns true if the
97 // code generation attempt succeeded.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000098 bool GenerateCode();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000099
lrn@chromium.org7516f052011-03-30 08:52:27 +0000100 // Finish the code by setting stack height, safepoint, and bailout
101 // information on it.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000102 void FinishCode(Handle<Code> code);
103
104 // Deferred code support.
105 template<int T>
106 void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
107 Token::Value op);
108 void DoDeferredNumberTagD(LNumberTagD* instr);
109 void DoDeferredNumberTagI(LNumberTagI* instr);
110 void DoDeferredTaggedToI(LTaggedToI* instr);
111 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
112 void DoDeferredStackCheck(LStackCheck* instr);
113 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
114 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
115 void DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
116 Label* map_check);
117
118 // Parallel move support.
119 void DoParallelMove(LParallelMove* move);
120 void DoGap(LGap* instr);
121
122 // Emit frame translation commands for an environment.
123 void WriteTranslation(LEnvironment* environment, Translation* translation);
124
125 // Declare methods that deal with the individual node types.
126#define DECLARE_DO(type) void Do##type(L##type* node);
127 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
128#undef DECLARE_DO
129
130 private:
131 enum Status {
132 UNUSED,
133 GENERATING,
134 DONE,
135 ABORTED
136 };
137
138 bool is_unused() const { return status_ == UNUSED; }
139 bool is_generating() const { return status_ == GENERATING; }
140 bool is_done() const { return status_ == DONE; }
141 bool is_aborted() const { return status_ == ABORTED; }
142
143 StrictModeFlag strict_mode_flag() const {
144 return info()->strict_mode_flag();
145 }
146
147 LChunk* chunk() const { return chunk_; }
148 Scope* scope() const { return scope_; }
149 HGraph* graph() const { return chunk_->graph(); }
150
151 Register scratch0() { return lithiumScratchReg; }
152 Register scratch1() { return lithiumScratchReg2; }
153 DoubleRegister double_scratch0() { return lithiumScratchDouble; }
154
155 int GetNextEmittedBlock(int block);
156 LInstruction* GetNextInstruction();
157
158 void EmitClassOfTest(Label* if_true,
159 Label* if_false,
160 Handle<String> class_name,
161 Register input,
162 Register temporary,
163 Register temporary2);
164
165 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
166 int GetParameterCount() const { return scope()->num_parameters(); }
167
168 void Abort(const char* format, ...);
169 void Comment(const char* format, ...);
170
171 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
172
173 // Code generation passes. Returns true if code generation should
174 // continue.
175 bool GeneratePrologue();
176 bool GenerateBody();
177 bool GenerateDeferredCode();
178 bool GenerateDeoptJumpTable();
179 bool GenerateSafepointTable();
180
181 enum SafepointMode {
182 RECORD_SIMPLE_SAFEPOINT,
183 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
184 };
185
186 void CallCode(Handle<Code> code,
187 RelocInfo::Mode mode,
188 LInstruction* instr);
189
190 void CallCodeGeneric(Handle<Code> code,
191 RelocInfo::Mode mode,
192 LInstruction* instr,
193 SafepointMode safepoint_mode);
194
195 void CallRuntime(const Runtime::Function* function,
196 int num_arguments,
197 LInstruction* instr);
198
199 void CallRuntime(Runtime::FunctionId id,
200 int num_arguments,
201 LInstruction* instr) {
202 const Runtime::Function* function = Runtime::FunctionForId(id);
203 CallRuntime(function, num_arguments, instr);
204 }
205
206 void CallRuntimeFromDeferred(Runtime::FunctionId id,
207 int argc,
208 LInstruction* instr);
209
210 // Generate a direct call to a known function. Expects the function
211 // to be in a1.
212 void CallKnownFunction(Handle<JSFunction> function,
213 int arity,
214 LInstruction* instr,
215 CallKind call_kind);
216
217 void LoadHeapObject(Register result, Handle<HeapObject> object);
218
219 void RegisterLazyDeoptimization(LInstruction* instr,
220 SafepointMode safepoint_mode);
221
222 void RegisterEnvironmentForDeoptimization(LEnvironment* environment);
223 void DeoptimizeIf(Condition cc,
224 LEnvironment* environment,
225 Register src1,
226 const Operand& src2);
227
228 void AddToTranslation(Translation* translation,
229 LOperand* op,
230 bool is_tagged);
231 void PopulateDeoptimizationData(Handle<Code> code);
232 int DefineDeoptimizationLiteral(Handle<Object> literal);
233
234 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
235
236 Register ToRegister(int index) const;
237 DoubleRegister ToDoubleRegister(int index) const;
238
239 // Specific math operations - used from DoUnaryMathOperation.
240 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
241 void DoMathAbs(LUnaryMathOperation* instr);
242 void DoMathFloor(LUnaryMathOperation* instr);
243 void DoMathRound(LUnaryMathOperation* instr);
244 void DoMathSqrt(LUnaryMathOperation* instr);
245 void DoMathPowHalf(LUnaryMathOperation* instr);
246 void DoMathLog(LUnaryMathOperation* instr);
247 void DoMathCos(LUnaryMathOperation* instr);
248 void DoMathSin(LUnaryMathOperation* instr);
249
250 // Support for recording safepoint and position information.
251 void RecordSafepoint(LPointerMap* pointers,
252 Safepoint::Kind kind,
253 int arguments,
254 int deoptimization_index);
255 void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
256 void RecordSafepoint(int deoptimization_index);
257 void RecordSafepointWithRegisters(LPointerMap* pointers,
258 int arguments,
259 int deoptimization_index);
260 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
261 int arguments,
262 int deoptimization_index);
263 void RecordPosition(int position);
264 int LastSafepointEnd() {
265 return static_cast<int>(safepoints_.GetPcAfterGap());
266 }
267
268 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
269 void EmitGoto(int block);
270 void EmitBranch(int left_block,
271 int right_block,
272 Condition cc,
273 Register src1,
274 const Operand& src2);
275 void EmitBranchF(int left_block,
276 int right_block,
277 Condition cc,
278 FPURegister src1,
279 FPURegister src2);
280 void EmitCmpI(LOperand* left, LOperand* right);
281 void EmitNumberUntagD(Register input,
282 DoubleRegister result,
283 bool deoptimize_on_undefined,
284 LEnvironment* env);
285
286 // Emits optimized code for typeof x == "y". Modifies input register.
287 // Returns the condition on which a final split to
288 // true and false label should be made, to optimize fallthrough.
289 // Returns two registers in cmp1 and cmp2 that can be used in the
290 // Branch instruction after EmitTypeofIs.
291 Condition EmitTypeofIs(Label* true_label,
292 Label* false_label,
293 Register input,
294 Handle<String> type_name,
295 Register& cmp1,
296 Operand& cmp2);
297
298 // Emits optimized code for %_IsObject(x). Preserves input register.
299 // Returns the condition on which a final split to
300 // true and false label should be made, to optimize fallthrough.
301 Condition EmitIsObject(Register input,
302 Register temp1,
303 Label* is_not_object,
304 Label* is_object);
305
306 // Emits optimized code for %_IsConstructCall().
307 // Caller should branch on equal condition.
308 void EmitIsConstructCall(Register temp1, Register temp2);
309
310 void EmitLoadFieldOrConstantFunction(Register result,
311 Register object,
312 Handle<Map> type,
313 Handle<String> name);
314
315 struct JumpTableEntry {
316 explicit inline JumpTableEntry(Address entry)
317 : label(),
318 address(entry) { }
319 Label label;
320 Address address;
321 };
322
323 LChunk* const chunk_;
324 MacroAssembler* const masm_;
325 CompilationInfo* const info_;
326
327 int current_block_;
328 int current_instruction_;
329 const ZoneList<LInstruction*>* instructions_;
330 ZoneList<LEnvironment*> deoptimizations_;
331 ZoneList<JumpTableEntry> deopt_jump_table_;
332 ZoneList<Handle<Object> > deoptimization_literals_;
333 int inlined_function_count_;
334 Scope* const scope_;
335 Status status_;
336 TranslationBuffer translations_;
337 ZoneList<LDeferredCode*> deferred_;
338 int osr_pc_offset_;
339
340 // Builder that keeps track of safepoints in the code. The table
341 // itself is emitted at the end of the generated code.
342 SafepointTableBuilder safepoints_;
343
344 // Compiler from a set of parallel moves to a sequential list of moves.
345 LGapResolver resolver_;
346
347 Safepoint::Kind expected_safepoint_kind_;
348
349 class PushSafepointRegistersScope BASE_EMBEDDED {
350 public:
351 PushSafepointRegistersScope(LCodeGen* codegen,
352 Safepoint::Kind kind)
353 : codegen_(codegen) {
354 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
355 codegen_->expected_safepoint_kind_ = kind;
356
357 switch (codegen_->expected_safepoint_kind_) {
358 case Safepoint::kWithRegisters:
359 codegen_->masm_->PushSafepointRegisters();
360 break;
361 case Safepoint::kWithRegistersAndDoubles:
362 codegen_->masm_->PushSafepointRegistersAndDoubles();
363 break;
364 default:
365 UNREACHABLE();
366 }
367 }
368
369 ~PushSafepointRegistersScope() {
370 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
371 ASSERT((kind & Safepoint::kWithRegisters) != 0);
372 switch (kind) {
373 case Safepoint::kWithRegisters:
374 codegen_->masm_->PopSafepointRegisters();
375 break;
376 case Safepoint::kWithRegistersAndDoubles:
377 codegen_->masm_->PopSafepointRegistersAndDoubles();
378 break;
379 default:
380 UNREACHABLE();
381 }
382 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
383 }
384
385 private:
386 LCodeGen* codegen_;
387 };
388
389 friend class LDeferredCode;
390 friend class LEnvironment;
391 friend class SafepointGenerator;
392 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
393};
394
395
396class LDeferredCode: public ZoneObject {
397 public:
398 explicit LDeferredCode(LCodeGen* codegen)
399 : codegen_(codegen),
400 external_exit_(NULL),
401 instruction_index_(codegen->current_instruction_) {
402 codegen->AddDeferredCode(this);
403 }
404
405 virtual ~LDeferredCode() { }
406 virtual void Generate() = 0;
407 virtual LInstruction* instr() = 0;
408
409 void SetExit(Label *exit) { external_exit_ = exit; }
410 Label* entry() { return &entry_; }
411 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
412 int instruction_index() const { return instruction_index_; }
413
414 protected:
415 LCodeGen* codegen() const { return codegen_; }
416 MacroAssembler* masm() const { return codegen_->masm(); }
417
418 private:
419 LCodeGen* codegen_;
420 Label entry_;
421 Label exit_;
422 Label* external_exit_;
423 int instruction_index_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000424};
ager@chromium.org5c838252010-02-19 08:53:10 +0000425
426} } // namespace v8::internal
427
lrn@chromium.org7516f052011-03-30 08:52:27 +0000428#endif // V8_MIPS_LITHIUM_CODEGEN_MIPS_H_