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