blob: 57d3d9b853d181cebbeb89081b27db38e82dfe38 [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),
erikcorry0ad885c2011-11-21 13:51:57 +000061 last_lazy_deopt_pc_(0),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000062 resolver_(this),
63 expected_safepoint_kind_(Safepoint::kSimple) {
64 PopulateDeoptimizationLiteralsWithInlinedFunctions();
65 }
66
67
68 // Simple accessors.
69 MacroAssembler* masm() const { return masm_; }
70 CompilationInfo* info() const { return info_; }
71 Isolate* isolate() const { return info_->isolate(); }
72 Factory* factory() const { return isolate()->factory(); }
73 Heap* heap() const { return isolate()->heap(); }
74
75 // Support for converting LOperands to assembler types.
76 // LOperand must be a register.
77 Register ToRegister(LOperand* op) const;
78
79 // LOperand is loaded into scratch, unless already a register.
80 Register EmitLoadRegister(LOperand* op, Register scratch);
81
82 // LOperand must be a double register.
83 DoubleRegister ToDoubleRegister(LOperand* op) const;
84
85 // LOperand is loaded into dbl_scratch, unless already a double register.
86 DoubleRegister EmitLoadDoubleRegister(LOperand* op,
87 FloatRegister flt_scratch,
88 DoubleRegister dbl_scratch);
89 int ToInteger32(LConstantOperand* op) const;
90 double ToDouble(LConstantOperand* op) const;
91 Operand ToOperand(LOperand* op);
92 MemOperand ToMemOperand(LOperand* op) const;
93 // Returns a MemOperand pointing to the high word of a DoubleStackSlot.
94 MemOperand ToHighMemOperand(LOperand* op) const;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000095
lrn@chromium.org7516f052011-03-30 08:52:27 +000096 // Try to generate code for the entire chunk, but it may fail if the
97 // chunk contains constructs we cannot handle. Returns true if the
98 // code generation attempt succeeded.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000099 bool GenerateCode();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000100
lrn@chromium.org7516f052011-03-30 08:52:27 +0000101 // Finish the code by setting stack height, safepoint, and bailout
102 // information on it.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000103 void FinishCode(Handle<Code> code);
104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000105 void DoDeferredNumberTagD(LNumberTagD* instr);
106 void DoDeferredNumberTagI(LNumberTagI* instr);
107 void DoDeferredTaggedToI(LTaggedToI* instr);
108 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
109 void DoDeferredStackCheck(LStackCheck* instr);
110 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
111 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
erikcorry0ad885c2011-11-21 13:51:57 +0000112 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
113 Label* map_check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000114
115 // Parallel move support.
116 void DoParallelMove(LParallelMove* move);
117 void DoGap(LGap* instr);
118
119 // Emit frame translation commands for an environment.
120 void WriteTranslation(LEnvironment* environment, Translation* translation);
121
122 // 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
140 StrictModeFlag strict_mode_flag() const {
141 return info()->strict_mode_flag();
142 }
143
144 LChunk* chunk() const { return chunk_; }
145 Scope* scope() const { return scope_; }
146 HGraph* graph() const { return chunk_->graph(); }
147
148 Register scratch0() { return lithiumScratchReg; }
149 Register scratch1() { return lithiumScratchReg2; }
150 DoubleRegister double_scratch0() { return lithiumScratchDouble; }
151
152 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
162 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
163 int GetParameterCount() const { return scope()->num_parameters(); }
164
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 GenerateDeoptJumpTable();
176 bool GenerateSafepointTable();
177
178 enum SafepointMode {
179 RECORD_SIMPLE_SAFEPOINT,
180 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
181 };
182
183 void CallCode(Handle<Code> code,
184 RelocInfo::Mode mode,
185 LInstruction* instr);
186
187 void CallCodeGeneric(Handle<Code> code,
188 RelocInfo::Mode mode,
189 LInstruction* instr,
190 SafepointMode safepoint_mode);
191
192 void CallRuntime(const Runtime::Function* function,
193 int num_arguments,
194 LInstruction* instr);
195
196 void CallRuntime(Runtime::FunctionId id,
197 int num_arguments,
198 LInstruction* instr) {
199 const Runtime::Function* function = Runtime::FunctionForId(id);
200 CallRuntime(function, num_arguments, instr);
201 }
202
203 void CallRuntimeFromDeferred(Runtime::FunctionId id,
204 int argc,
205 LInstruction* instr);
206
207 // Generate a direct call to a known function. Expects the function
208 // to be in a1.
209 void CallKnownFunction(Handle<JSFunction> function,
210 int arity,
211 LInstruction* instr,
212 CallKind call_kind);
213
214 void LoadHeapObject(Register result, Handle<HeapObject> object);
215
erikcorry0ad885c2011-11-21 13:51:57 +0000216 void RecordSafepointWithLazyDeopt(LInstruction* instr,
217 SafepointMode safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000218
erikcorry0ad885c2011-11-21 13:51:57 +0000219 void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
220 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000221 void DeoptimizeIf(Condition cc,
222 LEnvironment* environment,
223 Register src1,
224 const Operand& src2);
225
226 void AddToTranslation(Translation* translation,
227 LOperand* op,
228 bool is_tagged);
229 void PopulateDeoptimizationData(Handle<Code> code);
230 int DefineDeoptimizationLiteral(Handle<Object> literal);
231
232 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
233
234 Register ToRegister(int index) const;
235 DoubleRegister ToDoubleRegister(int index) const;
236
237 // Specific math operations - used from DoUnaryMathOperation.
238 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
239 void DoMathAbs(LUnaryMathOperation* instr);
240 void DoMathFloor(LUnaryMathOperation* instr);
241 void DoMathRound(LUnaryMathOperation* instr);
242 void DoMathSqrt(LUnaryMathOperation* instr);
243 void DoMathPowHalf(LUnaryMathOperation* instr);
244 void DoMathLog(LUnaryMathOperation* instr);
245 void DoMathCos(LUnaryMathOperation* instr);
246 void DoMathSin(LUnaryMathOperation* instr);
247
248 // Support for recording safepoint and position information.
249 void RecordSafepoint(LPointerMap* pointers,
250 Safepoint::Kind kind,
251 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000252 Safepoint::DeoptMode mode);
253 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
254 void RecordSafepoint(Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000255 void RecordSafepointWithRegisters(LPointerMap* pointers,
256 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000257 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000258 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
259 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000260 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000261 void RecordPosition(int position);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000262
263 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
264 void EmitGoto(int block);
265 void EmitBranch(int left_block,
266 int right_block,
267 Condition cc,
268 Register src1,
269 const Operand& src2);
270 void EmitBranchF(int left_block,
271 int right_block,
272 Condition cc,
273 FPURegister src1,
274 FPURegister src2);
275 void EmitCmpI(LOperand* left, LOperand* right);
276 void EmitNumberUntagD(Register input,
277 DoubleRegister result,
278 bool deoptimize_on_undefined,
279 LEnvironment* env);
280
281 // Emits optimized code for typeof x == "y". Modifies input register.
282 // Returns the condition on which a final split to
283 // true and false label should be made, to optimize fallthrough.
284 // Returns two registers in cmp1 and cmp2 that can be used in the
285 // Branch instruction after EmitTypeofIs.
286 Condition EmitTypeofIs(Label* true_label,
287 Label* false_label,
288 Register input,
289 Handle<String> type_name,
290 Register& cmp1,
291 Operand& cmp2);
292
293 // Emits optimized code for %_IsObject(x). Preserves input register.
294 // Returns the condition on which a final split to
295 // true and false label should be made, to optimize fallthrough.
296 Condition EmitIsObject(Register input,
297 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +0000298 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000299 Label* is_not_object,
300 Label* is_object);
301
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +0000302 // Emits optimized code for %_IsString(x). Preserves input register.
303 // Returns the condition on which a final split to
304 // true and false label should be made, to optimize fallthrough.
305 Condition EmitIsString(Register input,
306 Register temp1,
307 Label* is_not_string);
308
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000309 // Emits optimized code for %_IsConstructCall().
310 // Caller should branch on equal condition.
311 void EmitIsConstructCall(Register temp1, Register temp2);
312
313 void EmitLoadFieldOrConstantFunction(Register result,
314 Register object,
315 Handle<Map> type,
316 Handle<String> name);
317
318 struct JumpTableEntry {
319 explicit inline JumpTableEntry(Address entry)
320 : label(),
321 address(entry) { }
322 Label label;
323 Address address;
324 };
325
erikcorry0ad885c2011-11-21 13:51:57 +0000326 void EnsureSpaceForLazyDeopt();
327
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000328 LChunk* const chunk_;
329 MacroAssembler* const masm_;
330 CompilationInfo* const info_;
331
332 int current_block_;
333 int current_instruction_;
334 const ZoneList<LInstruction*>* instructions_;
335 ZoneList<LEnvironment*> deoptimizations_;
336 ZoneList<JumpTableEntry> deopt_jump_table_;
337 ZoneList<Handle<Object> > deoptimization_literals_;
338 int inlined_function_count_;
339 Scope* const scope_;
340 Status status_;
341 TranslationBuffer translations_;
342 ZoneList<LDeferredCode*> deferred_;
343 int osr_pc_offset_;
erikcorry0ad885c2011-11-21 13:51:57 +0000344 int last_lazy_deopt_pc_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000345
346 // Builder that keeps track of safepoints in the code. The table
347 // itself is emitted at the end of the generated code.
348 SafepointTableBuilder safepoints_;
349
350 // Compiler from a set of parallel moves to a sequential list of moves.
351 LGapResolver resolver_;
352
353 Safepoint::Kind expected_safepoint_kind_;
354
355 class PushSafepointRegistersScope BASE_EMBEDDED {
356 public:
357 PushSafepointRegistersScope(LCodeGen* codegen,
358 Safepoint::Kind kind)
359 : codegen_(codegen) {
360 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
361 codegen_->expected_safepoint_kind_ = kind;
362
363 switch (codegen_->expected_safepoint_kind_) {
364 case Safepoint::kWithRegisters:
365 codegen_->masm_->PushSafepointRegisters();
366 break;
367 case Safepoint::kWithRegistersAndDoubles:
368 codegen_->masm_->PushSafepointRegistersAndDoubles();
369 break;
370 default:
371 UNREACHABLE();
372 }
373 }
374
375 ~PushSafepointRegistersScope() {
376 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
377 ASSERT((kind & Safepoint::kWithRegisters) != 0);
378 switch (kind) {
379 case Safepoint::kWithRegisters:
380 codegen_->masm_->PopSafepointRegisters();
381 break;
382 case Safepoint::kWithRegistersAndDoubles:
383 codegen_->masm_->PopSafepointRegistersAndDoubles();
384 break;
385 default:
386 UNREACHABLE();
387 }
388 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
389 }
390
391 private:
392 LCodeGen* codegen_;
393 };
394
395 friend class LDeferredCode;
396 friend class LEnvironment;
397 friend class SafepointGenerator;
398 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
399};
400
401
402class LDeferredCode: public ZoneObject {
403 public:
404 explicit LDeferredCode(LCodeGen* codegen)
405 : codegen_(codegen),
406 external_exit_(NULL),
407 instruction_index_(codegen->current_instruction_) {
408 codegen->AddDeferredCode(this);
409 }
410
411 virtual ~LDeferredCode() { }
412 virtual void Generate() = 0;
413 virtual LInstruction* instr() = 0;
414
415 void SetExit(Label *exit) { external_exit_ = exit; }
416 Label* entry() { return &entry_; }
417 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
418 int instruction_index() const { return instruction_index_; }
419
420 protected:
421 LCodeGen* codegen() const { return codegen_; }
422 MacroAssembler* masm() const { return codegen_->masm(); }
423
424 private:
425 LCodeGen* codegen_;
426 Label entry_;
427 Label exit_;
428 Label* external_exit_;
429 int instruction_index_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000430};
ager@chromium.org5c838252010-02-19 08:53:10 +0000431
432} } // namespace v8::internal
433
lrn@chromium.org7516f052011-03-30 08:52:27 +0000434#endif // V8_MIPS_LITHIUM_CODEGEN_MIPS_H_