blob: deab7cd9f6239f979c03db4fb1a6b92837449862 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/code-generator.h"
6
7#include "src/compiler/code-generator-impl.h"
8#include "src/compiler/gap-resolver.h"
9#include "src/compiler/node-matchers.h"
10#include "src/compiler/node-properties-inl.h"
11#include "src/ia32/assembler-ia32.h"
12#include "src/ia32/macro-assembler-ia32.h"
13#include "src/scopes.h"
14
15namespace v8 {
16namespace internal {
17namespace compiler {
18
19#define __ masm()->
20
21
22// Adds IA-32 specific methods for decoding operands.
23class IA32OperandConverter : public InstructionOperandConverter {
24 public:
25 IA32OperandConverter(CodeGenerator* gen, Instruction* instr)
26 : InstructionOperandConverter(gen, instr) {}
27
28 Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
29
30 Immediate InputImmediate(int index) {
31 return ToImmediate(instr_->InputAt(index));
32 }
33
34 Operand OutputOperand() { return ToOperand(instr_->Output()); }
35
36 Operand TempOperand(int index) { return ToOperand(instr_->TempAt(index)); }
37
38 Operand ToOperand(InstructionOperand* op, int extra = 0) {
39 if (op->IsRegister()) {
40 DCHECK(extra == 0);
41 return Operand(ToRegister(op));
42 } else if (op->IsDoubleRegister()) {
43 DCHECK(extra == 0);
44 return Operand(ToDoubleRegister(op));
45 }
46 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
47 // The linkage computes where all spill slots are located.
48 FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), extra);
49 return Operand(offset.from_stack_pointer() ? esp : ebp, offset.offset());
50 }
51
52 Operand HighOperand(InstructionOperand* op) {
53 DCHECK(op->IsDoubleStackSlot());
54 return ToOperand(op, kPointerSize);
55 }
56
57 Immediate ToImmediate(InstructionOperand* operand) {
58 Constant constant = ToConstant(operand);
59 switch (constant.type()) {
60 case Constant::kInt32:
61 return Immediate(constant.ToInt32());
62 case Constant::kFloat64:
63 return Immediate(
64 isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
65 case Constant::kExternalReference:
66 return Immediate(constant.ToExternalReference());
67 case Constant::kHeapObject:
68 return Immediate(constant.ToHeapObject());
69 case Constant::kInt64:
70 break;
71 }
72 UNREACHABLE();
73 return Immediate(-1);
74 }
75
76 Operand MemoryOperand(int* first_input) {
77 const int offset = *first_input;
78 switch (AddressingModeField::decode(instr_->opcode())) {
79 case kMode_MR1I:
80 *first_input += 2;
81 return Operand(InputRegister(offset + 0), InputRegister(offset + 1),
82 times_1,
83 0); // TODO(dcarney): K != 0
84 case kMode_MRI:
85 *first_input += 2;
86 return Operand::ForRegisterPlusImmediate(InputRegister(offset + 0),
87 InputImmediate(offset + 1));
88 case kMode_MI:
89 *first_input += 1;
90 return Operand(InputImmediate(offset + 0));
91 default:
92 UNREACHABLE();
93 return Operand(no_reg);
94 }
95 }
96
97 Operand MemoryOperand() {
98 int first_input = 0;
99 return MemoryOperand(&first_input);
100 }
101};
102
103
104static bool HasImmediateInput(Instruction* instr, int index) {
105 return instr->InputAt(index)->IsImmediate();
106}
107
108
109// Assembles an instruction after register allocation, producing machine code.
110void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
111 IA32OperandConverter i(this, instr);
112
113 switch (ArchOpcodeField::decode(instr->opcode())) {
114 case kArchCallCodeObject: {
115 EnsureSpaceForLazyDeopt();
116 if (HasImmediateInput(instr, 0)) {
117 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
118 __ call(code, RelocInfo::CODE_TARGET);
119 } else {
120 Register reg = i.InputRegister(0);
121 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
122 }
123 AddSafepointAndDeopt(instr);
124 break;
125 }
126 case kArchCallJSFunction: {
127 EnsureSpaceForLazyDeopt();
128 Register func = i.InputRegister(0);
129 if (FLAG_debug_code) {
130 // Check the function's context matches the context argument.
131 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
132 __ Assert(equal, kWrongFunctionContext);
133 }
134 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
135 AddSafepointAndDeopt(instr);
136 break;
137 }
138 case kArchJmp:
139 __ jmp(code()->GetLabel(i.InputBlock(0)));
140 break;
141 case kArchNop:
142 // don't emit code for nops.
143 break;
144 case kArchRet:
145 AssembleReturn();
146 break;
147 case kArchTruncateDoubleToI:
148 __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
149 break;
150 case kIA32Add:
151 if (HasImmediateInput(instr, 1)) {
152 __ add(i.InputOperand(0), i.InputImmediate(1));
153 } else {
154 __ add(i.InputRegister(0), i.InputOperand(1));
155 }
156 break;
157 case kIA32And:
158 if (HasImmediateInput(instr, 1)) {
159 __ and_(i.InputOperand(0), i.InputImmediate(1));
160 } else {
161 __ and_(i.InputRegister(0), i.InputOperand(1));
162 }
163 break;
164 case kIA32Cmp:
165 if (HasImmediateInput(instr, 1)) {
166 __ cmp(i.InputOperand(0), i.InputImmediate(1));
167 } else {
168 __ cmp(i.InputRegister(0), i.InputOperand(1));
169 }
170 break;
171 case kIA32Test:
172 if (HasImmediateInput(instr, 1)) {
173 __ test(i.InputOperand(0), i.InputImmediate(1));
174 } else {
175 __ test(i.InputRegister(0), i.InputOperand(1));
176 }
177 break;
178 case kIA32Imul:
179 if (HasImmediateInput(instr, 1)) {
180 __ imul(i.OutputRegister(), i.InputOperand(0), i.InputInt32(1));
181 } else {
182 __ imul(i.OutputRegister(), i.InputOperand(1));
183 }
184 break;
185 case kIA32Idiv:
186 __ cdq();
187 __ idiv(i.InputOperand(1));
188 break;
189 case kIA32Udiv:
190 __ xor_(edx, edx);
191 __ div(i.InputOperand(1));
192 break;
193 case kIA32Not:
194 __ not_(i.OutputOperand());
195 break;
196 case kIA32Neg:
197 __ neg(i.OutputOperand());
198 break;
199 case kIA32Or:
200 if (HasImmediateInput(instr, 1)) {
201 __ or_(i.InputOperand(0), i.InputImmediate(1));
202 } else {
203 __ or_(i.InputRegister(0), i.InputOperand(1));
204 }
205 break;
206 case kIA32Xor:
207 if (HasImmediateInput(instr, 1)) {
208 __ xor_(i.InputOperand(0), i.InputImmediate(1));
209 } else {
210 __ xor_(i.InputRegister(0), i.InputOperand(1));
211 }
212 break;
213 case kIA32Sub:
214 if (HasImmediateInput(instr, 1)) {
215 __ sub(i.InputOperand(0), i.InputImmediate(1));
216 } else {
217 __ sub(i.InputRegister(0), i.InputOperand(1));
218 }
219 break;
220 case kIA32Shl:
221 if (HasImmediateInput(instr, 1)) {
222 __ shl(i.OutputRegister(), i.InputInt5(1));
223 } else {
224 __ shl_cl(i.OutputRegister());
225 }
226 break;
227 case kIA32Shr:
228 if (HasImmediateInput(instr, 1)) {
229 __ shr(i.OutputRegister(), i.InputInt5(1));
230 } else {
231 __ shr_cl(i.OutputRegister());
232 }
233 break;
234 case kIA32Sar:
235 if (HasImmediateInput(instr, 1)) {
236 __ sar(i.OutputRegister(), i.InputInt5(1));
237 } else {
238 __ sar_cl(i.OutputRegister());
239 }
240 break;
241 case kIA32Ror:
242 if (HasImmediateInput(instr, 1)) {
243 __ ror(i.OutputRegister(), i.InputInt5(1));
244 } else {
245 __ ror_cl(i.OutputRegister());
246 }
247 break;
248 case kSSEFloat64Cmp:
249 __ ucomisd(i.InputDoubleRegister(0), i.InputOperand(1));
250 break;
251 case kSSEFloat64Add:
252 __ addsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
253 break;
254 case kSSEFloat64Sub:
255 __ subsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
256 break;
257 case kSSEFloat64Mul:
258 __ mulsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
259 break;
260 case kSSEFloat64Div:
261 __ divsd(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
262 break;
263 case kSSEFloat64Mod: {
264 // TODO(dcarney): alignment is wrong.
265 __ sub(esp, Immediate(kDoubleSize));
266 // Move values to st(0) and st(1).
267 __ movsd(Operand(esp, 0), i.InputDoubleRegister(1));
268 __ fld_d(Operand(esp, 0));
269 __ movsd(Operand(esp, 0), i.InputDoubleRegister(0));
270 __ fld_d(Operand(esp, 0));
271 // Loop while fprem isn't done.
272 Label mod_loop;
273 __ bind(&mod_loop);
274 // This instructions traps on all kinds inputs, but we are assuming the
275 // floating point control word is set to ignore them all.
276 __ fprem();
277 // The following 2 instruction implicitly use eax.
278 __ fnstsw_ax();
279 __ sahf();
280 __ j(parity_even, &mod_loop);
281 // Move output to stack and clean up.
282 __ fstp(1);
283 __ fstp_d(Operand(esp, 0));
284 __ movsd(i.OutputDoubleRegister(), Operand(esp, 0));
285 __ add(esp, Immediate(kDoubleSize));
286 break;
287 }
288 case kSSEFloat64Sqrt:
289 __ sqrtsd(i.OutputDoubleRegister(), i.InputOperand(0));
290 break;
291 case kSSEFloat64ToInt32:
292 __ cvttsd2si(i.OutputRegister(), i.InputOperand(0));
293 break;
294 case kSSEFloat64ToUint32: {
295 XMMRegister scratch = xmm0;
296 __ Move(scratch, -2147483648.0);
297 __ addsd(scratch, i.InputOperand(0));
298 __ cvttsd2si(i.OutputRegister(), scratch);
299 __ add(i.OutputRegister(), Immediate(0x80000000));
300 break;
301 }
302 case kSSEInt32ToFloat64:
303 __ cvtsi2sd(i.OutputDoubleRegister(), i.InputOperand(0));
304 break;
305 case kSSEUint32ToFloat64:
306 // TODO(turbofan): IA32 SSE LoadUint32() should take an operand.
307 __ LoadUint32(i.OutputDoubleRegister(), i.InputRegister(0));
308 break;
309 case kIA32Movsxbl:
310 __ movsx_b(i.OutputRegister(), i.MemoryOperand());
311 break;
312 case kIA32Movzxbl:
313 __ movzx_b(i.OutputRegister(), i.MemoryOperand());
314 break;
315 case kIA32Movb: {
316 int index = 0;
317 Operand operand = i.MemoryOperand(&index);
318 if (HasImmediateInput(instr, index)) {
319 __ mov_b(operand, i.InputInt8(index));
320 } else {
321 __ mov_b(operand, i.InputRegister(index));
322 }
323 break;
324 }
325 case kIA32Movsxwl:
326 __ movsx_w(i.OutputRegister(), i.MemoryOperand());
327 break;
328 case kIA32Movzxwl:
329 __ movzx_w(i.OutputRegister(), i.MemoryOperand());
330 break;
331 case kIA32Movw: {
332 int index = 0;
333 Operand operand = i.MemoryOperand(&index);
334 if (HasImmediateInput(instr, index)) {
335 __ mov_w(operand, i.InputInt16(index));
336 } else {
337 __ mov_w(operand, i.InputRegister(index));
338 }
339 break;
340 }
341 case kIA32Movl:
342 if (instr->HasOutput()) {
343 __ mov(i.OutputRegister(), i.MemoryOperand());
344 } else {
345 int index = 0;
346 Operand operand = i.MemoryOperand(&index);
347 if (HasImmediateInput(instr, index)) {
348 __ mov(operand, i.InputImmediate(index));
349 } else {
350 __ mov(operand, i.InputRegister(index));
351 }
352 }
353 break;
354 case kIA32Movsd:
355 if (instr->HasOutput()) {
356 __ movsd(i.OutputDoubleRegister(), i.MemoryOperand());
357 } else {
358 int index = 0;
359 Operand operand = i.MemoryOperand(&index);
360 __ movsd(operand, i.InputDoubleRegister(index));
361 }
362 break;
363 case kIA32Movss:
364 if (instr->HasOutput()) {
365 __ movss(i.OutputDoubleRegister(), i.MemoryOperand());
366 __ cvtss2sd(i.OutputDoubleRegister(), i.OutputDoubleRegister());
367 } else {
368 int index = 0;
369 Operand operand = i.MemoryOperand(&index);
370 __ cvtsd2ss(xmm0, i.InputDoubleRegister(index));
371 __ movss(operand, xmm0);
372 }
373 break;
374 case kIA32Push:
375 if (HasImmediateInput(instr, 0)) {
376 __ push(i.InputImmediate(0));
377 } else {
378 __ push(i.InputOperand(0));
379 }
380 break;
381 case kIA32StoreWriteBarrier: {
382 Register object = i.InputRegister(0);
383 Register index = i.InputRegister(1);
384 Register value = i.InputRegister(2);
385 __ mov(Operand(object, index, times_1, 0), value);
386 __ lea(index, Operand(object, index, times_1, 0));
387 SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
388 ? kSaveFPRegs
389 : kDontSaveFPRegs;
390 __ RecordWrite(object, index, value, mode);
391 break;
392 }
393 }
394}
395
396
397// Assembles branches after an instruction.
398void CodeGenerator::AssembleArchBranch(Instruction* instr,
399 FlagsCondition condition) {
400 IA32OperandConverter i(this, instr);
401 Label done;
402
403 // Emit a branch. The true and false targets are always the last two inputs
404 // to the instruction.
405 BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
406 BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
407 bool fallthru = IsNextInAssemblyOrder(fblock);
408 Label* tlabel = code()->GetLabel(tblock);
409 Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
410 Label::Distance flabel_distance = fallthru ? Label::kNear : Label::kFar;
411 switch (condition) {
412 case kUnorderedEqual:
413 __ j(parity_even, flabel, flabel_distance);
414 // Fall through.
415 case kEqual:
416 __ j(equal, tlabel);
417 break;
418 case kUnorderedNotEqual:
419 __ j(parity_even, tlabel);
420 // Fall through.
421 case kNotEqual:
422 __ j(not_equal, tlabel);
423 break;
424 case kSignedLessThan:
425 __ j(less, tlabel);
426 break;
427 case kSignedGreaterThanOrEqual:
428 __ j(greater_equal, tlabel);
429 break;
430 case kSignedLessThanOrEqual:
431 __ j(less_equal, tlabel);
432 break;
433 case kSignedGreaterThan:
434 __ j(greater, tlabel);
435 break;
436 case kUnorderedLessThan:
437 __ j(parity_even, flabel, flabel_distance);
438 // Fall through.
439 case kUnsignedLessThan:
440 __ j(below, tlabel);
441 break;
442 case kUnorderedGreaterThanOrEqual:
443 __ j(parity_even, tlabel);
444 // Fall through.
445 case kUnsignedGreaterThanOrEqual:
446 __ j(above_equal, tlabel);
447 break;
448 case kUnorderedLessThanOrEqual:
449 __ j(parity_even, flabel, flabel_distance);
450 // Fall through.
451 case kUnsignedLessThanOrEqual:
452 __ j(below_equal, tlabel);
453 break;
454 case kUnorderedGreaterThan:
455 __ j(parity_even, tlabel);
456 // Fall through.
457 case kUnsignedGreaterThan:
458 __ j(above, tlabel);
459 break;
460 case kOverflow:
461 __ j(overflow, tlabel);
462 break;
463 case kNotOverflow:
464 __ j(no_overflow, tlabel);
465 break;
466 }
467 if (!fallthru) __ jmp(flabel, flabel_distance); // no fallthru to flabel.
468 __ bind(&done);
469}
470
471
472// Assembles boolean materializations after an instruction.
473void CodeGenerator::AssembleArchBoolean(Instruction* instr,
474 FlagsCondition condition) {
475 IA32OperandConverter i(this, instr);
476 Label done;
477
478 // Materialize a full 32-bit 1 or 0 value. The result register is always the
479 // last output of the instruction.
480 Label check;
481 DCHECK_NE(0, instr->OutputCount());
482 Register reg = i.OutputRegister(instr->OutputCount() - 1);
483 Condition cc = no_condition;
484 switch (condition) {
485 case kUnorderedEqual:
486 __ j(parity_odd, &check, Label::kNear);
487 __ mov(reg, Immediate(0));
488 __ jmp(&done, Label::kNear);
489 // Fall through.
490 case kEqual:
491 cc = equal;
492 break;
493 case kUnorderedNotEqual:
494 __ j(parity_odd, &check, Label::kNear);
495 __ mov(reg, Immediate(1));
496 __ jmp(&done, Label::kNear);
497 // Fall through.
498 case kNotEqual:
499 cc = not_equal;
500 break;
501 case kSignedLessThan:
502 cc = less;
503 break;
504 case kSignedGreaterThanOrEqual:
505 cc = greater_equal;
506 break;
507 case kSignedLessThanOrEqual:
508 cc = less_equal;
509 break;
510 case kSignedGreaterThan:
511 cc = greater;
512 break;
513 case kUnorderedLessThan:
514 __ j(parity_odd, &check, Label::kNear);
515 __ mov(reg, Immediate(0));
516 __ jmp(&done, Label::kNear);
517 // Fall through.
518 case kUnsignedLessThan:
519 cc = below;
520 break;
521 case kUnorderedGreaterThanOrEqual:
522 __ j(parity_odd, &check, Label::kNear);
523 __ mov(reg, Immediate(1));
524 __ jmp(&done, Label::kNear);
525 // Fall through.
526 case kUnsignedGreaterThanOrEqual:
527 cc = above_equal;
528 break;
529 case kUnorderedLessThanOrEqual:
530 __ j(parity_odd, &check, Label::kNear);
531 __ mov(reg, Immediate(0));
532 __ jmp(&done, Label::kNear);
533 // Fall through.
534 case kUnsignedLessThanOrEqual:
535 cc = below_equal;
536 break;
537 case kUnorderedGreaterThan:
538 __ j(parity_odd, &check, Label::kNear);
539 __ mov(reg, Immediate(1));
540 __ jmp(&done, Label::kNear);
541 // Fall through.
542 case kUnsignedGreaterThan:
543 cc = above;
544 break;
545 case kOverflow:
546 cc = overflow;
547 break;
548 case kNotOverflow:
549 cc = no_overflow;
550 break;
551 }
552 __ bind(&check);
553 if (reg.is_byte_register()) {
554 // setcc for byte registers (al, bl, cl, dl).
555 __ setcc(cc, reg);
556 __ movzx_b(reg, reg);
557 } else {
558 // Emit a branch to set a register to either 1 or 0.
559 Label set;
560 __ j(cc, &set, Label::kNear);
561 __ mov(reg, Immediate(0));
562 __ jmp(&done, Label::kNear);
563 __ bind(&set);
564 __ mov(reg, Immediate(1));
565 }
566 __ bind(&done);
567}
568
569
570void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
571 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
572 isolate(), deoptimization_id, Deoptimizer::LAZY);
573 __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
574}
575
576
577// The calling convention for JSFunctions on IA32 passes arguments on the
578// stack and the JSFunction and context in EDI and ESI, respectively, thus
579// the steps of the call look as follows:
580
581// --{ before the call instruction }--------------------------------------------
582// | caller frame |
583// ^ esp ^ ebp
584
585// --{ push arguments and setup ESI, EDI }--------------------------------------
586// | args + receiver | caller frame |
587// ^ esp ^ ebp
588// [edi = JSFunction, esi = context]
589
590// --{ call [edi + kCodeEntryOffset] }------------------------------------------
591// | RET | args + receiver | caller frame |
592// ^ esp ^ ebp
593
594// =={ prologue of called function }============================================
595// --{ push ebp }---------------------------------------------------------------
596// | FP | RET | args + receiver | caller frame |
597// ^ esp ^ ebp
598
599// --{ mov ebp, esp }-----------------------------------------------------------
600// | FP | RET | args + receiver | caller frame |
601// ^ ebp,esp
602
603// --{ push esi }---------------------------------------------------------------
604// | CTX | FP | RET | args + receiver | caller frame |
605// ^esp ^ ebp
606
607// --{ push edi }---------------------------------------------------------------
608// | FNC | CTX | FP | RET | args + receiver | caller frame |
609// ^esp ^ ebp
610
611// --{ subi esp, #N }-----------------------------------------------------------
612// | callee frame | FNC | CTX | FP | RET | args + receiver | caller frame |
613// ^esp ^ ebp
614
615// =={ body of called function }================================================
616
617// =={ epilogue of called function }============================================
618// --{ mov esp, ebp }-----------------------------------------------------------
619// | FP | RET | args + receiver | caller frame |
620// ^ esp,ebp
621
622// --{ pop ebp }-----------------------------------------------------------
623// | | RET | args + receiver | caller frame |
624// ^ esp ^ ebp
625
626// --{ ret #A+1 }-----------------------------------------------------------
627// | | caller frame |
628// ^ esp ^ ebp
629
630
631// Runtime function calls are accomplished by doing a stub call to the
632// CEntryStub (a real code object). On IA32 passes arguments on the
633// stack, the number of arguments in EAX, the address of the runtime function
634// in EBX, and the context in ESI.
635
636// --{ before the call instruction }--------------------------------------------
637// | caller frame |
638// ^ esp ^ ebp
639
640// --{ push arguments and setup EAX, EBX, and ESI }-----------------------------
641// | args + receiver | caller frame |
642// ^ esp ^ ebp
643// [eax = #args, ebx = runtime function, esi = context]
644
645// --{ call #CEntryStub }-------------------------------------------------------
646// | RET | args + receiver | caller frame |
647// ^ esp ^ ebp
648
649// =={ body of runtime function }===============================================
650
651// --{ runtime returns }--------------------------------------------------------
652// | caller frame |
653// ^ esp ^ ebp
654
655// Other custom linkages (e.g. for calling directly into and out of C++) may
656// need to save callee-saved registers on the stack, which is done in the
657// function prologue of generated code.
658
659// --{ before the call instruction }--------------------------------------------
660// | caller frame |
661// ^ esp ^ ebp
662
663// --{ set up arguments in registers on stack }---------------------------------
664// | args | caller frame |
665// ^ esp ^ ebp
666// [r0 = arg0, r1 = arg1, ...]
667
668// --{ call code }--------------------------------------------------------------
669// | RET | args | caller frame |
670// ^ esp ^ ebp
671
672// =={ prologue of called function }============================================
673// --{ push ebp }---------------------------------------------------------------
674// | FP | RET | args | caller frame |
675// ^ esp ^ ebp
676
677// --{ mov ebp, esp }-----------------------------------------------------------
678// | FP | RET | args | caller frame |
679// ^ ebp,esp
680
681// --{ save registers }---------------------------------------------------------
682// | regs | FP | RET | args | caller frame |
683// ^ esp ^ ebp
684
685// --{ subi esp, #N }-----------------------------------------------------------
686// | callee frame | regs | FP | RET | args | caller frame |
687// ^esp ^ ebp
688
689// =={ body of called function }================================================
690
691// =={ epilogue of called function }============================================
692// --{ restore registers }------------------------------------------------------
693// | regs | FP | RET | args | caller frame |
694// ^ esp ^ ebp
695
696// --{ mov esp, ebp }-----------------------------------------------------------
697// | FP | RET | args | caller frame |
698// ^ esp,ebp
699
700// --{ pop ebp }----------------------------------------------------------------
701// | RET | args | caller frame |
702// ^ esp ^ ebp
703
704
705void CodeGenerator::AssemblePrologue() {
706 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
707 Frame* frame = code_->frame();
708 int stack_slots = frame->GetSpillSlotCount();
709 if (descriptor->kind() == CallDescriptor::kCallAddress) {
710 // Assemble a prologue similar the to cdecl calling convention.
711 __ push(ebp);
712 __ mov(ebp, esp);
713 const RegList saves = descriptor->CalleeSavedRegisters();
714 if (saves != 0) { // Save callee-saved registers.
715 int register_save_area_size = 0;
716 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
717 if (!((1 << i) & saves)) continue;
718 __ push(Register::from_code(i));
719 register_save_area_size += kPointerSize;
720 }
721 frame->SetRegisterSaveAreaSize(register_save_area_size);
722 }
723 } else if (descriptor->IsJSFunctionCall()) {
724 CompilationInfo* info = linkage()->info();
725 __ Prologue(info->IsCodePreAgingActive());
726 frame->SetRegisterSaveAreaSize(
727 StandardFrameConstants::kFixedFrameSizeFromFp);
728
729 // Sloppy mode functions and builtins need to replace the receiver with the
730 // global proxy when called as functions (without an explicit receiver
731 // object).
732 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
733 if (info->strict_mode() == SLOPPY && !info->is_native()) {
734 Label ok;
735 // +2 for return address and saved frame pointer.
736 int receiver_slot = info->scope()->num_parameters() + 2;
737 __ mov(ecx, Operand(ebp, receiver_slot * kPointerSize));
738 __ cmp(ecx, isolate()->factory()->undefined_value());
739 __ j(not_equal, &ok, Label::kNear);
740 __ mov(ecx, GlobalObjectOperand());
741 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
742 __ mov(Operand(ebp, receiver_slot * kPointerSize), ecx);
743 __ bind(&ok);
744 }
745
746 } else {
747 __ StubPrologue();
748 frame->SetRegisterSaveAreaSize(
749 StandardFrameConstants::kFixedFrameSizeFromFp);
750 }
751 if (stack_slots > 0) {
752 __ sub(esp, Immediate(stack_slots * kPointerSize));
753 }
754}
755
756
757void CodeGenerator::AssembleReturn() {
758 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
759 if (descriptor->kind() == CallDescriptor::kCallAddress) {
760 const RegList saves = descriptor->CalleeSavedRegisters();
761 if (frame()->GetRegisterSaveAreaSize() > 0) {
762 // Remove this frame's spill slots first.
763 int stack_slots = frame()->GetSpillSlotCount();
764 if (stack_slots > 0) {
765 __ add(esp, Immediate(stack_slots * kPointerSize));
766 }
767 // Restore registers.
768 if (saves != 0) {
769 for (int i = 0; i < Register::kNumRegisters; i++) {
770 if (!((1 << i) & saves)) continue;
771 __ pop(Register::from_code(i));
772 }
773 }
774 __ pop(ebp); // Pop caller's frame pointer.
775 __ ret(0);
776 } else {
777 // No saved registers.
778 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
779 __ pop(ebp); // Pop caller's frame pointer.
780 __ ret(0);
781 }
782 } else {
783 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
784 __ pop(ebp); // Pop caller's frame pointer.
785 int pop_count = descriptor->IsJSFunctionCall()
786 ? static_cast<int>(descriptor->JSParameterCount())
787 : 0;
788 __ ret(pop_count * kPointerSize);
789 }
790}
791
792
793void CodeGenerator::AssembleMove(InstructionOperand* source,
794 InstructionOperand* destination) {
795 IA32OperandConverter g(this, NULL);
796 // Dispatch on the source and destination operand kinds. Not all
797 // combinations are possible.
798 if (source->IsRegister()) {
799 DCHECK(destination->IsRegister() || destination->IsStackSlot());
800 Register src = g.ToRegister(source);
801 Operand dst = g.ToOperand(destination);
802 __ mov(dst, src);
803 } else if (source->IsStackSlot()) {
804 DCHECK(destination->IsRegister() || destination->IsStackSlot());
805 Operand src = g.ToOperand(source);
806 if (destination->IsRegister()) {
807 Register dst = g.ToRegister(destination);
808 __ mov(dst, src);
809 } else {
810 Operand dst = g.ToOperand(destination);
811 __ push(src);
812 __ pop(dst);
813 }
814 } else if (source->IsConstant()) {
815 Constant src_constant = g.ToConstant(source);
816 if (src_constant.type() == Constant::kHeapObject) {
817 Handle<HeapObject> src = src_constant.ToHeapObject();
818 if (destination->IsRegister()) {
819 Register dst = g.ToRegister(destination);
820 __ LoadHeapObject(dst, src);
821 } else {
822 DCHECK(destination->IsStackSlot());
823 Operand dst = g.ToOperand(destination);
824 AllowDeferredHandleDereference embedding_raw_address;
825 if (isolate()->heap()->InNewSpace(*src)) {
826 __ PushHeapObject(src);
827 __ pop(dst);
828 } else {
829 __ mov(dst, src);
830 }
831 }
832 } else if (destination->IsRegister()) {
833 Register dst = g.ToRegister(destination);
834 __ mov(dst, g.ToImmediate(source));
835 } else if (destination->IsStackSlot()) {
836 Operand dst = g.ToOperand(destination);
837 __ mov(dst, g.ToImmediate(source));
838 } else {
839 double v = g.ToDouble(source);
840 uint64_t int_val = bit_cast<uint64_t, double>(v);
841 int32_t lower = static_cast<int32_t>(int_val);
842 int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
843 if (destination->IsDoubleRegister()) {
844 XMMRegister dst = g.ToDoubleRegister(destination);
845 __ Move(dst, v);
846 } else {
847 DCHECK(destination->IsDoubleStackSlot());
848 Operand dst0 = g.ToOperand(destination);
849 Operand dst1 = g.HighOperand(destination);
850 __ mov(dst0, Immediate(lower));
851 __ mov(dst1, Immediate(upper));
852 }
853 }
854 } else if (source->IsDoubleRegister()) {
855 XMMRegister src = g.ToDoubleRegister(source);
856 if (destination->IsDoubleRegister()) {
857 XMMRegister dst = g.ToDoubleRegister(destination);
858 __ movaps(dst, src);
859 } else {
860 DCHECK(destination->IsDoubleStackSlot());
861 Operand dst = g.ToOperand(destination);
862 __ movsd(dst, src);
863 }
864 } else if (source->IsDoubleStackSlot()) {
865 DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
866 Operand src = g.ToOperand(source);
867 if (destination->IsDoubleRegister()) {
868 XMMRegister dst = g.ToDoubleRegister(destination);
869 __ movsd(dst, src);
870 } else {
871 // We rely on having xmm0 available as a fixed scratch register.
872 Operand dst = g.ToOperand(destination);
873 __ movsd(xmm0, src);
874 __ movsd(dst, xmm0);
875 }
876 } else {
877 UNREACHABLE();
878 }
879}
880
881
882void CodeGenerator::AssembleSwap(InstructionOperand* source,
883 InstructionOperand* destination) {
884 IA32OperandConverter g(this, NULL);
885 // Dispatch on the source and destination operand kinds. Not all
886 // combinations are possible.
887 if (source->IsRegister() && destination->IsRegister()) {
888 // Register-register.
889 Register src = g.ToRegister(source);
890 Register dst = g.ToRegister(destination);
891 __ xchg(dst, src);
892 } else if (source->IsRegister() && destination->IsStackSlot()) {
893 // Register-memory.
894 __ xchg(g.ToRegister(source), g.ToOperand(destination));
895 } else if (source->IsStackSlot() && destination->IsStackSlot()) {
896 // Memory-memory.
897 Operand src = g.ToOperand(source);
898 Operand dst = g.ToOperand(destination);
899 __ push(dst);
900 __ push(src);
901 __ pop(dst);
902 __ pop(src);
903 } else if (source->IsDoubleRegister() && destination->IsDoubleRegister()) {
904 // XMM register-register swap. We rely on having xmm0
905 // available as a fixed scratch register.
906 XMMRegister src = g.ToDoubleRegister(source);
907 XMMRegister dst = g.ToDoubleRegister(destination);
908 __ movaps(xmm0, src);
909 __ movaps(src, dst);
910 __ movaps(dst, xmm0);
911 } else if (source->IsDoubleRegister() && source->IsDoubleStackSlot()) {
912 // XMM register-memory swap. We rely on having xmm0
913 // available as a fixed scratch register.
914 XMMRegister reg = g.ToDoubleRegister(source);
915 Operand other = g.ToOperand(destination);
916 __ movsd(xmm0, other);
917 __ movsd(other, reg);
918 __ movaps(reg, xmm0);
919 } else if (source->IsDoubleStackSlot() && destination->IsDoubleStackSlot()) {
920 // Double-width memory-to-memory.
921 Operand src0 = g.ToOperand(source);
922 Operand src1 = g.HighOperand(source);
923 Operand dst0 = g.ToOperand(destination);
924 Operand dst1 = g.HighOperand(destination);
925 __ movsd(xmm0, dst0); // Save destination in xmm0.
926 __ push(src0); // Then use stack to copy source to destination.
927 __ pop(dst0);
928 __ push(src1);
929 __ pop(dst1);
930 __ movsd(src0, xmm0);
931 } else {
932 // No other combinations are possible.
933 UNREACHABLE();
934 }
935}
936
937
938void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
939
940
941void CodeGenerator::EnsureSpaceForLazyDeopt() {
942 int space_needed = Deoptimizer::patch_size();
943 if (!linkage()->info()->IsStub()) {
944 // Ensure that we have enough space after the previous lazy-bailout
945 // instruction for patching the code here.
946 int current_pc = masm()->pc_offset();
947 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
948 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
949 __ Nop(padding_size);
950 }
951 }
952 MarkLazyDeoptSite();
953}
954
955#undef __
956
957} // namespace compiler
958} // namespace internal
959} // namespace v8