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 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 960