1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "codegen-inl.h" 31 #include "compiler.h" 32 #include "debug.h" 33 #include "full-codegen.h" 34 #include "parser.h" 35 36 namespace v8 { 37 namespace internal { 38 39 #define __ ACCESS_MASM(masm_) 40 41 // Generate code for a JS function. On entry to the function the receiver 42 // and arguments have been pushed on the stack left to right, with the 43 // return address on top of them. The actual argument count matches the 44 // formal parameter count expected by the function. 45 // 46 // The live registers are: 47 // o rdi: the JS function object being called (ie, ourselves) 48 // o rsi: our context 49 // o rbp: our caller's frame pointer 50 // o rsp: stack pointer (pointing to return address) 51 // 52 // The function builds a JS frame. Please see JavaScriptFrameConstants in 53 // frames-x64.h for its layout. 54 void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) { 55 ASSERT(info_ == NULL); 56 info_ = info; 57 SetFunctionPosition(function()); 58 59 if (mode == PRIMARY) { 60 __ push(rbp); // Caller's frame pointer. 61 __ movq(rbp, rsp); 62 __ push(rsi); // Callee's context. 63 __ push(rdi); // Callee's JS Function. 64 65 { Comment cmnt(masm_, "[ Allocate locals"); 66 int locals_count = scope()->num_stack_slots(); 67 if (locals_count == 1) { 68 __ PushRoot(Heap::kUndefinedValueRootIndex); 69 } else if (locals_count > 1) { 70 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 71 for (int i = 0; i < locals_count; i++) { 72 __ push(rdx); 73 } 74 } 75 } 76 77 bool function_in_register = true; 78 79 // Possibly allocate a local context. 80 if (scope()->num_heap_slots() > 0) { 81 Comment cmnt(masm_, "[ Allocate local context"); 82 // Argument to NewContext is the function, which is still in rdi. 83 __ push(rdi); 84 __ CallRuntime(Runtime::kNewContext, 1); 85 function_in_register = false; 86 // Context is returned in both rax and rsi. It replaces the context 87 // passed to us. It's saved in the stack and kept live in rsi. 88 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); 89 90 // Copy any necessary parameters into the context. 91 int num_parameters = scope()->num_parameters(); 92 for (int i = 0; i < num_parameters; i++) { 93 Slot* slot = scope()->parameter(i)->slot(); 94 if (slot != NULL && slot->type() == Slot::CONTEXT) { 95 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 96 (num_parameters - 1 - i) * kPointerSize; 97 // Load parameter from stack. 98 __ movq(rax, Operand(rbp, parameter_offset)); 99 // Store it in the context. 100 int context_offset = Context::SlotOffset(slot->index()); 101 __ movq(Operand(rsi, context_offset), rax); 102 // Update the write barrier. This clobbers all involved 103 // registers, so we have use a third register to avoid 104 // clobbering rsi. 105 __ movq(rcx, rsi); 106 __ RecordWrite(rcx, context_offset, rax, rbx); 107 } 108 } 109 } 110 111 // Possibly allocate an arguments object. 112 Variable* arguments = scope()->arguments()->AsVariable(); 113 if (arguments != NULL) { 114 // Arguments object must be allocated after the context object, in 115 // case the "arguments" or ".arguments" variables are in the context. 116 Comment cmnt(masm_, "[ Allocate arguments object"); 117 if (function_in_register) { 118 __ push(rdi); 119 } else { 120 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 121 } 122 // The receiver is just before the parameters on the caller's stack. 123 int offset = scope()->num_parameters() * kPointerSize; 124 __ lea(rdx, 125 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); 126 __ push(rdx); 127 __ Push(Smi::FromInt(scope()->num_parameters())); 128 // Arguments to ArgumentsAccessStub: 129 // function, receiver address, parameter count. 130 // The stub will rewrite receiver and parameter count if the previous 131 // stack frame was an arguments adapter frame. 132 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 133 __ CallStub(&stub); 134 // Store new arguments object in both "arguments" and ".arguments" slots. 135 __ movq(rcx, rax); 136 Move(arguments->slot(), rax, rbx, rdx); 137 Slot* dot_arguments_slot = 138 scope()->arguments_shadow()->AsVariable()->slot(); 139 Move(dot_arguments_slot, rcx, rbx, rdx); 140 } 141 } 142 143 { Comment cmnt(masm_, "[ Declarations"); 144 VisitDeclarations(scope()->declarations()); 145 } 146 147 { Comment cmnt(masm_, "[ Stack check"); 148 Label ok; 149 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 150 __ j(above_equal, &ok); 151 StackCheckStub stub; 152 __ CallStub(&stub); 153 __ bind(&ok); 154 } 155 156 if (FLAG_trace) { 157 __ CallRuntime(Runtime::kTraceEnter, 0); 158 } 159 160 { Comment cmnt(masm_, "[ Body"); 161 ASSERT(loop_depth() == 0); 162 VisitStatements(function()->body()); 163 ASSERT(loop_depth() == 0); 164 } 165 166 { Comment cmnt(masm_, "[ return <undefined>;"); 167 // Emit a 'return undefined' in case control fell off the end of the body. 168 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); 169 EmitReturnSequence(function()->end_position()); 170 } 171 } 172 173 174 void FullCodeGenerator::EmitReturnSequence(int position) { 175 Comment cmnt(masm_, "[ Return sequence"); 176 if (return_label_.is_bound()) { 177 __ jmp(&return_label_); 178 } else { 179 __ bind(&return_label_); 180 if (FLAG_trace) { 181 __ push(rax); 182 __ CallRuntime(Runtime::kTraceExit, 1); 183 } 184 #ifdef DEBUG 185 // Add a label for checking the size of the code used for returning. 186 Label check_exit_codesize; 187 masm_->bind(&check_exit_codesize); 188 #endif 189 CodeGenerator::RecordPositions(masm_, position); 190 __ RecordJSReturn(); 191 // Do not use the leave instruction here because it is too short to 192 // patch with the code required by the debugger. 193 __ movq(rsp, rbp); 194 __ pop(rbp); 195 __ ret((scope()->num_parameters() + 1) * kPointerSize); 196 #ifdef ENABLE_DEBUGGER_SUPPORT 197 // Add padding that will be overwritten by a debugger breakpoint. We 198 // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7 199 // (3 + 1 + 3). 200 const int kPadding = Assembler::kJSReturnSequenceLength - 7; 201 for (int i = 0; i < kPadding; ++i) { 202 masm_->int3(); 203 } 204 // Check that the size of the code used for returning matches what is 205 // expected by the debugger. 206 ASSERT_EQ(Assembler::kJSReturnSequenceLength, 207 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); 208 #endif 209 } 210 } 211 212 213 void FullCodeGenerator::Apply(Expression::Context context, Register reg) { 214 switch (context) { 215 case Expression::kUninitialized: 216 UNREACHABLE(); 217 218 case Expression::kEffect: 219 // Nothing to do. 220 break; 221 222 case Expression::kValue: 223 // Move value into place. 224 switch (location_) { 225 case kAccumulator: 226 if (!reg.is(result_register())) __ movq(result_register(), reg); 227 break; 228 case kStack: 229 __ push(reg); 230 break; 231 } 232 break; 233 234 case Expression::kTest: 235 // For simplicity we always test the accumulator register. 236 if (!reg.is(result_register())) __ movq(result_register(), reg); 237 DoTest(context); 238 break; 239 240 case Expression::kValueTest: 241 case Expression::kTestValue: 242 if (!reg.is(result_register())) __ movq(result_register(), reg); 243 switch (location_) { 244 case kAccumulator: 245 break; 246 case kStack: 247 __ push(result_register()); 248 break; 249 } 250 DoTest(context); 251 break; 252 } 253 } 254 255 256 void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) { 257 switch (context) { 258 case Expression::kUninitialized: 259 UNREACHABLE(); 260 case Expression::kEffect: 261 // Nothing to do. 262 break; 263 case Expression::kValue: { 264 MemOperand slot_operand = EmitSlotSearch(slot, result_register()); 265 switch (location_) { 266 case kAccumulator: 267 __ movq(result_register(), slot_operand); 268 break; 269 case kStack: 270 // Memory operands can be pushed directly. 271 __ push(slot_operand); 272 break; 273 } 274 break; 275 } 276 277 case Expression::kTest: 278 Move(result_register(), slot); 279 DoTest(context); 280 break; 281 282 case Expression::kValueTest: 283 case Expression::kTestValue: 284 Move(result_register(), slot); 285 switch (location_) { 286 case kAccumulator: 287 break; 288 case kStack: 289 __ push(result_register()); 290 break; 291 } 292 DoTest(context); 293 break; 294 } 295 } 296 297 298 void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) { 299 switch (context) { 300 case Expression::kUninitialized: 301 UNREACHABLE(); 302 case Expression::kEffect: 303 // Nothing to do. 304 break; 305 case Expression::kValue: 306 switch (location_) { 307 case kAccumulator: 308 __ Move(result_register(), lit->handle()); 309 break; 310 case kStack: 311 __ Push(lit->handle()); 312 break; 313 } 314 break; 315 316 case Expression::kTest: 317 __ Move(result_register(), lit->handle()); 318 DoTest(context); 319 break; 320 321 case Expression::kValueTest: 322 case Expression::kTestValue: 323 __ Move(result_register(), lit->handle()); 324 switch (location_) { 325 case kAccumulator: 326 break; 327 case kStack: 328 __ push(result_register()); 329 break; 330 } 331 DoTest(context); 332 break; 333 } 334 } 335 336 337 void FullCodeGenerator::ApplyTOS(Expression::Context context) { 338 switch (context) { 339 case Expression::kUninitialized: 340 UNREACHABLE(); 341 342 case Expression::kEffect: 343 __ Drop(1); 344 break; 345 346 case Expression::kValue: 347 switch (location_) { 348 case kAccumulator: 349 __ pop(result_register()); 350 break; 351 case kStack: 352 break; 353 } 354 break; 355 356 case Expression::kTest: 357 __ pop(result_register()); 358 DoTest(context); 359 break; 360 361 case Expression::kValueTest: 362 case Expression::kTestValue: 363 switch (location_) { 364 case kAccumulator: 365 __ pop(result_register()); 366 break; 367 case kStack: 368 __ movq(result_register(), Operand(rsp, 0)); 369 break; 370 } 371 DoTest(context); 372 break; 373 } 374 } 375 376 377 void FullCodeGenerator::DropAndApply(int count, 378 Expression::Context context, 379 Register reg) { 380 ASSERT(count > 0); 381 ASSERT(!reg.is(rsp)); 382 switch (context) { 383 case Expression::kUninitialized: 384 UNREACHABLE(); 385 386 case Expression::kEffect: 387 __ Drop(count); 388 break; 389 390 case Expression::kValue: 391 switch (location_) { 392 case kAccumulator: 393 __ Drop(count); 394 if (!reg.is(result_register())) __ movq(result_register(), reg); 395 break; 396 case kStack: 397 if (count > 1) __ Drop(count - 1); 398 __ movq(Operand(rsp, 0), reg); 399 break; 400 } 401 break; 402 403 case Expression::kTest: 404 __ Drop(count); 405 if (!reg.is(result_register())) __ movq(result_register(), reg); 406 DoTest(context); 407 break; 408 409 case Expression::kValueTest: 410 case Expression::kTestValue: 411 switch (location_) { 412 case kAccumulator: 413 __ Drop(count); 414 if (!reg.is(result_register())) __ movq(result_register(), reg); 415 break; 416 case kStack: 417 if (count > 1) __ Drop(count - 1); 418 __ movq(result_register(), reg); 419 __ movq(Operand(rsp, 0), result_register()); 420 break; 421 } 422 DoTest(context); 423 break; 424 } 425 } 426 427 428 void FullCodeGenerator::Apply(Expression::Context context, 429 Label* materialize_true, 430 Label* materialize_false) { 431 switch (context) { 432 case Expression::kUninitialized: 433 434 case Expression::kEffect: 435 ASSERT_EQ(materialize_true, materialize_false); 436 __ bind(materialize_true); 437 break; 438 439 case Expression::kValue: { 440 Label done; 441 switch (location_) { 442 case kAccumulator: 443 __ bind(materialize_true); 444 __ Move(result_register(), Factory::true_value()); 445 __ jmp(&done); 446 __ bind(materialize_false); 447 __ Move(result_register(), Factory::false_value()); 448 break; 449 case kStack: 450 __ bind(materialize_true); 451 __ Push(Factory::true_value()); 452 __ jmp(&done); 453 __ bind(materialize_false); 454 __ Push(Factory::false_value()); 455 break; 456 } 457 __ bind(&done); 458 break; 459 } 460 461 case Expression::kTest: 462 break; 463 464 case Expression::kValueTest: 465 __ bind(materialize_true); 466 switch (location_) { 467 case kAccumulator: 468 __ Move(result_register(), Factory::true_value()); 469 break; 470 case kStack: 471 __ Push(Factory::true_value()); 472 break; 473 } 474 __ jmp(true_label_); 475 break; 476 477 case Expression::kTestValue: 478 __ bind(materialize_false); 479 switch (location_) { 480 case kAccumulator: 481 __ Move(result_register(), Factory::false_value()); 482 break; 483 case kStack: 484 __ Push(Factory::false_value()); 485 break; 486 } 487 __ jmp(false_label_); 488 break; 489 } 490 } 491 492 493 void FullCodeGenerator::DoTest(Expression::Context context) { 494 // The value to test is in the accumulator. If the value might be needed 495 // on the stack (value/test and test/value contexts with a stack location 496 // desired), then the value is already duplicated on the stack. 497 ASSERT_NE(NULL, true_label_); 498 ASSERT_NE(NULL, false_label_); 499 500 // In value/test and test/value expression contexts with stack as the 501 // desired location, there is already an extra value on the stack. Use a 502 // label to discard it if unneeded. 503 Label discard; 504 Label* if_true = true_label_; 505 Label* if_false = false_label_; 506 switch (context) { 507 case Expression::kUninitialized: 508 case Expression::kEffect: 509 case Expression::kValue: 510 UNREACHABLE(); 511 case Expression::kTest: 512 break; 513 case Expression::kValueTest: 514 switch (location_) { 515 case kAccumulator: 516 break; 517 case kStack: 518 if_false = &discard; 519 break; 520 } 521 break; 522 case Expression::kTestValue: 523 switch (location_) { 524 case kAccumulator: 525 break; 526 case kStack: 527 if_true = &discard; 528 break; 529 } 530 break; 531 } 532 533 // Emit the inlined tests assumed by the stub. 534 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); 535 __ j(equal, if_false); 536 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); 537 __ j(equal, if_true); 538 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); 539 __ j(equal, if_false); 540 ASSERT_EQ(0, kSmiTag); 541 __ SmiCompare(result_register(), Smi::FromInt(0)); 542 __ j(equal, if_false); 543 Condition is_smi = masm_->CheckSmi(result_register()); 544 __ j(is_smi, if_true); 545 546 // Save a copy of the value if it may be needed and isn't already saved. 547 switch (context) { 548 case Expression::kUninitialized: 549 case Expression::kEffect: 550 case Expression::kValue: 551 UNREACHABLE(); 552 case Expression::kTest: 553 break; 554 case Expression::kValueTest: 555 switch (location_) { 556 case kAccumulator: 557 __ push(result_register()); 558 break; 559 case kStack: 560 break; 561 } 562 break; 563 case Expression::kTestValue: 564 switch (location_) { 565 case kAccumulator: 566 __ push(result_register()); 567 break; 568 case kStack: 569 break; 570 } 571 break; 572 } 573 574 // Call the ToBoolean stub for all other cases. 575 ToBooleanStub stub; 576 __ push(result_register()); 577 __ CallStub(&stub); 578 __ testq(rax, rax); 579 580 // The stub returns nonzero for true. Complete based on the context. 581 switch (context) { 582 case Expression::kUninitialized: 583 case Expression::kEffect: 584 case Expression::kValue: 585 UNREACHABLE(); 586 587 case Expression::kTest: 588 __ j(not_zero, true_label_); 589 __ jmp(false_label_); 590 break; 591 592 case Expression::kValueTest: 593 switch (location_) { 594 case kAccumulator: 595 __ j(zero, &discard); 596 __ pop(result_register()); 597 __ jmp(true_label_); 598 break; 599 case kStack: 600 __ j(not_zero, true_label_); 601 break; 602 } 603 __ bind(&discard); 604 __ Drop(1); 605 __ jmp(false_label_); 606 break; 607 608 case Expression::kTestValue: 609 switch (location_) { 610 case kAccumulator: 611 __ j(not_zero, &discard); 612 __ pop(result_register()); 613 __ jmp(false_label_); 614 break; 615 case kStack: 616 __ j(zero, false_label_); 617 break; 618 } 619 __ bind(&discard); 620 __ Drop(1); 621 __ jmp(true_label_); 622 break; 623 } 624 } 625 626 627 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { 628 switch (slot->type()) { 629 case Slot::PARAMETER: 630 case Slot::LOCAL: 631 return Operand(rbp, SlotOffset(slot)); 632 case Slot::CONTEXT: { 633 int context_chain_length = 634 scope()->ContextChainLength(slot->var()->scope()); 635 __ LoadContext(scratch, context_chain_length); 636 return CodeGenerator::ContextOperand(scratch, slot->index()); 637 } 638 case Slot::LOOKUP: 639 UNREACHABLE(); 640 } 641 UNREACHABLE(); 642 return Operand(rax, 0); 643 } 644 645 646 void FullCodeGenerator::Move(Register destination, Slot* source) { 647 MemOperand location = EmitSlotSearch(source, destination); 648 __ movq(destination, location); 649 } 650 651 652 void FullCodeGenerator::Move(Slot* dst, 653 Register src, 654 Register scratch1, 655 Register scratch2) { 656 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. 657 ASSERT(!scratch1.is(src) && !scratch2.is(src)); 658 MemOperand location = EmitSlotSearch(dst, scratch1); 659 __ movq(location, src); 660 // Emit the write barrier code if the location is in the heap. 661 if (dst->type() == Slot::CONTEXT) { 662 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 663 __ RecordWrite(scratch1, offset, src, scratch2); 664 } 665 } 666 667 668 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 669 Comment cmnt(masm_, "[ Declaration"); 670 Variable* var = decl->proxy()->var(); 671 ASSERT(var != NULL); // Must have been resolved. 672 Slot* slot = var->slot(); 673 Property* prop = var->AsProperty(); 674 675 if (slot != NULL) { 676 switch (slot->type()) { 677 case Slot::PARAMETER: 678 case Slot::LOCAL: 679 if (decl->mode() == Variable::CONST) { 680 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 681 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); 682 } else if (decl->fun() != NULL) { 683 VisitForValue(decl->fun(), kAccumulator); 684 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 685 } 686 break; 687 688 case Slot::CONTEXT: 689 // We bypass the general EmitSlotSearch because we know more about 690 // this specific context. 691 692 // The variable in the decl always resides in the current context. 693 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); 694 if (FLAG_debug_code) { 695 // Check if we have the correct context pointer. 696 __ movq(rbx, 697 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); 698 __ cmpq(rbx, rsi); 699 __ Check(equal, "Unexpected declaration in current context."); 700 } 701 if (decl->mode() == Variable::CONST) { 702 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 703 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 704 kScratchRegister); 705 // No write barrier since the hole value is in old space. 706 } else if (decl->fun() != NULL) { 707 VisitForValue(decl->fun(), kAccumulator); 708 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 709 result_register()); 710 int offset = Context::SlotOffset(slot->index()); 711 __ movq(rbx, rsi); 712 __ RecordWrite(rbx, offset, result_register(), rcx); 713 } 714 break; 715 716 case Slot::LOOKUP: { 717 __ push(rsi); 718 __ Push(var->name()); 719 // Declaration nodes are always introduced in one of two modes. 720 ASSERT(decl->mode() == Variable::VAR || 721 decl->mode() == Variable::CONST); 722 PropertyAttributes attr = 723 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; 724 __ Push(Smi::FromInt(attr)); 725 // Push initial value, if any. 726 // Note: For variables we must not push an initial value (such as 727 // 'undefined') because we may have a (legal) redeclaration and we 728 // must not destroy the current value. 729 if (decl->mode() == Variable::CONST) { 730 __ PushRoot(Heap::kTheHoleValueRootIndex); 731 } else if (decl->fun() != NULL) { 732 VisitForValue(decl->fun(), kStack); 733 } else { 734 __ Push(Smi::FromInt(0)); // no initial value! 735 } 736 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 737 break; 738 } 739 } 740 741 } else if (prop != NULL) { 742 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { 743 // We are declaring a function or constant that rewrites to a 744 // property. Use (keyed) IC to set the initial value. 745 VisitForValue(prop->obj(), kStack); 746 VisitForValue(prop->key(), kStack); 747 748 if (decl->fun() != NULL) { 749 VisitForValue(decl->fun(), kAccumulator); 750 } else { 751 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); 752 } 753 754 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 755 __ call(ic, RelocInfo::CODE_TARGET); 756 // Absence of a test rax instruction following the call 757 // indicates that none of the load was inlined. 758 __ nop(); 759 760 // Value in rax is ignored (declarations are statements). Receiver 761 // and key on stack are discarded. 762 __ Drop(2); 763 } 764 } 765 } 766 767 768 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 769 // Call the runtime to declare the globals. 770 __ push(rsi); // The context is the first argument. 771 __ Push(pairs); 772 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 773 __ CallRuntime(Runtime::kDeclareGlobals, 3); 774 // Return value is ignored. 775 } 776 777 778 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 779 Comment cmnt(masm_, "[ FunctionLiteral"); 780 781 // Build the function boilerplate and instantiate it. 782 Handle<JSFunction> boilerplate = 783 Compiler::BuildBoilerplate(expr, script(), this); 784 if (HasStackOverflow()) return; 785 786 ASSERT(boilerplate->IsBoilerplate()); 787 788 // Create a new closure. 789 __ push(rsi); 790 __ Push(boilerplate); 791 __ CallRuntime(Runtime::kNewClosure, 2); 792 Apply(context_, rax); 793 } 794 795 796 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 797 Comment cmnt(masm_, "[ VariableProxy"); 798 EmitVariableLoad(expr->var(), context_); 799 } 800 801 802 void FullCodeGenerator::EmitVariableLoad(Variable* var, 803 Expression::Context context) { 804 // Four cases: non-this global variables, lookup slots, all other 805 // types of slots, and parameters that rewrite to explicit property 806 // accesses on the arguments object. 807 Slot* slot = var->slot(); 808 Property* property = var->AsProperty(); 809 810 if (var->is_global() && !var->is_this()) { 811 Comment cmnt(masm_, "Global variable"); 812 // Use inline caching. Variable name is passed in rcx and the global 813 // object on the stack. 814 __ push(CodeGenerator::GlobalObject()); 815 __ Move(rcx, var->name()); 816 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 817 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); 818 // A test rax instruction following the call is used by the IC to 819 // indicate that the inobject property case was inlined. Ensure there 820 // is no test rax instruction here. 821 __ nop(); 822 DropAndApply(1, context, rax); 823 824 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 825 Comment cmnt(masm_, "Lookup slot"); 826 __ push(rsi); // Context. 827 __ Push(var->name()); 828 __ CallRuntime(Runtime::kLoadContextSlot, 2); 829 Apply(context, rax); 830 831 } else if (slot != NULL) { 832 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 833 ? "Context slot" 834 : "Stack slot"); 835 Apply(context, slot); 836 837 } else { 838 Comment cmnt(masm_, "Rewritten parameter"); 839 ASSERT_NOT_NULL(property); 840 // Rewritten parameter accesses are of the form "slot[literal]". 841 842 // Assert that the object is in a slot. 843 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 844 ASSERT_NOT_NULL(object_var); 845 Slot* object_slot = object_var->slot(); 846 ASSERT_NOT_NULL(object_slot); 847 848 // Load the object. 849 MemOperand object_loc = EmitSlotSearch(object_slot, rax); 850 __ push(object_loc); 851 852 // Assert that the key is a smi. 853 Literal* key_literal = property->key()->AsLiteral(); 854 ASSERT_NOT_NULL(key_literal); 855 ASSERT(key_literal->handle()->IsSmi()); 856 857 // Load the key. 858 __ Push(key_literal->handle()); 859 860 // Do a keyed property load. 861 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 862 __ call(ic, RelocInfo::CODE_TARGET); 863 // Notice: We must not have a "test rax, ..." instruction after the 864 // call. It is treated specially by the LoadIC code. 865 __ nop(); 866 // Drop key and object left on the stack by IC, and push the result. 867 DropAndApply(2, context, rax); 868 } 869 } 870 871 872 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 873 Comment cmnt(masm_, "[ RegExpLiteral"); 874 Label done; 875 // Registers will be used as follows: 876 // rdi = JS function. 877 // rbx = literals array. 878 // rax = regexp literal. 879 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 880 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); 881 int literal_offset = 882 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; 883 __ movq(rax, FieldOperand(rbx, literal_offset)); 884 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 885 __ j(not_equal, &done); 886 // Create regexp literal using runtime function 887 // Result will be in rax. 888 __ push(rbx); 889 __ Push(Smi::FromInt(expr->literal_index())); 890 __ Push(expr->pattern()); 891 __ Push(expr->flags()); 892 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 893 __ bind(&done); 894 Apply(context_, rax); 895 } 896 897 898 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 899 Comment cmnt(masm_, "[ ObjectLiteral"); 900 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 901 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); 902 __ Push(Smi::FromInt(expr->literal_index())); 903 __ Push(expr->constant_properties()); 904 if (expr->depth() > 1) { 905 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); 906 } else { 907 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); 908 } 909 910 // If result_saved is true the result is on top of the stack. If 911 // result_saved is false the result is in rax. 912 bool result_saved = false; 913 914 for (int i = 0; i < expr->properties()->length(); i++) { 915 ObjectLiteral::Property* property = expr->properties()->at(i); 916 if (property->IsCompileTimeValue()) continue; 917 918 Literal* key = property->key(); 919 Expression* value = property->value(); 920 if (!result_saved) { 921 __ push(rax); // Save result on the stack 922 result_saved = true; 923 } 924 switch (property->kind()) { 925 case ObjectLiteral::Property::CONSTANT: 926 UNREACHABLE(); 927 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 928 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); 929 // Fall through. 930 case ObjectLiteral::Property::COMPUTED: 931 if (key->handle()->IsSymbol()) { 932 VisitForValue(value, kAccumulator); 933 __ Move(rcx, key->handle()); 934 __ movq(rdx, Operand(rsp, 0)); 935 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 936 __ call(ic, RelocInfo::CODE_TARGET); 937 __ nop(); 938 break; 939 } 940 // Fall through. 941 case ObjectLiteral::Property::PROTOTYPE: 942 __ push(Operand(rsp, 0)); // Duplicate receiver. 943 VisitForValue(key, kStack); 944 VisitForValue(value, kStack); 945 __ CallRuntime(Runtime::kSetProperty, 3); 946 break; 947 case ObjectLiteral::Property::SETTER: 948 case ObjectLiteral::Property::GETTER: 949 __ push(Operand(rsp, 0)); // Duplicate receiver. 950 VisitForValue(key, kStack); 951 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? 952 Smi::FromInt(1) : 953 Smi::FromInt(0)); 954 VisitForValue(value, kStack); 955 __ CallRuntime(Runtime::kDefineAccessor, 4); 956 break; 957 } 958 } 959 960 if (result_saved) { 961 ApplyTOS(context_); 962 } else { 963 Apply(context_, rax); 964 } 965 } 966 967 968 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 969 Comment cmnt(masm_, "[ ArrayLiteral"); 970 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 971 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); 972 __ Push(Smi::FromInt(expr->literal_index())); 973 __ Push(expr->constant_elements()); 974 if (expr->depth() > 1) { 975 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 976 } else { 977 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 978 } 979 980 bool result_saved = false; // Is the result saved to the stack? 981 982 // Emit code to evaluate all the non-constant subexpressions and to store 983 // them into the newly cloned array. 984 ZoneList<Expression*>* subexprs = expr->values(); 985 for (int i = 0, len = subexprs->length(); i < len; i++) { 986 Expression* subexpr = subexprs->at(i); 987 // If the subexpression is a literal or a simple materialized literal it 988 // is already set in the cloned array. 989 if (subexpr->AsLiteral() != NULL || 990 CompileTimeValue::IsCompileTimeValue(subexpr)) { 991 continue; 992 } 993 994 if (!result_saved) { 995 __ push(rax); 996 result_saved = true; 997 } 998 VisitForValue(subexpr, kAccumulator); 999 1000 // Store the subexpression value in the array's elements. 1001 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. 1002 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); 1003 int offset = FixedArray::kHeaderSize + (i * kPointerSize); 1004 __ movq(FieldOperand(rbx, offset), result_register()); 1005 1006 // Update the write barrier for the array store. 1007 __ RecordWrite(rbx, offset, result_register(), rcx); 1008 } 1009 1010 if (result_saved) { 1011 ApplyTOS(context_); 1012 } else { 1013 Apply(context_, rax); 1014 } 1015 } 1016 1017 1018 void FullCodeGenerator::VisitAssignment(Assignment* expr) { 1019 Comment cmnt(masm_, "[ Assignment"); 1020 ASSERT(expr->op() != Token::INIT_CONST); 1021 // Left-hand side can only be a property, a global or a (parameter or local) 1022 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1023 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1024 LhsKind assign_type = VARIABLE; 1025 Property* prop = expr->target()->AsProperty(); 1026 if (prop != NULL) { 1027 assign_type = 1028 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1029 } 1030 1031 // Evaluate LHS expression. 1032 switch (assign_type) { 1033 case VARIABLE: 1034 // Nothing to do here. 1035 break; 1036 case NAMED_PROPERTY: 1037 if (expr->is_compound()) { 1038 // We need the receiver both on the stack and in the accumulator. 1039 VisitForValue(prop->obj(), kAccumulator); 1040 __ push(result_register()); 1041 } else { 1042 VisitForValue(prop->obj(), kStack); 1043 } 1044 break; 1045 case KEYED_PROPERTY: 1046 VisitForValue(prop->obj(), kStack); 1047 VisitForValue(prop->key(), kStack); 1048 break; 1049 } 1050 1051 // If we have a compound assignment: Get value of LHS expression and 1052 // store in on top of the stack. 1053 if (expr->is_compound()) { 1054 Location saved_location = location_; 1055 location_ = kStack; 1056 switch (assign_type) { 1057 case VARIABLE: 1058 EmitVariableLoad(expr->target()->AsVariableProxy()->var(), 1059 Expression::kValue); 1060 break; 1061 case NAMED_PROPERTY: 1062 EmitNamedPropertyLoad(prop); 1063 __ push(result_register()); 1064 break; 1065 case KEYED_PROPERTY: 1066 EmitKeyedPropertyLoad(prop); 1067 __ push(result_register()); 1068 break; 1069 } 1070 location_ = saved_location; 1071 } 1072 1073 // Evaluate RHS expression. 1074 Expression* rhs = expr->value(); 1075 VisitForValue(rhs, kAccumulator); 1076 1077 // If we have a compound assignment: Apply operator. 1078 if (expr->is_compound()) { 1079 Location saved_location = location_; 1080 location_ = kAccumulator; 1081 EmitBinaryOp(expr->binary_op(), Expression::kValue); 1082 location_ = saved_location; 1083 } 1084 1085 // Record source position before possible IC call. 1086 SetSourcePosition(expr->position()); 1087 1088 // Store the value. 1089 switch (assign_type) { 1090 case VARIABLE: 1091 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1092 context_); 1093 break; 1094 case NAMED_PROPERTY: 1095 EmitNamedPropertyAssignment(expr); 1096 break; 1097 case KEYED_PROPERTY: 1098 EmitKeyedPropertyAssignment(expr); 1099 break; 1100 } 1101 } 1102 1103 1104 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { 1105 SetSourcePosition(prop->position()); 1106 Literal* key = prop->key()->AsLiteral(); 1107 __ Move(rcx, key->handle()); 1108 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 1109 __ Call(ic, RelocInfo::CODE_TARGET); 1110 __ nop(); 1111 } 1112 1113 1114 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 1115 SetSourcePosition(prop->position()); 1116 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1117 __ Call(ic, RelocInfo::CODE_TARGET); 1118 __ nop(); 1119 } 1120 1121 1122 void FullCodeGenerator::EmitBinaryOp(Token::Value op, 1123 Expression::Context context) { 1124 __ push(result_register()); 1125 GenericBinaryOpStub stub(op, 1126 NO_OVERWRITE, 1127 NO_GENERIC_BINARY_FLAGS); 1128 __ CallStub(&stub); 1129 Apply(context, rax); 1130 } 1131 1132 1133 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1134 Expression::Context context) { 1135 // Three main cases: non-this global variables, lookup slots, and 1136 // all other types of slots. Left-hand-side parameters that rewrite 1137 // to explicit property accesses do not reach here. 1138 ASSERT(var != NULL); 1139 ASSERT(var->is_global() || var->slot() != NULL); 1140 Slot* slot = var->slot(); 1141 if (var->is_global()) { 1142 ASSERT(!var->is_this()); 1143 // Assignment to a global variable. Use inline caching for the 1144 // assignment. Right-hand-side value is passed in rax, variable name in 1145 // rcx, and the global object in rdx. 1146 __ Move(rcx, var->name()); 1147 __ movq(rdx, CodeGenerator::GlobalObject()); 1148 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1149 __ Call(ic, RelocInfo::CODE_TARGET); 1150 Apply(context, rax); 1151 1152 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 1153 __ push(result_register()); // Value. 1154 __ push(rsi); // Context. 1155 __ Push(var->name()); 1156 __ CallRuntime(Runtime::kStoreContextSlot, 3); 1157 Apply(context, rax); 1158 1159 } else if (var->slot() != NULL) { 1160 switch (slot->type()) { 1161 case Slot::LOCAL: 1162 case Slot::PARAMETER: 1163 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 1164 break; 1165 1166 case Slot::CONTEXT: { 1167 MemOperand target = EmitSlotSearch(slot, rcx); 1168 __ movq(target, result_register()); 1169 1170 // RecordWrite may destroy all its register arguments. 1171 __ movq(rdx, result_register()); 1172 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1173 __ RecordWrite(rcx, offset, rdx, rbx); 1174 break; 1175 } 1176 1177 case Slot::LOOKUP: 1178 UNREACHABLE(); 1179 break; 1180 } 1181 Apply(context, result_register()); 1182 1183 } else { 1184 // Variables rewritten as properties are not treated as variables in 1185 // assignments. 1186 UNREACHABLE(); 1187 } 1188 } 1189 1190 1191 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1192 // Assignment to a property, using a named store IC. 1193 Property* prop = expr->target()->AsProperty(); 1194 ASSERT(prop != NULL); 1195 ASSERT(prop->key()->AsLiteral() != NULL); 1196 1197 // If the assignment starts a block of assignments to the same object, 1198 // change to slow case to avoid the quadratic behavior of repeatedly 1199 // adding fast properties. 1200 if (expr->starts_initialization_block()) { 1201 __ push(result_register()); 1202 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. 1203 __ CallRuntime(Runtime::kToSlowProperties, 1); 1204 __ pop(result_register()); 1205 } 1206 1207 // Record source code position before IC call. 1208 SetSourcePosition(expr->position()); 1209 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1210 if (expr->ends_initialization_block()) { 1211 __ movq(rdx, Operand(rsp, 0)); 1212 } else { 1213 __ pop(rdx); 1214 } 1215 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1216 __ Call(ic, RelocInfo::CODE_TARGET); 1217 __ nop(); 1218 1219 // If the assignment ends an initialization block, revert to fast case. 1220 if (expr->ends_initialization_block()) { 1221 __ push(rax); // Result of assignment, saved even if not needed. 1222 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. 1223 __ CallRuntime(Runtime::kToFastProperties, 1); 1224 __ pop(rax); 1225 DropAndApply(1, context_, rax); 1226 } else { 1227 Apply(context_, rax); 1228 } 1229 } 1230 1231 1232 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { 1233 // Assignment to a property, using a keyed store IC. 1234 1235 // If the assignment starts a block of assignments to the same object, 1236 // change to slow case to avoid the quadratic behavior of repeatedly 1237 // adding fast properties. 1238 if (expr->starts_initialization_block()) { 1239 __ push(result_register()); 1240 // Receiver is now under the key and value. 1241 __ push(Operand(rsp, 2 * kPointerSize)); 1242 __ CallRuntime(Runtime::kToSlowProperties, 1); 1243 __ pop(result_register()); 1244 } 1245 1246 // Record source code position before IC call. 1247 SetSourcePosition(expr->position()); 1248 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1249 __ Call(ic, RelocInfo::CODE_TARGET); 1250 // This nop signals to the IC that there is no inlined code at the call 1251 // site for it to patch. 1252 __ nop(); 1253 1254 // If the assignment ends an initialization block, revert to fast case. 1255 if (expr->ends_initialization_block()) { 1256 __ push(rax); // Result of assignment, saved even if not needed. 1257 // Receiver is under the key and value. 1258 __ push(Operand(rsp, 2 * kPointerSize)); 1259 __ CallRuntime(Runtime::kToFastProperties, 1); 1260 __ pop(rax); 1261 } 1262 1263 // Receiver and key are still on stack. 1264 DropAndApply(2, context_, rax); 1265 } 1266 1267 1268 void FullCodeGenerator::VisitProperty(Property* expr) { 1269 Comment cmnt(masm_, "[ Property"); 1270 Expression* key = expr->key(); 1271 1272 // Evaluate receiver. 1273 VisitForValue(expr->obj(), kStack); 1274 1275 if (key->IsPropertyName()) { 1276 EmitNamedPropertyLoad(expr); 1277 // Drop receiver left on the stack by IC. 1278 DropAndApply(1, context_, rax); 1279 } else { 1280 VisitForValue(expr->key(), kStack); 1281 EmitKeyedPropertyLoad(expr); 1282 // Drop key and receiver left on the stack by IC. 1283 DropAndApply(2, context_, rax); 1284 } 1285 } 1286 1287 1288 void FullCodeGenerator::EmitCallWithIC(Call* expr, 1289 Handle<Object> name, 1290 RelocInfo::Mode mode) { 1291 // Code common for calls using the IC. 1292 ZoneList<Expression*>* args = expr->arguments(); 1293 int arg_count = args->length(); 1294 for (int i = 0; i < arg_count; i++) { 1295 VisitForValue(args->at(i), kStack); 1296 } 1297 __ Move(rcx, name); 1298 // Record source position for debugger. 1299 SetSourcePosition(expr->position()); 1300 // Call the IC initialization code. 1301 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 1302 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, 1303 in_loop); 1304 __ Call(ic, mode); 1305 // Restore context register. 1306 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1307 Apply(context_, rax); 1308 } 1309 1310 1311 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1312 // Code common for calls using the call stub. 1313 ZoneList<Expression*>* args = expr->arguments(); 1314 int arg_count = args->length(); 1315 for (int i = 0; i < arg_count; i++) { 1316 VisitForValue(args->at(i), kStack); 1317 } 1318 // Record source position for debugger. 1319 SetSourcePosition(expr->position()); 1320 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1321 __ CallStub(&stub); 1322 // Restore context register. 1323 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1324 // Discard the function left on TOS. 1325 DropAndApply(1, context_, rax); 1326 } 1327 1328 1329 void FullCodeGenerator::VisitCall(Call* expr) { 1330 Comment cmnt(masm_, "[ Call"); 1331 Expression* fun = expr->expression(); 1332 Variable* var = fun->AsVariableProxy()->AsVariable(); 1333 1334 if (var != NULL && var->is_possibly_eval()) { 1335 // Call to the identifier 'eval'. 1336 UNREACHABLE(); 1337 } else if (var != NULL && !var->is_this() && var->is_global()) { 1338 // Call to a global variable. 1339 // Push global object as receiver for the call IC lookup. 1340 __ push(CodeGenerator::GlobalObject()); 1341 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1342 } else if (var != NULL && var->slot() != NULL && 1343 var->slot()->type() == Slot::LOOKUP) { 1344 // Call to a lookup slot. 1345 UNREACHABLE(); 1346 } else if (fun->AsProperty() != NULL) { 1347 // Call to an object property. 1348 Property* prop = fun->AsProperty(); 1349 Literal* key = prop->key()->AsLiteral(); 1350 if (key != NULL && key->handle()->IsSymbol()) { 1351 // Call to a named property, use call IC. 1352 VisitForValue(prop->obj(), kStack); 1353 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1354 } else { 1355 // Call to a keyed property, use keyed load IC followed by function 1356 // call. 1357 VisitForValue(prop->obj(), kStack); 1358 VisitForValue(prop->key(), kStack); 1359 // Record source code position for IC call. 1360 SetSourcePosition(prop->position()); 1361 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1362 __ call(ic, RelocInfo::CODE_TARGET); 1363 // By emitting a nop we make sure that we do not have a "test rax,..." 1364 // instruction after the call it is treated specially by the LoadIC code. 1365 __ nop(); 1366 // Drop key left on the stack by IC. 1367 __ Drop(1); 1368 // Pop receiver. 1369 __ pop(rbx); 1370 // Push result (function). 1371 __ push(rax); 1372 // Push receiver object on stack. 1373 if (prop->is_synthetic()) { 1374 __ movq(rcx, CodeGenerator::GlobalObject()); 1375 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); 1376 } else { 1377 __ push(rbx); 1378 } 1379 EmitCallWithStub(expr); 1380 } 1381 } else { 1382 // Call to some other expression. If the expression is an anonymous 1383 // function literal not called in a loop, mark it as one that should 1384 // also use the fast code generator. 1385 FunctionLiteral* lit = fun->AsFunctionLiteral(); 1386 if (lit != NULL && 1387 lit->name()->Equals(Heap::empty_string()) && 1388 loop_depth() == 0) { 1389 lit->set_try_full_codegen(true); 1390 } 1391 VisitForValue(fun, kStack); 1392 // Load global receiver object. 1393 __ movq(rbx, CodeGenerator::GlobalObject()); 1394 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); 1395 // Emit function call. 1396 EmitCallWithStub(expr); 1397 } 1398 } 1399 1400 1401 void FullCodeGenerator::VisitCallNew(CallNew* expr) { 1402 Comment cmnt(masm_, "[ CallNew"); 1403 // According to ECMA-262, section 11.2.2, page 44, the function 1404 // expression in new calls must be evaluated before the 1405 // arguments. 1406 // Push function on the stack. 1407 VisitForValue(expr->expression(), kStack); 1408 1409 // Push global object (receiver). 1410 __ push(CodeGenerator::GlobalObject()); 1411 1412 // Push the arguments ("left-to-right") on the stack. 1413 ZoneList<Expression*>* args = expr->arguments(); 1414 int arg_count = args->length(); 1415 for (int i = 0; i < arg_count; i++) { 1416 VisitForValue(args->at(i), kStack); 1417 } 1418 1419 // Call the construct call builtin that handles allocation and 1420 // constructor invocation. 1421 SetSourcePosition(expr->position()); 1422 1423 // Load function, arg_count into rdi and rax. 1424 __ Set(rax, arg_count); 1425 // Function is in rsp[arg_count + 1]. 1426 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); 1427 1428 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1429 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1430 1431 // Replace function on TOS with result in rax, or pop it. 1432 DropAndApply(1, context_, rax); 1433 } 1434 1435 1436 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 1437 Comment cmnt(masm_, "[ CallRuntime"); 1438 ZoneList<Expression*>* args = expr->arguments(); 1439 1440 if (expr->is_jsruntime()) { 1441 // Prepare for calling JS runtime function. 1442 __ movq(rax, CodeGenerator::GlobalObject()); 1443 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); 1444 } 1445 1446 // Push the arguments ("left-to-right"). 1447 int arg_count = args->length(); 1448 for (int i = 0; i < arg_count; i++) { 1449 VisitForValue(args->at(i), kStack); 1450 } 1451 1452 if (expr->is_jsruntime()) { 1453 // Call the JS runtime function using a call IC. 1454 __ Move(rcx, expr->name()); 1455 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 1456 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); 1457 __ call(ic, RelocInfo::CODE_TARGET); 1458 // Restore context register. 1459 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1460 } else { 1461 __ CallRuntime(expr->function(), arg_count); 1462 } 1463 Apply(context_, rax); 1464 } 1465 1466 1467 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 1468 switch (expr->op()) { 1469 case Token::VOID: { 1470 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 1471 VisitForEffect(expr->expression()); 1472 switch (context_) { 1473 case Expression::kUninitialized: 1474 UNREACHABLE(); 1475 break; 1476 case Expression::kEffect: 1477 break; 1478 case Expression::kValue: 1479 switch (location_) { 1480 case kAccumulator: 1481 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); 1482 break; 1483 case kStack: 1484 __ PushRoot(Heap::kUndefinedValueRootIndex); 1485 break; 1486 } 1487 break; 1488 case Expression::kTestValue: 1489 // Value is false so it's needed. 1490 switch (location_) { 1491 case kAccumulator: 1492 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex); 1493 break; 1494 case kStack: 1495 __ PushRoot(Heap::kUndefinedValueRootIndex); 1496 break; 1497 } 1498 // Fall through. 1499 case Expression::kTest: 1500 case Expression::kValueTest: 1501 __ jmp(false_label_); 1502 break; 1503 } 1504 break; 1505 } 1506 1507 case Token::NOT: { 1508 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 1509 Label materialize_true, materialize_false, done; 1510 // Initially assume a pure test context. Notice that the labels are 1511 // swapped. 1512 Label* if_true = false_label_; 1513 Label* if_false = true_label_; 1514 switch (context_) { 1515 case Expression::kUninitialized: 1516 UNREACHABLE(); 1517 break; 1518 case Expression::kEffect: 1519 if_true = &done; 1520 if_false = &done; 1521 break; 1522 case Expression::kValue: 1523 if_true = &materialize_false; 1524 if_false = &materialize_true; 1525 break; 1526 case Expression::kTest: 1527 break; 1528 case Expression::kValueTest: 1529 if_false = &materialize_true; 1530 break; 1531 case Expression::kTestValue: 1532 if_true = &materialize_false; 1533 break; 1534 } 1535 VisitForControl(expr->expression(), if_true, if_false); 1536 Apply(context_, if_false, if_true); // Labels swapped. 1537 break; 1538 } 1539 1540 case Token::TYPEOF: { 1541 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 1542 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 1543 if (proxy != NULL && 1544 !proxy->var()->is_this() && 1545 proxy->var()->is_global()) { 1546 Comment cmnt(masm_, "Global variable"); 1547 __ push(CodeGenerator::GlobalObject()); 1548 __ Move(rcx, proxy->name()); 1549 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 1550 // Use a regular load, not a contextual load, to avoid a reference 1551 // error. 1552 __ Call(ic, RelocInfo::CODE_TARGET); 1553 __ movq(Operand(rsp, 0), rax); 1554 } else if (proxy != NULL && 1555 proxy->var()->slot() != NULL && 1556 proxy->var()->slot()->type() == Slot::LOOKUP) { 1557 __ push(rsi); 1558 __ Push(proxy->name()); 1559 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 1560 __ push(rax); 1561 } else { 1562 // This expression cannot throw a reference error at the top level. 1563 VisitForValue(expr->expression(), kStack); 1564 } 1565 1566 __ CallRuntime(Runtime::kTypeof, 1); 1567 Apply(context_, rax); 1568 break; 1569 } 1570 1571 case Token::ADD: { 1572 Comment cmt(masm_, "[ UnaryOperation (ADD)"); 1573 VisitForValue(expr->expression(), kAccumulator); 1574 Label no_conversion; 1575 Condition is_smi = masm_->CheckSmi(result_register()); 1576 __ j(is_smi, &no_conversion); 1577 __ push(result_register()); 1578 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 1579 __ bind(&no_conversion); 1580 Apply(context_, result_register()); 1581 break; 1582 } 1583 1584 case Token::SUB: { 1585 Comment cmt(masm_, "[ UnaryOperation (SUB)"); 1586 bool overwrite = 1587 (expr->expression()->AsBinaryOperation() != NULL && 1588 expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); 1589 GenericUnaryOpStub stub(Token::SUB, overwrite); 1590 // GenericUnaryOpStub expects the argument to be in the 1591 // accumulator register rax. 1592 VisitForValue(expr->expression(), kAccumulator); 1593 __ CallStub(&stub); 1594 Apply(context_, rax); 1595 break; 1596 } 1597 1598 case Token::BIT_NOT: { 1599 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); 1600 bool overwrite = 1601 (expr->expression()->AsBinaryOperation() != NULL && 1602 expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); 1603 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); 1604 // GenericUnaryOpStub expects the argument to be in the 1605 // accumulator register rax. 1606 VisitForValue(expr->expression(), kAccumulator); 1607 // Avoid calling the stub for Smis. 1608 Label smi, done; 1609 Condition is_smi = masm_->CheckSmi(result_register()); 1610 __ j(is_smi, &smi); 1611 // Non-smi: call stub leaving result in accumulator register. 1612 __ CallStub(&stub); 1613 __ jmp(&done); 1614 // Perform operation directly on Smis. 1615 __ bind(&smi); 1616 __ SmiNot(result_register(), result_register()); 1617 __ bind(&done); 1618 Apply(context_, result_register()); 1619 break; 1620 } 1621 1622 default: 1623 UNREACHABLE(); 1624 } 1625 } 1626 1627 1628 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 1629 Comment cmnt(masm_, "[ CountOperation"); 1630 1631 // Expression can only be a property, a global or a (parameter or local) 1632 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1633 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1634 LhsKind assign_type = VARIABLE; 1635 Property* prop = expr->expression()->AsProperty(); 1636 // In case of a property we use the uninitialized expression context 1637 // of the key to detect a named property. 1638 if (prop != NULL) { 1639 assign_type = 1640 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1641 } 1642 1643 // Evaluate expression and get value. 1644 if (assign_type == VARIABLE) { 1645 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 1646 Location saved_location = location_; 1647 location_ = kAccumulator; 1648 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 1649 Expression::kValue); 1650 location_ = saved_location; 1651 } else { 1652 // Reserve space for result of postfix operation. 1653 if (expr->is_postfix() && context_ != Expression::kEffect) { 1654 __ Push(Smi::FromInt(0)); 1655 } 1656 VisitForValue(prop->obj(), kStack); 1657 if (assign_type == NAMED_PROPERTY) { 1658 EmitNamedPropertyLoad(prop); 1659 } else { 1660 VisitForValue(prop->key(), kStack); 1661 EmitKeyedPropertyLoad(prop); 1662 } 1663 } 1664 1665 // Call ToNumber only if operand is not a smi. 1666 Label no_conversion; 1667 Condition is_smi; 1668 is_smi = masm_->CheckSmi(rax); 1669 __ j(is_smi, &no_conversion); 1670 __ push(rax); 1671 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 1672 __ bind(&no_conversion); 1673 1674 // Save result for postfix expressions. 1675 if (expr->is_postfix()) { 1676 switch (context_) { 1677 case Expression::kUninitialized: 1678 UNREACHABLE(); 1679 case Expression::kEffect: 1680 // Do not save result. 1681 break; 1682 case Expression::kValue: 1683 case Expression::kTest: 1684 case Expression::kValueTest: 1685 case Expression::kTestValue: 1686 // Save the result on the stack. If we have a named or keyed property 1687 // we store the result under the receiver that is currently on top 1688 // of the stack. 1689 switch (assign_type) { 1690 case VARIABLE: 1691 __ push(rax); 1692 break; 1693 case NAMED_PROPERTY: 1694 __ movq(Operand(rsp, kPointerSize), rax); 1695 break; 1696 case KEYED_PROPERTY: 1697 __ movq(Operand(rsp, 2 * kPointerSize), rax); 1698 break; 1699 } 1700 break; 1701 } 1702 } 1703 1704 // Inline smi case if we are in a loop. 1705 Label stub_call, done; 1706 if (loop_depth() > 0) { 1707 if (expr->op() == Token::INC) { 1708 __ SmiAddConstant(rax, rax, Smi::FromInt(1)); 1709 } else { 1710 __ SmiSubConstant(rax, rax, Smi::FromInt(1)); 1711 } 1712 __ j(overflow, &stub_call); 1713 // We could eliminate this smi check if we split the code at 1714 // the first smi check before calling ToNumber. 1715 is_smi = masm_->CheckSmi(rax); 1716 __ j(is_smi, &done); 1717 __ bind(&stub_call); 1718 // Call stub. Undo operation first. 1719 if (expr->op() == Token::INC) { 1720 __ SmiSubConstant(rax, rax, Smi::FromInt(1)); 1721 } else { 1722 __ SmiAddConstant(rax, rax, Smi::FromInt(1)); 1723 } 1724 } 1725 // Call stub for +1/-1. 1726 GenericBinaryOpStub stub(expr->binary_op(), 1727 NO_OVERWRITE, 1728 NO_GENERIC_BINARY_FLAGS); 1729 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); 1730 __ bind(&done); 1731 1732 // Store the value returned in rax. 1733 switch (assign_type) { 1734 case VARIABLE: 1735 if (expr->is_postfix()) { 1736 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 1737 Expression::kEffect); 1738 // For all contexts except kEffect: We have the result on 1739 // top of the stack. 1740 if (context_ != Expression::kEffect) { 1741 ApplyTOS(context_); 1742 } 1743 } else { 1744 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 1745 context_); 1746 } 1747 break; 1748 case NAMED_PROPERTY: { 1749 __ Move(rcx, prop->key()->AsLiteral()->handle()); 1750 __ pop(rdx); 1751 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1752 __ call(ic, RelocInfo::CODE_TARGET); 1753 // This nop signals to the IC that there is no inlined code at the call 1754 // site for it to patch. 1755 __ nop(); 1756 if (expr->is_postfix()) { 1757 if (context_ != Expression::kEffect) { 1758 ApplyTOS(context_); 1759 } 1760 } else { 1761 Apply(context_, rax); 1762 } 1763 break; 1764 } 1765 case KEYED_PROPERTY: { 1766 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1767 __ call(ic, RelocInfo::CODE_TARGET); 1768 // This nop signals to the IC that there is no inlined code at the call 1769 // site for it to patch. 1770 __ nop(); 1771 if (expr->is_postfix()) { 1772 __ Drop(2); // Result is on the stack under the key and the receiver. 1773 if (context_ != Expression::kEffect) { 1774 ApplyTOS(context_); 1775 } 1776 } else { 1777 DropAndApply(2, context_, rax); 1778 } 1779 break; 1780 } 1781 } 1782 } 1783 1784 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { 1785 Comment cmnt(masm_, "[ BinaryOperation"); 1786 switch (expr->op()) { 1787 case Token::COMMA: 1788 VisitForEffect(expr->left()); 1789 Visit(expr->right()); 1790 break; 1791 1792 case Token::OR: 1793 case Token::AND: 1794 EmitLogicalOperation(expr); 1795 break; 1796 1797 case Token::ADD: 1798 case Token::SUB: 1799 case Token::DIV: 1800 case Token::MOD: 1801 case Token::MUL: 1802 case Token::BIT_OR: 1803 case Token::BIT_AND: 1804 case Token::BIT_XOR: 1805 case Token::SHL: 1806 case Token::SHR: 1807 case Token::SAR: 1808 VisitForValue(expr->left(), kStack); 1809 VisitForValue(expr->right(), kAccumulator); 1810 EmitBinaryOp(expr->op(), context_); 1811 break; 1812 1813 default: 1814 UNREACHABLE(); 1815 } 1816 } 1817 1818 1819 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 1820 Comment cmnt(masm_, "[ CompareOperation"); 1821 1822 // Always perform the comparison for its control flow. Pack the result 1823 // into the expression's context after the comparison is performed. 1824 Label materialize_true, materialize_false, done; 1825 // Initially assume we are in a test context. 1826 Label* if_true = true_label_; 1827 Label* if_false = false_label_; 1828 switch (context_) { 1829 case Expression::kUninitialized: 1830 UNREACHABLE(); 1831 break; 1832 case Expression::kEffect: 1833 if_true = &done; 1834 if_false = &done; 1835 break; 1836 case Expression::kValue: 1837 if_true = &materialize_true; 1838 if_false = &materialize_false; 1839 break; 1840 case Expression::kTest: 1841 break; 1842 case Expression::kValueTest: 1843 if_true = &materialize_true; 1844 break; 1845 case Expression::kTestValue: 1846 if_false = &materialize_false; 1847 break; 1848 } 1849 1850 VisitForValue(expr->left(), kStack); 1851 switch (expr->op()) { 1852 case Token::IN: 1853 VisitForValue(expr->right(), kStack); 1854 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 1855 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 1856 __ j(equal, if_true); 1857 __ jmp(if_false); 1858 break; 1859 1860 case Token::INSTANCEOF: { 1861 VisitForValue(expr->right(), kStack); 1862 InstanceofStub stub; 1863 __ CallStub(&stub); 1864 __ testq(rax, rax); 1865 __ j(zero, if_true); // The stub returns 0 for true. 1866 __ jmp(if_false); 1867 break; 1868 } 1869 1870 default: { 1871 VisitForValue(expr->right(), kAccumulator); 1872 Condition cc = no_condition; 1873 bool strict = false; 1874 switch (expr->op()) { 1875 case Token::EQ_STRICT: 1876 strict = true; 1877 // Fall through. 1878 case Token::EQ: 1879 cc = equal; 1880 __ pop(rdx); 1881 break; 1882 case Token::LT: 1883 cc = less; 1884 __ pop(rdx); 1885 break; 1886 case Token::GT: 1887 // Reverse left and right sizes to obtain ECMA-262 conversion order. 1888 cc = less; 1889 __ movq(rdx, result_register()); 1890 __ pop(rax); 1891 break; 1892 case Token::LTE: 1893 // Reverse left and right sizes to obtain ECMA-262 conversion order. 1894 cc = greater_equal; 1895 __ movq(rdx, result_register()); 1896 __ pop(rax); 1897 break; 1898 case Token::GTE: 1899 cc = greater_equal; 1900 __ pop(rdx); 1901 break; 1902 case Token::IN: 1903 case Token::INSTANCEOF: 1904 default: 1905 UNREACHABLE(); 1906 } 1907 1908 // The comparison stub expects the smi vs. smi case to be handled 1909 // before it is called. 1910 Label slow_case; 1911 __ JumpIfNotBothSmi(rax, rdx, &slow_case); 1912 __ SmiCompare(rdx, rax); 1913 __ j(cc, if_true); 1914 __ jmp(if_false); 1915 1916 __ bind(&slow_case); 1917 CompareStub stub(cc, strict); 1918 __ CallStub(&stub); 1919 __ testq(rax, rax); 1920 __ j(cc, if_true); 1921 __ jmp(if_false); 1922 } 1923 } 1924 1925 // Convert the result of the comparison into one expected for this 1926 // expression's context. 1927 Apply(context_, if_true, if_false); 1928 } 1929 1930 1931 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { 1932 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 1933 Apply(context_, rax); 1934 } 1935 1936 1937 Register FullCodeGenerator::result_register() { return rax; } 1938 1939 1940 Register FullCodeGenerator::context_register() { return rsi; } 1941 1942 1943 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 1944 ASSERT(IsAligned(frame_offset, kPointerSize)); 1945 __ movq(Operand(rbp, frame_offset), value); 1946 } 1947 1948 1949 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { 1950 __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index)); 1951 } 1952 1953 1954 // ---------------------------------------------------------------------------- 1955 // Non-local control flow support. 1956 1957 1958 void FullCodeGenerator::EnterFinallyBlock() { 1959 ASSERT(!result_register().is(rdx)); 1960 ASSERT(!result_register().is(rcx)); 1961 // Cook return address on top of stack (smi encoded Code* delta) 1962 __ movq(rdx, Operand(rsp, 0)); 1963 __ Move(rcx, masm_->CodeObject()); 1964 __ subq(rdx, rcx); 1965 __ Integer32ToSmi(rdx, rdx); 1966 __ movq(Operand(rsp, 0), rdx); 1967 // Store result register while executing finally block. 1968 __ push(result_register()); 1969 } 1970 1971 1972 void FullCodeGenerator::ExitFinallyBlock() { 1973 ASSERT(!result_register().is(rdx)); 1974 ASSERT(!result_register().is(rcx)); 1975 // Restore result register from stack. 1976 __ pop(result_register()); 1977 // Uncook return address. 1978 __ movq(rdx, Operand(rsp, 0)); 1979 __ SmiToInteger32(rdx, rdx); 1980 __ Move(rcx, masm_->CodeObject()); 1981 __ addq(rdx, rcx); 1982 __ movq(Operand(rsp, 0), rdx); 1983 // And return. 1984 __ ret(0); 1985 } 1986 1987 1988 #undef __ 1989 1990 1991 } } // namespace v8::internal 1992