Home | History | Annotate | Download | only in ia32
      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 
      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 
     15 namespace v8 {
     16 namespace internal {
     17 namespace compiler {
     18 
     19 #define __ masm()->
     20 
     21 
     22 // Adds IA-32 specific methods for decoding operands.
     23 class 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 
    104 static 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.
    110 void 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.
    398 void 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.
    473 void 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 
    570 void 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 
    705 void 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 
    757 void 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 
    793 void 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 
    882 void 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 
    938 void CodeGenerator::AddNopForSmiCodeInlining() { __ nop(); }
    939 
    940 
    941 void 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
    960