blob: b5082561e0061642a8c4c5854cb80f6809789832 [file] [log] [blame]
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001// Copyright 2012 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
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000096 bool IsInteger32(LConstantOperand* op) const;
97 Handle<Object> ToHandle(LConstantOperand* op) const;
98
lrn@chromium.org7516f052011-03-30 08:52:27 +000099 // Try to generate code for the entire chunk, but it may fail if the
100 // chunk contains constructs we cannot handle. Returns true if the
101 // code generation attempt succeeded.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000102 bool GenerateCode();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000103
lrn@chromium.org7516f052011-03-30 08:52:27 +0000104 // Finish the code by setting stack height, safepoint, and bailout
105 // information on it.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000106 void FinishCode(Handle<Code> code);
107
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000108 void DoDeferredNumberTagD(LNumberTagD* instr);
109 void DoDeferredNumberTagI(LNumberTagI* instr);
110 void DoDeferredTaggedToI(LTaggedToI* instr);
111 void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
112 void DoDeferredStackCheck(LStackCheck* instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000113 void DoDeferredRandom(LRandom* instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000114 void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
115 void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +0000116 void DoDeferredAllocateObject(LAllocateObject* instr);
erikcorry0ad885c2011-11-21 13:51:57 +0000117 void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
118 Label* map_check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000119
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000120 void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map,
121 CompareMapMode mode, LEnvironment* env);
122
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 // Parallel move support.
124 void DoParallelMove(LParallelMove* move);
125 void DoGap(LGap* instr);
126
127 // Emit frame translation commands for an environment.
128 void WriteTranslation(LEnvironment* environment, Translation* translation);
129
130 // Declare methods that deal with the individual node types.
131#define DECLARE_DO(type) void Do##type(L##type* node);
132 LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
133#undef DECLARE_DO
134
135 private:
136 enum Status {
137 UNUSED,
138 GENERATING,
139 DONE,
140 ABORTED
141 };
142
143 bool is_unused() const { return status_ == UNUSED; }
144 bool is_generating() const { return status_ == GENERATING; }
145 bool is_done() const { return status_ == DONE; }
146 bool is_aborted() const { return status_ == ABORTED; }
147
148 StrictModeFlag strict_mode_flag() const {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000149 return info()->is_classic_mode() ? kNonStrictMode : kStrictMode;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000150 }
151
152 LChunk* chunk() const { return chunk_; }
153 Scope* scope() const { return scope_; }
154 HGraph* graph() const { return chunk_->graph(); }
155
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000156 Register scratch0() { return kLithiumScratchReg; }
157 Register scratch1() { return kLithiumScratchReg2; }
158 DoubleRegister double_scratch0() { return kLithiumScratchDouble; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000159
160 int GetNextEmittedBlock(int block);
161 LInstruction* GetNextInstruction();
162
163 void EmitClassOfTest(Label* if_true,
164 Label* if_false,
165 Handle<String> class_name,
166 Register input,
167 Register temporary,
168 Register temporary2);
169
170 int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
171 int GetParameterCount() const { return scope()->num_parameters(); }
172
173 void Abort(const char* format, ...);
174 void Comment(const char* format, ...);
175
176 void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code); }
177
178 // Code generation passes. Returns true if code generation should
179 // continue.
180 bool GeneratePrologue();
181 bool GenerateBody();
182 bool GenerateDeferredCode();
183 bool GenerateDeoptJumpTable();
184 bool GenerateSafepointTable();
185
186 enum SafepointMode {
187 RECORD_SIMPLE_SAFEPOINT,
188 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
189 };
190
191 void CallCode(Handle<Code> code,
192 RelocInfo::Mode mode,
193 LInstruction* instr);
194
195 void CallCodeGeneric(Handle<Code> code,
196 RelocInfo::Mode mode,
197 LInstruction* instr,
198 SafepointMode safepoint_mode);
199
200 void CallRuntime(const Runtime::Function* function,
201 int num_arguments,
202 LInstruction* instr);
203
204 void CallRuntime(Runtime::FunctionId id,
205 int num_arguments,
206 LInstruction* instr) {
207 const Runtime::Function* function = Runtime::FunctionForId(id);
208 CallRuntime(function, num_arguments, instr);
209 }
210
211 void CallRuntimeFromDeferred(Runtime::FunctionId id,
212 int argc,
213 LInstruction* instr);
214
215 // Generate a direct call to a known function. Expects the function
216 // to be in a1.
217 void CallKnownFunction(Handle<JSFunction> function,
218 int arity,
219 LInstruction* instr,
220 CallKind call_kind);
221
222 void LoadHeapObject(Register result, Handle<HeapObject> object);
223
erikcorry0ad885c2011-11-21 13:51:57 +0000224 void RecordSafepointWithLazyDeopt(LInstruction* instr,
225 SafepointMode safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000226
erikcorry0ad885c2011-11-21 13:51:57 +0000227 void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
228 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000229 void DeoptimizeIf(Condition cc,
230 LEnvironment* environment,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000231 Register src1 = zero_reg,
232 const Operand& src2 = Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000233
234 void AddToTranslation(Translation* translation,
235 LOperand* op,
236 bool is_tagged);
237 void PopulateDeoptimizationData(Handle<Code> code);
238 int DefineDeoptimizationLiteral(Handle<Object> literal);
239
240 void PopulateDeoptimizationLiteralsWithInlinedFunctions();
241
242 Register ToRegister(int index) const;
243 DoubleRegister ToDoubleRegister(int index) const;
244
245 // Specific math operations - used from DoUnaryMathOperation.
246 void EmitIntegerMathAbs(LUnaryMathOperation* instr);
247 void DoMathAbs(LUnaryMathOperation* instr);
248 void DoMathFloor(LUnaryMathOperation* instr);
249 void DoMathRound(LUnaryMathOperation* instr);
250 void DoMathSqrt(LUnaryMathOperation* instr);
251 void DoMathPowHalf(LUnaryMathOperation* instr);
252 void DoMathLog(LUnaryMathOperation* instr);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000253 void DoMathTan(LUnaryMathOperation* instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000254 void DoMathCos(LUnaryMathOperation* instr);
255 void DoMathSin(LUnaryMathOperation* instr);
256
257 // Support for recording safepoint and position information.
258 void RecordSafepoint(LPointerMap* pointers,
259 Safepoint::Kind kind,
260 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000261 Safepoint::DeoptMode mode);
262 void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
263 void RecordSafepoint(Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000264 void RecordSafepointWithRegisters(LPointerMap* pointers,
265 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000266 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000267 void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
268 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000269 Safepoint::DeoptMode mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000270 void RecordPosition(int position);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000271
272 static Condition TokenToCondition(Token::Value op, bool is_unsigned);
273 void EmitGoto(int block);
274 void EmitBranch(int left_block,
275 int right_block,
276 Condition cc,
277 Register src1,
278 const Operand& src2);
279 void EmitBranchF(int left_block,
280 int right_block,
281 Condition cc,
282 FPURegister src1,
283 FPURegister src2);
284 void EmitCmpI(LOperand* left, LOperand* right);
285 void EmitNumberUntagD(Register input,
286 DoubleRegister result,
287 bool deoptimize_on_undefined,
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000288 bool deoptimize_on_minus_zero,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 LEnvironment* env);
290
291 // Emits optimized code for typeof x == "y". Modifies input register.
292 // Returns the condition on which a final split to
293 // true and false label should be made, to optimize fallthrough.
294 // Returns two registers in cmp1 and cmp2 that can be used in the
295 // Branch instruction after EmitTypeofIs.
296 Condition EmitTypeofIs(Label* true_label,
297 Label* false_label,
298 Register input,
299 Handle<String> type_name,
300 Register& cmp1,
301 Operand& cmp2);
302
303 // Emits optimized code for %_IsObject(x). Preserves input register.
304 // Returns the condition on which a final split to
305 // true and false label should be made, to optimize fallthrough.
306 Condition EmitIsObject(Register input,
307 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +0000308 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000309 Label* is_not_object,
310 Label* is_object);
311
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +0000312 // Emits optimized code for %_IsString(x). Preserves input register.
313 // Returns the condition on which a final split to
314 // true and false label should be made, to optimize fallthrough.
315 Condition EmitIsString(Register input,
316 Register temp1,
317 Label* is_not_string);
318
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000319 // Emits optimized code for %_IsConstructCall().
320 // Caller should branch on equal condition.
321 void EmitIsConstructCall(Register temp1, Register temp2);
322
323 void EmitLoadFieldOrConstantFunction(Register result,
324 Register object,
325 Handle<Map> type,
326 Handle<String> name);
327
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000328 // Emits optimized code to deep-copy the contents of statically known
329 // object graphs (e.g. object literal boilerplate).
330 void EmitDeepCopy(Handle<JSObject> object,
331 Register result,
332 Register source,
333 int* offset);
334
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000335 struct JumpTableEntry {
336 explicit inline JumpTableEntry(Address entry)
337 : label(),
338 address(entry) { }
339 Label label;
340 Address address;
341 };
342
erikcorry0ad885c2011-11-21 13:51:57 +0000343 void EnsureSpaceForLazyDeopt();
344
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000345 LChunk* const chunk_;
346 MacroAssembler* const masm_;
347 CompilationInfo* const info_;
348
349 int current_block_;
350 int current_instruction_;
351 const ZoneList<LInstruction*>* instructions_;
352 ZoneList<LEnvironment*> deoptimizations_;
353 ZoneList<JumpTableEntry> deopt_jump_table_;
354 ZoneList<Handle<Object> > deoptimization_literals_;
355 int inlined_function_count_;
356 Scope* const scope_;
357 Status status_;
358 TranslationBuffer translations_;
359 ZoneList<LDeferredCode*> deferred_;
360 int osr_pc_offset_;
erikcorry0ad885c2011-11-21 13:51:57 +0000361 int last_lazy_deopt_pc_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000362
363 // Builder that keeps track of safepoints in the code. The table
364 // itself is emitted at the end of the generated code.
365 SafepointTableBuilder safepoints_;
366
367 // Compiler from a set of parallel moves to a sequential list of moves.
368 LGapResolver resolver_;
369
370 Safepoint::Kind expected_safepoint_kind_;
371
372 class PushSafepointRegistersScope BASE_EMBEDDED {
373 public:
374 PushSafepointRegistersScope(LCodeGen* codegen,
375 Safepoint::Kind kind)
376 : codegen_(codegen) {
377 ASSERT(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
378 codegen_->expected_safepoint_kind_ = kind;
379
380 switch (codegen_->expected_safepoint_kind_) {
381 case Safepoint::kWithRegisters:
382 codegen_->masm_->PushSafepointRegisters();
383 break;
384 case Safepoint::kWithRegistersAndDoubles:
385 codegen_->masm_->PushSafepointRegistersAndDoubles();
386 break;
387 default:
388 UNREACHABLE();
389 }
390 }
391
392 ~PushSafepointRegistersScope() {
393 Safepoint::Kind kind = codegen_->expected_safepoint_kind_;
394 ASSERT((kind & Safepoint::kWithRegisters) != 0);
395 switch (kind) {
396 case Safepoint::kWithRegisters:
397 codegen_->masm_->PopSafepointRegisters();
398 break;
399 case Safepoint::kWithRegistersAndDoubles:
400 codegen_->masm_->PopSafepointRegistersAndDoubles();
401 break;
402 default:
403 UNREACHABLE();
404 }
405 codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
406 }
407
408 private:
409 LCodeGen* codegen_;
410 };
411
412 friend class LDeferredCode;
413 friend class LEnvironment;
414 friend class SafepointGenerator;
415 DISALLOW_COPY_AND_ASSIGN(LCodeGen);
416};
417
418
419class LDeferredCode: public ZoneObject {
420 public:
421 explicit LDeferredCode(LCodeGen* codegen)
422 : codegen_(codegen),
423 external_exit_(NULL),
424 instruction_index_(codegen->current_instruction_) {
425 codegen->AddDeferredCode(this);
426 }
427
428 virtual ~LDeferredCode() { }
429 virtual void Generate() = 0;
430 virtual LInstruction* instr() = 0;
431
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000432 void SetExit(Label* exit) { external_exit_ = exit; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000433 Label* entry() { return &entry_; }
434 Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
435 int instruction_index() const { return instruction_index_; }
436
437 protected:
438 LCodeGen* codegen() const { return codegen_; }
439 MacroAssembler* masm() const { return codegen_->masm(); }
440
441 private:
442 LCodeGen* codegen_;
443 Label entry_;
444 Label exit_;
445 Label* external_exit_;
446 int instruction_index_;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000447};
ager@chromium.org5c838252010-02-19 08:53:10 +0000448
449} } // namespace v8::internal
450
lrn@chromium.org7516f052011-03-30 08:52:27 +0000451#endif // V8_MIPS_LITHIUM_CODEGEN_MIPS_H_