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