| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 __ mov(eax, Immediate(Factory::undefined_value())); | 72 __ mov(eax, Immediate(Factory::undefined_value())); |
| 73 for (int i = 0; i < locals_count; i++) { | 73 for (int i = 0; i < locals_count; i++) { |
| 74 __ push(eax); | 74 __ push(eax); |
| 75 } | 75 } |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 | 78 |
| 79 bool function_in_register = true; | 79 bool function_in_register = true; |
| 80 | 80 |
| 81 // Possibly allocate a local context. | 81 // Possibly allocate a local context. |
| 82 if (scope()->num_heap_slots() > 0) { | 82 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 83 if (heap_slots > 0) { |
| 83 Comment cmnt(masm_, "[ Allocate local context"); | 84 Comment cmnt(masm_, "[ Allocate local context"); |
| 84 // Argument to NewContext is the function, which is still in edi. | 85 // Argument to NewContext is the function, which is still in edi. |
| 85 __ push(edi); | 86 __ push(edi); |
| 86 __ CallRuntime(Runtime::kNewContext, 1); | 87 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 88 FastNewContextStub stub(heap_slots); |
| 89 __ CallStub(&stub); |
| 90 } else { |
| 91 __ CallRuntime(Runtime::kNewContext, 1); |
| 92 } |
| 87 function_in_register = false; | 93 function_in_register = false; |
| 88 // Context is returned in both eax and esi. It replaces the context | 94 // Context is returned in both eax and esi. It replaces the context |
| 89 // passed to us. It's saved in the stack and kept live in esi. | 95 // passed to us. It's saved in the stack and kept live in esi. |
| 90 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 96 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 91 | 97 |
| 92 // Copy parameters into context if necessary. | 98 // Copy parameters into context if necessary. |
| 93 int num_parameters = scope()->num_parameters(); | 99 int num_parameters = scope()->num_parameters(); |
| 94 for (int i = 0; i < num_parameters; i++) { | 100 for (int i = 0; i < num_parameters; i++) { |
| 95 Slot* slot = scope()->parameter(i)->slot(); | 101 Slot* slot = scope()->parameter(i)->slot(); |
| 96 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 102 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 __ CallStub(&stub); | 139 __ CallStub(&stub); |
| 134 __ mov(ecx, eax); // Duplicate result. | 140 __ mov(ecx, eax); // Duplicate result. |
| 135 Move(arguments->slot(), eax, ebx, edx); | 141 Move(arguments->slot(), eax, ebx, edx); |
| 136 Slot* dot_arguments_slot = | 142 Slot* dot_arguments_slot = |
| 137 scope()->arguments_shadow()->AsVariable()->slot(); | 143 scope()->arguments_shadow()->AsVariable()->slot(); |
| 138 Move(dot_arguments_slot, ecx, ebx, edx); | 144 Move(dot_arguments_slot, ecx, ebx, edx); |
| 139 } | 145 } |
| 140 } | 146 } |
| 141 | 147 |
| 142 { Comment cmnt(masm_, "[ Declarations"); | 148 { Comment cmnt(masm_, "[ Declarations"); |
| 143 VisitDeclarations(scope()->declarations()); | 149 // For named function expressions, declare the function name as a |
| 150 // constant. |
| 151 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 152 EmitDeclaration(scope()->function(), Variable::CONST, NULL); |
| 153 } |
| 154 // Visit all the explicit declarations unless there is an illegal |
| 155 // redeclaration. |
| 156 if (scope()->HasIllegalRedeclaration()) { |
| 157 scope()->VisitIllegalRedeclaration(this); |
| 158 } else { |
| 159 VisitDeclarations(scope()->declarations()); |
| 160 } |
| 144 } | 161 } |
| 145 | 162 |
| 146 { Comment cmnt(masm_, "[ Stack check"); | 163 { Comment cmnt(masm_, "[ Stack check"); |
| 147 Label ok; | 164 Label ok; |
| 148 ExternalReference stack_limit = | 165 ExternalReference stack_limit = |
| 149 ExternalReference::address_of_stack_limit(); | 166 ExternalReference::address_of_stack_limit(); |
| 150 __ cmp(esp, Operand::StaticVariable(stack_limit)); | 167 __ cmp(esp, Operand::StaticVariable(stack_limit)); |
| 151 __ j(above_equal, &ok, taken); | 168 __ j(above_equal, &ok, taken); |
| 152 StackCheckStub stub; | 169 StackCheckStub stub; |
| 153 __ CallStub(&stub); | 170 __ CallStub(&stub); |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 __ mov(result_register(), reg); | 435 __ mov(result_register(), reg); |
| 419 __ mov(Operand(esp, 0), result_register()); | 436 __ mov(Operand(esp, 0), result_register()); |
| 420 break; | 437 break; |
| 421 } | 438 } |
| 422 DoTest(context); | 439 DoTest(context); |
| 423 break; | 440 break; |
| 424 } | 441 } |
| 425 } | 442 } |
| 426 | 443 |
| 427 | 444 |
| 445 void FullCodeGenerator::PrepareTest(Label* materialize_true, |
| 446 Label* materialize_false, |
| 447 Label** if_true, |
| 448 Label** if_false) { |
| 449 switch (context_) { |
| 450 case Expression::kUninitialized: |
| 451 UNREACHABLE(); |
| 452 break; |
| 453 case Expression::kEffect: |
| 454 // In an effect context, the true and the false case branch to the |
| 455 // same label. |
| 456 *if_true = *if_false = materialize_true; |
| 457 break; |
| 458 case Expression::kValue: |
| 459 *if_true = materialize_true; |
| 460 *if_false = materialize_false; |
| 461 break; |
| 462 case Expression::kTest: |
| 463 *if_true = true_label_; |
| 464 *if_false = false_label_; |
| 465 break; |
| 466 case Expression::kValueTest: |
| 467 *if_true = materialize_true; |
| 468 *if_false = false_label_; |
| 469 break; |
| 470 case Expression::kTestValue: |
| 471 *if_true = true_label_; |
| 472 *if_false = materialize_false; |
| 473 break; |
| 474 } |
| 475 } |
| 476 |
| 477 |
| 428 void FullCodeGenerator::Apply(Expression::Context context, | 478 void FullCodeGenerator::Apply(Expression::Context context, |
| 429 Label* materialize_true, | 479 Label* materialize_true, |
| 430 Label* materialize_false) { | 480 Label* materialize_false) { |
| 431 switch (context) { | 481 switch (context) { |
| 432 case Expression::kUninitialized: | 482 case Expression::kUninitialized: |
| 433 | 483 |
| 434 case Expression::kEffect: | 484 case Expression::kEffect: |
| 435 ASSERT_EQ(materialize_true, materialize_false); | 485 ASSERT_EQ(materialize_true, materialize_false); |
| 436 __ bind(materialize_true); | 486 __ bind(materialize_true); |
| 437 break; | 487 break; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 case kStack: | 533 case kStack: |
| 484 __ push(Immediate(Factory::false_value())); | 534 __ push(Immediate(Factory::false_value())); |
| 485 break; | 535 break; |
| 486 } | 536 } |
| 487 __ jmp(false_label_); | 537 __ jmp(false_label_); |
| 488 break; | 538 break; |
| 489 } | 539 } |
| 490 } | 540 } |
| 491 | 541 |
| 492 | 542 |
| 543 // Convert constant control flow (true or false) to the result expected for |
| 544 // a given expression context. |
| 545 void FullCodeGenerator::Apply(Expression::Context context, bool flag) { |
| 546 switch (context) { |
| 547 case Expression::kUninitialized: |
| 548 UNREACHABLE(); |
| 549 break; |
| 550 case Expression::kEffect: |
| 551 break; |
| 552 case Expression::kValue: { |
| 553 Handle<Object> value = |
| 554 flag ? Factory::true_value() : Factory::false_value(); |
| 555 switch (location_) { |
| 556 case kAccumulator: |
| 557 __ mov(result_register(), value); |
| 558 break; |
| 559 case kStack: |
| 560 __ push(Immediate(value)); |
| 561 break; |
| 562 } |
| 563 break; |
| 564 } |
| 565 case Expression::kTest: |
| 566 __ jmp(flag ? true_label_ : false_label_); |
| 567 break; |
| 568 case Expression::kTestValue: |
| 569 switch (location_) { |
| 570 case kAccumulator: |
| 571 // If value is false it's needed. |
| 572 if (!flag) __ mov(result_register(), Factory::false_value()); |
| 573 break; |
| 574 case kStack: |
| 575 // If value is false it's needed. |
| 576 if (!flag) __ push(Immediate(Factory::false_value())); |
| 577 break; |
| 578 } |
| 579 __ jmp(flag ? true_label_ : false_label_); |
| 580 break; |
| 581 case Expression::kValueTest: |
| 582 switch (location_) { |
| 583 case kAccumulator: |
| 584 // If value is true it's needed. |
| 585 if (flag) __ mov(result_register(), Factory::true_value()); |
| 586 break; |
| 587 case kStack: |
| 588 // If value is true it's needed. |
| 589 if (flag) __ push(Immediate(Factory::true_value())); |
| 590 break; |
| 591 } |
| 592 __ jmp(flag ? true_label_ : false_label_); |
| 593 break; |
| 594 } |
| 595 } |
| 596 |
| 597 |
| 493 void FullCodeGenerator::DoTest(Expression::Context context) { | 598 void FullCodeGenerator::DoTest(Expression::Context context) { |
| 494 // The value to test is in the accumulator. If the value might be needed | 599 // 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 | 600 // on the stack (value/test and test/value contexts with a stack location |
| 496 // desired), then the value is already duplicated on the stack. | 601 // desired), then the value is already duplicated on the stack. |
| 497 ASSERT_NE(NULL, true_label_); | 602 ASSERT_NE(NULL, true_label_); |
| 498 ASSERT_NE(NULL, false_label_); | 603 ASSERT_NE(NULL, false_label_); |
| 499 | 604 |
| 500 // In value/test and test/value expression contexts with stack as the | 605 // 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 | 606 // desired location, there is already an extra value on the stack. Use a |
| 502 // label to discard it if unneeded. | 607 // label to discard it if unneeded. |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 658 MemOperand location = EmitSlotSearch(dst, scratch1); | 763 MemOperand location = EmitSlotSearch(dst, scratch1); |
| 659 __ mov(location, src); | 764 __ mov(location, src); |
| 660 // Emit the write barrier code if the location is in the heap. | 765 // Emit the write barrier code if the location is in the heap. |
| 661 if (dst->type() == Slot::CONTEXT) { | 766 if (dst->type() == Slot::CONTEXT) { |
| 662 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; | 767 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; |
| 663 __ RecordWrite(scratch1, offset, src, scratch2); | 768 __ RecordWrite(scratch1, offset, src, scratch2); |
| 664 } | 769 } |
| 665 } | 770 } |
| 666 | 771 |
| 667 | 772 |
| 668 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 773 void FullCodeGenerator::EmitDeclaration(Variable* variable, |
| 774 Variable::Mode mode, |
| 775 FunctionLiteral* function) { |
| 669 Comment cmnt(masm_, "[ Declaration"); | 776 Comment cmnt(masm_, "[ Declaration"); |
| 670 Variable* var = decl->proxy()->var(); | 777 ASSERT(variable != NULL); // Must have been resolved. |
| 671 ASSERT(var != NULL); // Must have been resolved. | 778 Slot* slot = variable->slot(); |
| 672 Slot* slot = var->slot(); | 779 Property* prop = variable->AsProperty(); |
| 673 Property* prop = var->AsProperty(); | |
| 674 | |
| 675 if (slot != NULL) { | 780 if (slot != NULL) { |
| 676 switch (slot->type()) { | 781 switch (slot->type()) { |
| 677 case Slot::PARAMETER: | 782 case Slot::PARAMETER: |
| 678 case Slot::LOCAL: | 783 case Slot::LOCAL: |
| 679 if (decl->mode() == Variable::CONST) { | 784 if (mode == Variable::CONST) { |
| 680 __ mov(Operand(ebp, SlotOffset(slot)), | 785 __ mov(Operand(ebp, SlotOffset(slot)), |
| 681 Immediate(Factory::the_hole_value())); | 786 Immediate(Factory::the_hole_value())); |
| 682 } else if (decl->fun() != NULL) { | 787 } else if (function != NULL) { |
| 683 VisitForValue(decl->fun(), kAccumulator); | 788 VisitForValue(function, kAccumulator); |
| 684 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 789 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); |
| 685 } | 790 } |
| 686 break; | 791 break; |
| 687 | 792 |
| 688 case Slot::CONTEXT: | 793 case Slot::CONTEXT: |
| 689 // We bypass the general EmitSlotSearch because we know more about | 794 // We bypass the general EmitSlotSearch because we know more about |
| 690 // this specific context. | 795 // this specific context. |
| 691 | 796 |
| 692 // The variable in the decl always resides in the current context. | 797 // The variable in the decl always resides in the current context. |
| 693 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); | 798 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 694 if (FLAG_debug_code) { | 799 if (FLAG_debug_code) { |
| 695 // Check if we have the correct context pointer. | 800 // Check if we have the correct context pointer. |
| 696 __ mov(ebx, | 801 __ mov(ebx, |
| 697 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); | 802 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); |
| 698 __ cmp(ebx, Operand(esi)); | 803 __ cmp(ebx, Operand(esi)); |
| 699 __ Check(equal, "Unexpected declaration in current context."); | 804 __ Check(equal, "Unexpected declaration in current context."); |
| 700 } | 805 } |
| 701 if (decl->mode() == Variable::CONST) { | 806 if (mode == Variable::CONST) { |
| 702 __ mov(eax, Immediate(Factory::the_hole_value())); | 807 __ mov(eax, Immediate(Factory::the_hole_value())); |
| 703 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); | 808 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); |
| 704 // No write barrier since the hole value is in old space. | 809 // No write barrier since the hole value is in old space. |
| 705 } else if (decl->fun() != NULL) { | 810 } else if (function != NULL) { |
| 706 VisitForValue(decl->fun(), kAccumulator); | 811 VisitForValue(function, kAccumulator); |
| 707 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), | 812 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), |
| 708 result_register()); | 813 result_register()); |
| 709 int offset = Context::SlotOffset(slot->index()); | 814 int offset = Context::SlotOffset(slot->index()); |
| 710 __ mov(ebx, esi); | 815 __ mov(ebx, esi); |
| 711 __ RecordWrite(ebx, offset, result_register(), ecx); | 816 __ RecordWrite(ebx, offset, result_register(), ecx); |
| 712 } | 817 } |
| 713 break; | 818 break; |
| 714 | 819 |
| 715 case Slot::LOOKUP: { | 820 case Slot::LOOKUP: { |
| 716 __ push(esi); | 821 __ push(esi); |
| 717 __ push(Immediate(var->name())); | 822 __ push(Immediate(variable->name())); |
| 718 // Declaration nodes are always introduced in one of two modes. | 823 // Declaration nodes are always introduced in one of two modes. |
| 719 ASSERT(decl->mode() == Variable::VAR || | 824 ASSERT(mode == Variable::VAR || |
| 720 decl->mode() == Variable::CONST); | 825 mode == Variable::CONST); |
| 721 PropertyAttributes attr = | 826 PropertyAttributes attr = |
| 722 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; | 827 (mode == Variable::VAR) ? NONE : READ_ONLY; |
| 723 __ push(Immediate(Smi::FromInt(attr))); | 828 __ push(Immediate(Smi::FromInt(attr))); |
| 724 // Push initial value, if any. | 829 // Push initial value, if any. |
| 725 // Note: For variables we must not push an initial value (such as | 830 // Note: For variables we must not push an initial value (such as |
| 726 // 'undefined') because we may have a (legal) redeclaration and we | 831 // 'undefined') because we may have a (legal) redeclaration and we |
| 727 // must not destroy the current value. | 832 // must not destroy the current value. |
| 728 if (decl->mode() == Variable::CONST) { | 833 if (mode == Variable::CONST) { |
| 729 __ push(Immediate(Factory::the_hole_value())); | 834 __ push(Immediate(Factory::the_hole_value())); |
| 730 } else if (decl->fun() != NULL) { | 835 } else if (function != NULL) { |
| 731 VisitForValue(decl->fun(), kStack); | 836 VisitForValue(function, kStack); |
| 732 } else { | 837 } else { |
| 733 __ push(Immediate(Smi::FromInt(0))); // No initial value! | 838 __ push(Immediate(Smi::FromInt(0))); // No initial value! |
| 734 } | 839 } |
| 735 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 840 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 736 break; | 841 break; |
| 737 } | 842 } |
| 738 } | 843 } |
| 739 | 844 |
| 740 } else if (prop != NULL) { | 845 } else if (prop != NULL) { |
| 741 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 846 if (function != NULL || mode == Variable::CONST) { |
| 742 // We are declaring a function or constant that rewrites to a | 847 // We are declaring a function or constant that rewrites to a |
| 743 // property. Use (keyed) IC to set the initial value. | 848 // property. Use (keyed) IC to set the initial value. |
| 744 VisitForValue(prop->obj(), kStack); | 849 VisitForValue(prop->obj(), kStack); |
| 745 if (decl->fun() != NULL) { | 850 if (function != NULL) { |
| 746 VisitForValue(prop->key(), kStack); | 851 VisitForValue(prop->key(), kStack); |
| 747 VisitForValue(decl->fun(), kAccumulator); | 852 VisitForValue(function, kAccumulator); |
| 748 __ pop(ecx); | 853 __ pop(ecx); |
| 749 } else { | 854 } else { |
| 750 VisitForValue(prop->key(), kAccumulator); | 855 VisitForValue(prop->key(), kAccumulator); |
| 751 __ mov(ecx, result_register()); | 856 __ mov(ecx, result_register()); |
| 752 __ mov(result_register(), Factory::the_hole_value()); | 857 __ mov(result_register(), Factory::the_hole_value()); |
| 753 } | 858 } |
| 754 __ pop(edx); | 859 __ pop(edx); |
| 755 | 860 |
| 756 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 861 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 757 __ call(ic, RelocInfo::CODE_TARGET); | 862 __ call(ic, RelocInfo::CODE_TARGET); |
| 758 // Absence of a test eax instruction following the call | 863 // Absence of a test eax instruction following the call |
| 759 // indicates that none of the load was inlined. | 864 // indicates that none of the load was inlined. |
| 760 __ nop(); | 865 __ nop(); |
| 761 } | 866 } |
| 762 } | 867 } |
| 763 } | 868 } |
| 764 | 869 |
| 765 | 870 |
| 871 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 872 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 873 } |
| 874 |
| 875 |
| 766 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 876 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 767 // Call the runtime to declare the globals. | 877 // Call the runtime to declare the globals. |
| 768 __ push(esi); // The context is the first argument. | 878 __ push(esi); // The context is the first argument. |
| 769 __ push(Immediate(pairs)); | 879 __ push(Immediate(pairs)); |
| 770 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 880 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 771 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 881 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 772 // Return value is ignored. | 882 // Return value is ignored. |
| 773 } | 883 } |
| 774 | 884 |
| 775 | 885 |
| 776 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 886 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 777 Comment cmnt(masm_, "[ FunctionLiteral"); | 887 Comment cmnt(masm_, "[ SwitchStatement"); |
| 778 | 888 Breakable nested_statement(this, stmt); |
| 779 // Build the shared function info and instantiate the function based | 889 SetStatementPosition(stmt); |
| 780 // on it. | 890 // Keep the switch value on the stack until a case matches. |
| 781 Handle<SharedFunctionInfo> function_info = | 891 VisitForValue(stmt->tag(), kStack); |
| 782 Compiler::BuildFunctionInfo(expr, script(), this); | 892 |
| 783 if (HasStackOverflow()) return; | 893 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 784 | 894 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 785 // Create a new closure. | 895 |
| 786 __ push(esi); | 896 Label next_test; // Recycled for each test. |
| 787 __ push(Immediate(function_info)); | 897 // Compile all the tests with branches to their bodies. |
| 788 __ CallRuntime(Runtime::kNewClosure, 2); | 898 for (int i = 0; i < clauses->length(); i++) { |
| 899 CaseClause* clause = clauses->at(i); |
| 900 // The default is not a test, but remember it as final fall through. |
| 901 if (clause->is_default()) { |
| 902 default_clause = clause; |
| 903 continue; |
| 904 } |
| 905 |
| 906 Comment cmnt(masm_, "[ Case comparison"); |
| 907 __ bind(&next_test); |
| 908 next_test.Unuse(); |
| 909 |
| 910 // Compile the label expression. |
| 911 VisitForValue(clause->label(), kAccumulator); |
| 912 |
| 913 // Perform the comparison as if via '==='. The comparison stub expects |
| 914 // the smi vs. smi case to be handled before it is called. |
| 915 Label slow_case; |
| 916 __ mov(edx, Operand(esp, 0)); // Switch value. |
| 917 __ mov(ecx, edx); |
| 918 __ or_(ecx, Operand(eax)); |
| 919 __ test(ecx, Immediate(kSmiTagMask)); |
| 920 __ j(not_zero, &slow_case, not_taken); |
| 921 __ cmp(edx, Operand(eax)); |
| 922 __ j(not_equal, &next_test); |
| 923 __ Drop(1); // Switch value is no longer needed. |
| 924 __ jmp(clause->body_target()->entry_label()); |
| 925 |
| 926 __ bind(&slow_case); |
| 927 CompareStub stub(equal, true); |
| 928 __ CallStub(&stub); |
| 929 __ test(eax, Operand(eax)); |
| 930 __ j(not_equal, &next_test); |
| 931 __ Drop(1); // Switch value is no longer needed. |
| 932 __ jmp(clause->body_target()->entry_label()); |
| 933 } |
| 934 |
| 935 // Discard the test value and jump to the default if present, otherwise to |
| 936 // the end of the statement. |
| 937 __ bind(&next_test); |
| 938 __ Drop(1); // Switch value is no longer needed. |
| 939 if (default_clause == NULL) { |
| 940 __ jmp(nested_statement.break_target()); |
| 941 } else { |
| 942 __ jmp(default_clause->body_target()->entry_label()); |
| 943 } |
| 944 |
| 945 // Compile all the case bodies. |
| 946 for (int i = 0; i < clauses->length(); i++) { |
| 947 Comment cmnt(masm_, "[ Case body"); |
| 948 CaseClause* clause = clauses->at(i); |
| 949 __ bind(clause->body_target()->entry_label()); |
| 950 VisitStatements(clause->statements()); |
| 951 } |
| 952 |
| 953 __ bind(nested_statement.break_target()); |
| 954 } |
| 955 |
| 956 |
| 957 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 958 Comment cmnt(masm_, "[ ForInStatement"); |
| 959 SetStatementPosition(stmt); |
| 960 |
| 961 Label loop, exit; |
| 962 ForIn loop_statement(this, stmt); |
| 963 increment_loop_depth(); |
| 964 |
| 965 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 966 // ignore null and undefined in contrast to the specification; see |
| 967 // ECMA-262 section 12.6.4. |
| 968 VisitForValue(stmt->enumerable(), kAccumulator); |
| 969 __ cmp(eax, Factory::undefined_value()); |
| 970 __ j(equal, &exit); |
| 971 __ cmp(eax, Factory::null_value()); |
| 972 __ j(equal, &exit); |
| 973 |
| 974 // Convert the object to a JS object. |
| 975 Label convert, done_convert; |
| 976 __ test(eax, Immediate(kSmiTagMask)); |
| 977 __ j(zero, &convert); |
| 978 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 979 __ j(above_equal, &done_convert); |
| 980 __ bind(&convert); |
| 981 __ push(eax); |
| 982 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 983 __ bind(&done_convert); |
| 984 __ push(eax); |
| 985 |
| 986 // TODO(kasperl): Check cache validity in generated code. This is a |
| 987 // fast case for the JSObject::IsSimpleEnum cache validity |
| 988 // checks. If we cannot guarantee cache validity, call the runtime |
| 989 // system to check cache validity or get the property names in a |
| 990 // fixed array. |
| 991 |
| 992 // Get the set of properties to enumerate. |
| 993 __ push(eax); // Duplicate the enumerable object on the stack. |
| 994 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 995 |
| 996 // If we got a map from the runtime call, we can do a fast |
| 997 // modification check. Otherwise, we got a fixed array, and we have |
| 998 // to do a slow check. |
| 999 Label fixed_array; |
| 1000 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map()); |
| 1001 __ j(not_equal, &fixed_array); |
| 1002 |
| 1003 // We got a map in register eax. Get the enumeration cache from it. |
| 1004 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset)); |
| 1005 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 1006 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1007 |
| 1008 // Setup the four remaining stack slots. |
| 1009 __ push(eax); // Map. |
| 1010 __ push(edx); // Enumeration cache. |
| 1011 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); |
| 1012 __ SmiTag(eax); |
| 1013 __ push(eax); // Enumeration cache length (as smi). |
| 1014 __ push(Immediate(Smi::FromInt(0))); // Initial index. |
| 1015 __ jmp(&loop); |
| 1016 |
| 1017 // We got a fixed array in register eax. Iterate through that. |
| 1018 __ bind(&fixed_array); |
| 1019 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check. |
| 1020 __ push(eax); |
| 1021 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 1022 __ SmiTag(eax); |
| 1023 __ push(eax); // Fixed array length (as smi). |
| 1024 __ push(Immediate(Smi::FromInt(0))); // Initial index. |
| 1025 |
| 1026 // Generate code for doing the condition check. |
| 1027 __ bind(&loop); |
| 1028 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. |
| 1029 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. |
| 1030 __ j(above_equal, loop_statement.break_target()); |
| 1031 |
| 1032 // Get the current entry of the array into register ebx. |
| 1033 __ mov(ebx, Operand(esp, 2 * kPointerSize)); |
| 1034 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize)); |
| 1035 |
| 1036 // Get the expected map from the stack or a zero map in the |
| 1037 // permanent slow case into register edx. |
| 1038 __ mov(edx, Operand(esp, 3 * kPointerSize)); |
| 1039 |
| 1040 // Check if the expected map still matches that of the enumerable. |
| 1041 // If not, we have to filter the key. |
| 1042 Label update_each; |
| 1043 __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
| 1044 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 1045 __ j(equal, &update_each); |
| 1046 |
| 1047 // Convert the entry to a string or null if it isn't a property |
| 1048 // anymore. If the property has been removed while iterating, we |
| 1049 // just skip it. |
| 1050 __ push(ecx); // Enumerable. |
| 1051 __ push(ebx); // Current entry. |
| 1052 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 1053 __ cmp(eax, Factory::null_value()); |
| 1054 __ j(equal, loop_statement.continue_target()); |
| 1055 __ mov(ebx, Operand(eax)); |
| 1056 |
| 1057 // Update the 'each' property or variable from the possibly filtered |
| 1058 // entry in register ebx. |
| 1059 __ bind(&update_each); |
| 1060 __ mov(result_register(), ebx); |
| 1061 // Perform the assignment as if via '='. |
| 1062 EmitAssignment(stmt->each()); |
| 1063 |
| 1064 // Generate code for the body of the loop. |
| 1065 Label stack_limit_hit, stack_check_done; |
| 1066 Visit(stmt->body()); |
| 1067 |
| 1068 __ StackLimitCheck(&stack_limit_hit); |
| 1069 __ bind(&stack_check_done); |
| 1070 |
| 1071 // Generate code for the going to the next element by incrementing |
| 1072 // the index (smi) stored on top of the stack. |
| 1073 __ bind(loop_statement.continue_target()); |
| 1074 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1))); |
| 1075 __ jmp(&loop); |
| 1076 |
| 1077 // Slow case for the stack limit check. |
| 1078 StackCheckStub stack_check_stub; |
| 1079 __ bind(&stack_limit_hit); |
| 1080 __ CallStub(&stack_check_stub); |
| 1081 __ jmp(&stack_check_done); |
| 1082 |
| 1083 // Remove the pointers stored on the stack. |
| 1084 __ bind(loop_statement.break_target()); |
| 1085 __ add(Operand(esp), Immediate(5 * kPointerSize)); |
| 1086 |
| 1087 // Exit and decrement the loop depth. |
| 1088 __ bind(&exit); |
| 1089 decrement_loop_depth(); |
| 1090 } |
| 1091 |
| 1092 |
| 1093 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { |
| 1094 // Use the fast case closure allocation code that allocates in new |
| 1095 // space for nested functions that don't need literals cloning. |
| 1096 if (scope()->is_function_scope() && info->num_literals() == 0) { |
| 1097 FastNewClosureStub stub; |
| 1098 __ push(Immediate(info)); |
| 1099 __ CallStub(&stub); |
| 1100 } else { |
| 1101 __ push(esi); |
| 1102 __ push(Immediate(info)); |
| 1103 __ CallRuntime(Runtime::kNewClosure, 2); |
| 1104 } |
| 789 Apply(context_, eax); | 1105 Apply(context_, eax); |
| 790 } | 1106 } |
| 791 | 1107 |
| 792 | 1108 |
| 793 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 1109 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 794 Comment cmnt(masm_, "[ VariableProxy"); | 1110 Comment cmnt(masm_, "[ VariableProxy"); |
| 795 EmitVariableLoad(expr->var(), context_); | 1111 EmitVariableLoad(expr->var(), context_); |
| 796 } | 1112 } |
| 797 | 1113 |
| 798 | 1114 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 823 Comment cmnt(masm_, "Lookup slot"); | 1139 Comment cmnt(masm_, "Lookup slot"); |
| 824 __ push(esi); // Context. | 1140 __ push(esi); // Context. |
| 825 __ push(Immediate(var->name())); | 1141 __ push(Immediate(var->name())); |
| 826 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1142 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 827 Apply(context, eax); | 1143 Apply(context, eax); |
| 828 | 1144 |
| 829 } else if (slot != NULL) { | 1145 } else if (slot != NULL) { |
| 830 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1146 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 831 ? "Context slot" | 1147 ? "Context slot" |
| 832 : "Stack slot"); | 1148 : "Stack slot"); |
| 833 Apply(context, slot); | 1149 if (var->mode() == Variable::CONST) { |
| 1150 // Constants may be the hole value if they have not been initialized. |
| 1151 // Unhole them. |
| 1152 Label done; |
| 1153 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1154 __ mov(eax, slot_operand); |
| 1155 __ cmp(eax, Factory::the_hole_value()); |
| 1156 __ j(not_equal, &done); |
| 1157 __ mov(eax, Factory::undefined_value()); |
| 1158 __ bind(&done); |
| 1159 Apply(context, eax); |
| 1160 } else { |
| 1161 Apply(context, slot); |
| 1162 } |
| 834 | 1163 |
| 835 } else { | 1164 } else { |
| 836 Comment cmnt(masm_, "Rewritten parameter"); | 1165 Comment cmnt(masm_, "Rewritten parameter"); |
| 837 ASSERT_NOT_NULL(property); | 1166 ASSERT_NOT_NULL(property); |
| 838 // Rewritten parameter accesses are of the form "slot[literal]". | 1167 // Rewritten parameter accesses are of the form "slot[literal]". |
| 839 | 1168 |
| 840 // Assert that the object is in a slot. | 1169 // Assert that the object is in a slot. |
| 841 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | 1170 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); |
| 842 ASSERT_NOT_NULL(object_var); | 1171 ASSERT_NOT_NULL(object_var); |
| 843 Slot* object_slot = object_var->slot(); | 1172 Slot* object_slot = object_var->slot(); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 959 if (result_saved) { | 1288 if (result_saved) { |
| 960 ApplyTOS(context_); | 1289 ApplyTOS(context_); |
| 961 } else { | 1290 } else { |
| 962 Apply(context_, eax); | 1291 Apply(context_, eax); |
| 963 } | 1292 } |
| 964 } | 1293 } |
| 965 | 1294 |
| 966 | 1295 |
| 967 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1296 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 968 Comment cmnt(masm_, "[ ArrayLiteral"); | 1297 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 1298 |
| 1299 ZoneList<Expression*>* subexprs = expr->values(); |
| 1300 int length = subexprs->length(); |
| 1301 |
| 969 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 1302 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 970 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); | 1303 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
| 971 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 1304 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 972 __ push(Immediate(expr->constant_elements())); | 1305 __ push(Immediate(expr->constant_elements())); |
| 973 if (expr->depth() > 1) { | 1306 if (expr->depth() > 1) { |
| 974 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 1307 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 1308 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { |
| 1309 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 975 } else { | 1310 } else { |
| 976 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 1311 FastCloneShallowArrayStub stub(length); |
| 1312 __ CallStub(&stub); |
| 977 } | 1313 } |
| 978 | 1314 |
| 979 bool result_saved = false; // Is the result saved to the stack? | 1315 bool result_saved = false; // Is the result saved to the stack? |
| 980 | 1316 |
| 981 // Emit code to evaluate all the non-constant subexpressions and to store | 1317 // Emit code to evaluate all the non-constant subexpressions and to store |
| 982 // them into the newly cloned array. | 1318 // them into the newly cloned array. |
| 983 ZoneList<Expression*>* subexprs = expr->values(); | 1319 for (int i = 0; i < length; i++) { |
| 984 for (int i = 0, len = subexprs->length(); i < len; i++) { | |
| 985 Expression* subexpr = subexprs->at(i); | 1320 Expression* subexpr = subexprs->at(i); |
| 986 // If the subexpression is a literal or a simple materialized literal it | 1321 // If the subexpression is a literal or a simple materialized literal it |
| 987 // is already set in the cloned array. | 1322 // is already set in the cloned array. |
| 988 if (subexpr->AsLiteral() != NULL || | 1323 if (subexpr->AsLiteral() != NULL || |
| 989 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 1324 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 990 continue; | 1325 continue; |
| 991 } | 1326 } |
| 992 | 1327 |
| 993 if (!result_saved) { | 1328 if (!result_saved) { |
| 994 __ push(eax); | 1329 __ push(eax); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1009 if (result_saved) { | 1344 if (result_saved) { |
| 1010 ApplyTOS(context_); | 1345 ApplyTOS(context_); |
| 1011 } else { | 1346 } else { |
| 1012 Apply(context_, eax); | 1347 Apply(context_, eax); |
| 1013 } | 1348 } |
| 1014 } | 1349 } |
| 1015 | 1350 |
| 1016 | 1351 |
| 1017 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1352 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1018 Comment cmnt(masm_, "[ Assignment"); | 1353 Comment cmnt(masm_, "[ Assignment"); |
| 1019 ASSERT(expr->op() != Token::INIT_CONST); | 1354 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1355 // on the left-hand side. |
| 1356 if (!expr->target()->IsValidLeftHandSide()) { |
| 1357 VisitForEffect(expr->target()); |
| 1358 return; |
| 1359 } |
| 1360 |
| 1020 // Left-hand side can only be a property, a global or a (parameter or local) | 1361 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1021 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1362 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1022 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1363 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1023 LhsKind assign_type = VARIABLE; | 1364 LhsKind assign_type = VARIABLE; |
| 1024 Property* prop = expr->target()->AsProperty(); | 1365 Property* prop = expr->target()->AsProperty(); |
| 1025 if (prop != NULL) { | 1366 if (prop != NULL) { |
| 1026 assign_type = | 1367 assign_type = |
| 1027 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 1368 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 1028 } | 1369 } |
| 1029 | 1370 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 location_ = saved_location; | 1429 location_ = saved_location; |
| 1089 } | 1430 } |
| 1090 | 1431 |
| 1091 // Record source position before possible IC call. | 1432 // Record source position before possible IC call. |
| 1092 SetSourcePosition(expr->position()); | 1433 SetSourcePosition(expr->position()); |
| 1093 | 1434 |
| 1094 // Store the value. | 1435 // Store the value. |
| 1095 switch (assign_type) { | 1436 switch (assign_type) { |
| 1096 case VARIABLE: | 1437 case VARIABLE: |
| 1097 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1438 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
| 1439 expr->op(), |
| 1098 context_); | 1440 context_); |
| 1099 break; | 1441 break; |
| 1100 case NAMED_PROPERTY: | 1442 case NAMED_PROPERTY: |
| 1101 EmitNamedPropertyAssignment(expr); | 1443 EmitNamedPropertyAssignment(expr); |
| 1102 break; | 1444 break; |
| 1103 case KEYED_PROPERTY: | 1445 case KEYED_PROPERTY: |
| 1104 EmitKeyedPropertyAssignment(expr); | 1446 EmitKeyedPropertyAssignment(expr); |
| 1105 break; | 1447 break; |
| 1106 } | 1448 } |
| 1107 } | 1449 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1130 __ push(result_register()); | 1472 __ push(result_register()); |
| 1131 GenericBinaryOpStub stub(op, | 1473 GenericBinaryOpStub stub(op, |
| 1132 NO_OVERWRITE, | 1474 NO_OVERWRITE, |
| 1133 NO_GENERIC_BINARY_FLAGS, | 1475 NO_GENERIC_BINARY_FLAGS, |
| 1134 TypeInfo::Unknown()); | 1476 TypeInfo::Unknown()); |
| 1135 __ CallStub(&stub); | 1477 __ CallStub(&stub); |
| 1136 Apply(context, eax); | 1478 Apply(context, eax); |
| 1137 } | 1479 } |
| 1138 | 1480 |
| 1139 | 1481 |
| 1482 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 1483 // Invalid left-hand sides are rewritten to have a 'throw |
| 1484 // ReferenceError' on the left-hand side. |
| 1485 if (!expr->IsValidLeftHandSide()) { |
| 1486 VisitForEffect(expr); |
| 1487 return; |
| 1488 } |
| 1489 |
| 1490 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1491 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1492 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1493 LhsKind assign_type = VARIABLE; |
| 1494 Property* prop = expr->AsProperty(); |
| 1495 if (prop != NULL) { |
| 1496 assign_type = (prop->key()->IsPropertyName()) |
| 1497 ? NAMED_PROPERTY |
| 1498 : KEYED_PROPERTY; |
| 1499 } |
| 1500 |
| 1501 switch (assign_type) { |
| 1502 case VARIABLE: { |
| 1503 Variable* var = expr->AsVariableProxy()->var(); |
| 1504 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect); |
| 1505 break; |
| 1506 } |
| 1507 case NAMED_PROPERTY: { |
| 1508 __ push(eax); // Preserve value. |
| 1509 VisitForValue(prop->obj(), kAccumulator); |
| 1510 __ mov(edx, eax); |
| 1511 __ pop(eax); // Restore value. |
| 1512 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1513 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1514 __ call(ic, RelocInfo::CODE_TARGET); |
| 1515 __ nop(); // Signal no inlined code. |
| 1516 break; |
| 1517 } |
| 1518 case KEYED_PROPERTY: { |
| 1519 __ push(eax); // Preserve value. |
| 1520 VisitForValue(prop->obj(), kStack); |
| 1521 VisitForValue(prop->key(), kAccumulator); |
| 1522 __ mov(ecx, eax); |
| 1523 __ pop(edx); |
| 1524 __ pop(eax); // Restore value. |
| 1525 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 1526 __ call(ic, RelocInfo::CODE_TARGET); |
| 1527 __ nop(); // Signal no inlined code. |
| 1528 break; |
| 1529 } |
| 1530 } |
| 1531 } |
| 1532 |
| 1533 |
| 1140 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1534 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1535 Token::Value op, |
| 1141 Expression::Context context) { | 1536 Expression::Context context) { |
| 1142 // Three main cases: global variables, lookup slots, and all other | 1537 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1143 // types of slots. Left-hand-side parameters that rewrite to | 1538 // here. |
| 1144 // explicit property accesses do not reach here. | |
| 1145 ASSERT(var != NULL); | 1539 ASSERT(var != NULL); |
| 1146 ASSERT(var->is_global() || var->slot() != NULL); | 1540 ASSERT(var->is_global() || var->slot() != NULL); |
| 1147 | 1541 |
| 1148 Slot* slot = var->slot(); | |
| 1149 if (var->is_global()) { | 1542 if (var->is_global()) { |
| 1150 ASSERT(!var->is_this()); | 1543 ASSERT(!var->is_this()); |
| 1151 // Assignment to a global variable. Use inline caching for the | 1544 // Assignment to a global variable. Use inline caching for the |
| 1152 // assignment. Right-hand-side value is passed in eax, variable name in | 1545 // assignment. Right-hand-side value is passed in eax, variable name in |
| 1153 // ecx, and the global object on the stack. | 1546 // ecx, and the global object on the stack. |
| 1154 __ mov(ecx, var->name()); | 1547 __ mov(ecx, var->name()); |
| 1155 __ mov(edx, CodeGenerator::GlobalObject()); | 1548 __ mov(edx, CodeGenerator::GlobalObject()); |
| 1156 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1549 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1157 __ call(ic, RelocInfo::CODE_TARGET); | 1550 __ call(ic, RelocInfo::CODE_TARGET); |
| 1158 __ nop(); | 1551 __ nop(); |
| 1159 Apply(context, eax); | |
| 1160 | 1552 |
| 1161 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1553 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { |
| 1162 __ push(result_register()); // Value. | 1554 // Perform the assignment for non-const variables and for initialization |
| 1163 __ push(esi); // Context. | 1555 // of const variables. Const assignments are simply skipped. |
| 1164 __ push(Immediate(var->name())); | 1556 Label done; |
| 1165 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1557 Slot* slot = var->slot(); |
| 1166 Apply(context, eax); | |
| 1167 | |
| 1168 } else if (slot != NULL) { | |
| 1169 switch (slot->type()) { | 1558 switch (slot->type()) { |
| 1559 case Slot::PARAMETER: |
| 1170 case Slot::LOCAL: | 1560 case Slot::LOCAL: |
| 1171 case Slot::PARAMETER: | 1561 if (op == Token::INIT_CONST) { |
| 1172 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); | 1562 // Detect const reinitialization by checking for the hole value. |
| 1563 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 1564 __ cmp(edx, Factory::the_hole_value()); |
| 1565 __ j(not_equal, &done); |
| 1566 } |
| 1567 // Perform the assignment. |
| 1568 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 1173 break; | 1569 break; |
| 1174 | 1570 |
| 1175 case Slot::CONTEXT: { | 1571 case Slot::CONTEXT: { |
| 1176 MemOperand target = EmitSlotSearch(slot, ecx); | 1572 MemOperand target = EmitSlotSearch(slot, ecx); |
| 1177 __ mov(target, result_register()); | 1573 if (op == Token::INIT_CONST) { |
| 1178 | 1574 // Detect const reinitialization by checking for the hole value. |
| 1179 // RecordWrite may destroy all its register arguments. | 1575 __ mov(edx, target); |
| 1180 __ mov(edx, result_register()); | 1576 __ cmp(edx, Factory::the_hole_value()); |
| 1577 __ j(not_equal, &done); |
| 1578 } |
| 1579 // Perform the assignment and issue the write barrier. |
| 1580 __ mov(target, eax); |
| 1581 // The value of the assignment is in eax. RecordWrite clobbers its |
| 1582 // register arguments. |
| 1583 __ mov(edx, eax); |
| 1181 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1584 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 1182 __ RecordWrite(ecx, offset, edx, ebx); | 1585 __ RecordWrite(ecx, offset, edx, ebx); |
| 1183 break; | 1586 break; |
| 1184 } | 1587 } |
| 1185 | 1588 |
| 1186 case Slot::LOOKUP: | 1589 case Slot::LOOKUP: |
| 1187 UNREACHABLE(); | 1590 // Call the runtime for the assignment. The runtime will ignore |
| 1591 // const reinitialization. |
| 1592 __ push(eax); // Value. |
| 1593 __ push(esi); // Context. |
| 1594 __ push(Immediate(var->name())); |
| 1595 if (op == Token::INIT_CONST) { |
| 1596 // The runtime will ignore const redeclaration. |
| 1597 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1598 } else { |
| 1599 __ CallRuntime(Runtime::kStoreContextSlot, 3); |
| 1600 } |
| 1188 break; | 1601 break; |
| 1189 } | 1602 } |
| 1190 Apply(context, result_register()); | 1603 __ bind(&done); |
| 1604 } |
| 1191 | 1605 |
| 1192 } else { | 1606 Apply(context, eax); |
| 1193 // Variables rewritten as properties are not treated as variables in | |
| 1194 // assignments. | |
| 1195 UNREACHABLE(); | |
| 1196 } | |
| 1197 } | 1607 } |
| 1198 | 1608 |
| 1199 | 1609 |
| 1200 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1610 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 1201 // Assignment to a property, using a named store IC. | 1611 // Assignment to a property, using a named store IC. |
| 1202 Property* prop = expr->target()->AsProperty(); | 1612 Property* prop = expr->target()->AsProperty(); |
| 1203 ASSERT(prop != NULL); | 1613 ASSERT(prop != NULL); |
| 1204 ASSERT(prop->key()->AsLiteral() != NULL); | 1614 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1205 | 1615 |
| 1206 // If the assignment starts a block of assignments to the same object, | 1616 // If the assignment starts a block of assignments to the same object, |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 | 1730 |
| 1321 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 1731 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 1322 // Code common for calls using the call stub. | 1732 // Code common for calls using the call stub. |
| 1323 ZoneList<Expression*>* args = expr->arguments(); | 1733 ZoneList<Expression*>* args = expr->arguments(); |
| 1324 int arg_count = args->length(); | 1734 int arg_count = args->length(); |
| 1325 for (int i = 0; i < arg_count; i++) { | 1735 for (int i = 0; i < arg_count; i++) { |
| 1326 VisitForValue(args->at(i), kStack); | 1736 VisitForValue(args->at(i), kStack); |
| 1327 } | 1737 } |
| 1328 // Record source position for debugger. | 1738 // Record source position for debugger. |
| 1329 SetSourcePosition(expr->position()); | 1739 SetSourcePosition(expr->position()); |
| 1330 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); | 1740 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1741 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1331 __ CallStub(&stub); | 1742 __ CallStub(&stub); |
| 1332 // Restore context register. | 1743 // Restore context register. |
| 1333 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1744 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 1334 DropAndApply(1, context_, eax); | 1745 DropAndApply(1, context_, eax); |
| 1335 } | 1746 } |
| 1336 | 1747 |
| 1337 | 1748 |
| 1338 void FullCodeGenerator::VisitCall(Call* expr) { | 1749 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1339 Comment cmnt(masm_, "[ Call"); | 1750 Comment cmnt(masm_, "[ Call"); |
| 1340 Expression* fun = expr->expression(); | 1751 Expression* fun = expr->expression(); |
| 1341 Variable* var = fun->AsVariableProxy()->AsVariable(); | 1752 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 1342 | 1753 |
| 1343 if (var != NULL && var->is_possibly_eval()) { | 1754 if (var != NULL && var->is_possibly_eval()) { |
| 1344 // Call to the identifier 'eval'. | 1755 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 1345 UNREACHABLE(); | 1756 // resolve the function we need to call and the receiver of the |
| 1757 // call. Then we call the resolved function using the given |
| 1758 // arguments. |
| 1759 VisitForValue(fun, kStack); |
| 1760 __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot. |
| 1761 |
| 1762 // Push the arguments. |
| 1763 ZoneList<Expression*>* args = expr->arguments(); |
| 1764 int arg_count = args->length(); |
| 1765 for (int i = 0; i < arg_count; i++) { |
| 1766 VisitForValue(args->at(i), kStack); |
| 1767 } |
| 1768 |
| 1769 // Push copy of the function - found below the arguments. |
| 1770 __ push(Operand(esp, (arg_count + 1) * kPointerSize)); |
| 1771 |
| 1772 // Push copy of the first argument or undefined if it doesn't exist. |
| 1773 if (arg_count > 0) { |
| 1774 __ push(Operand(esp, arg_count * kPointerSize)); |
| 1775 } else { |
| 1776 __ push(Immediate(Factory::undefined_value())); |
| 1777 } |
| 1778 |
| 1779 // Push the receiver of the enclosing function and do runtime call. |
| 1780 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 1781 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); |
| 1782 |
| 1783 // The runtime call returns a pair of values in eax (function) and |
| 1784 // edx (receiver). Touch up the stack with the right values. |
| 1785 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx); |
| 1786 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax); |
| 1787 |
| 1788 // Record source position for debugger. |
| 1789 SetSourcePosition(expr->position()); |
| 1790 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 1791 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1792 __ CallStub(&stub); |
| 1793 // Restore context register. |
| 1794 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 1795 DropAndApply(1, context_, eax); |
| 1346 } else if (var != NULL && !var->is_this() && var->is_global()) { | 1796 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 1347 // Push global object as receiver for the call IC. | 1797 // Push global object as receiver for the call IC. |
| 1348 __ push(CodeGenerator::GlobalObject()); | 1798 __ push(CodeGenerator::GlobalObject()); |
| 1349 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); | 1799 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); |
| 1350 } else if (var != NULL && var->slot() != NULL && | 1800 } else if (var != NULL && var->slot() != NULL && |
| 1351 var->slot()->type() == Slot::LOOKUP) { | 1801 var->slot()->type() == Slot::LOOKUP) { |
| 1352 // Call to a lookup slot. | 1802 // Call to a lookup slot (dynamically introduced variable). Call the |
| 1353 UNREACHABLE(); | 1803 // runtime to find the function to call (returned in eax) and the object |
| 1804 // holding it (returned in edx). |
| 1805 __ push(context_register()); |
| 1806 __ push(Immediate(var->name())); |
| 1807 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1808 __ push(eax); // Function. |
| 1809 __ push(edx); // Receiver. |
| 1810 EmitCallWithStub(expr); |
| 1354 } else if (fun->AsProperty() != NULL) { | 1811 } else if (fun->AsProperty() != NULL) { |
| 1355 // Call to an object property. | 1812 // Call to an object property. |
| 1356 Property* prop = fun->AsProperty(); | 1813 Property* prop = fun->AsProperty(); |
| 1357 Literal* key = prop->key()->AsLiteral(); | 1814 Literal* key = prop->key()->AsLiteral(); |
| 1358 if (key != NULL && key->handle()->IsSymbol()) { | 1815 if (key != NULL && key->handle()->IsSymbol()) { |
| 1359 // Call to a named property, use call IC. | 1816 // Call to a named property, use call IC. |
| 1360 VisitForValue(prop->obj(), kStack); | 1817 VisitForValue(prop->obj(), kStack); |
| 1361 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 1818 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 1362 } else { | 1819 } else { |
| 1363 // Call to a keyed property, use keyed load IC followed by function | 1820 // Call to a keyed property, use keyed load IC followed by function |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1440 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | 1897 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); |
| 1441 | 1898 |
| 1442 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 1899 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); |
| 1443 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 1900 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 1444 | 1901 |
| 1445 // Replace function on TOS with result in eax, or pop it. | 1902 // Replace function on TOS with result in eax, or pop it. |
| 1446 DropAndApply(1, context_, eax); | 1903 DropAndApply(1, context_, eax); |
| 1447 } | 1904 } |
| 1448 | 1905 |
| 1449 | 1906 |
| 1907 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) { |
| 1908 Handle<String> name = expr->name(); |
| 1909 if (strcmp("_IsSmi", *name->ToCString()) == 0) { |
| 1910 EmitIsSmi(expr->arguments()); |
| 1911 } else if (strcmp("_IsNonNegativeSmi", *name->ToCString()) == 0) { |
| 1912 EmitIsNonNegativeSmi(expr->arguments()); |
| 1913 } else if (strcmp("_IsObject", *name->ToCString()) == 0) { |
| 1914 EmitIsObject(expr->arguments()); |
| 1915 } else if (strcmp("_IsUndetectableObject", *name->ToCString()) == 0) { |
| 1916 EmitIsUndetectableObject(expr->arguments()); |
| 1917 } else if (strcmp("_IsFunction", *name->ToCString()) == 0) { |
| 1918 EmitIsFunction(expr->arguments()); |
| 1919 } else if (strcmp("_IsArray", *name->ToCString()) == 0) { |
| 1920 EmitIsArray(expr->arguments()); |
| 1921 } else if (strcmp("_IsRegExp", *name->ToCString()) == 0) { |
| 1922 EmitIsRegExp(expr->arguments()); |
| 1923 } else if (strcmp("_IsConstructCall", *name->ToCString()) == 0) { |
| 1924 EmitIsConstructCall(expr->arguments()); |
| 1925 } else if (strcmp("_ObjectEquals", *name->ToCString()) == 0) { |
| 1926 EmitObjectEquals(expr->arguments()); |
| 1927 } else if (strcmp("_Arguments", *name->ToCString()) == 0) { |
| 1928 EmitArguments(expr->arguments()); |
| 1929 } else if (strcmp("_ArgumentsLength", *name->ToCString()) == 0) { |
| 1930 EmitArgumentsLength(expr->arguments()); |
| 1931 } else if (strcmp("_ClassOf", *name->ToCString()) == 0) { |
| 1932 EmitClassOf(expr->arguments()); |
| 1933 } else if (strcmp("_Log", *name->ToCString()) == 0) { |
| 1934 EmitLog(expr->arguments()); |
| 1935 } else if (strcmp("_RandomHeapNumber", *name->ToCString()) == 0) { |
| 1936 EmitRandomHeapNumber(expr->arguments()); |
| 1937 } else if (strcmp("_SubString", *name->ToCString()) == 0) { |
| 1938 EmitSubString(expr->arguments()); |
| 1939 } else if (strcmp("_RegExpExec", *name->ToCString()) == 0) { |
| 1940 EmitRegExpExec(expr->arguments()); |
| 1941 } else if (strcmp("_ValueOf", *name->ToCString()) == 0) { |
| 1942 EmitValueOf(expr->arguments()); |
| 1943 } else if (strcmp("_SetValueOf", *name->ToCString()) == 0) { |
| 1944 EmitSetValueOf(expr->arguments()); |
| 1945 } else if (strcmp("_NumberToString", *name->ToCString()) == 0) { |
| 1946 EmitNumberToString(expr->arguments()); |
| 1947 } else if (strcmp("_CharFromCode", *name->ToCString()) == 0) { |
| 1948 EmitCharFromCode(expr->arguments()); |
| 1949 } else if (strcmp("_FastCharCodeAt", *name->ToCString()) == 0) { |
| 1950 EmitFastCharCodeAt(expr->arguments()); |
| 1951 } else if (strcmp("_StringAdd", *name->ToCString()) == 0) { |
| 1952 EmitStringAdd(expr->arguments()); |
| 1953 } else if (strcmp("_StringCompare", *name->ToCString()) == 0) { |
| 1954 EmitStringCompare(expr->arguments()); |
| 1955 } else if (strcmp("_MathPow", *name->ToCString()) == 0) { |
| 1956 EmitMathPow(expr->arguments()); |
| 1957 } else if (strcmp("_MathSin", *name->ToCString()) == 0) { |
| 1958 EmitMathSin(expr->arguments()); |
| 1959 } else if (strcmp("_MathCos", *name->ToCString()) == 0) { |
| 1960 EmitMathCos(expr->arguments()); |
| 1961 } else if (strcmp("_MathSqrt", *name->ToCString()) == 0) { |
| 1962 EmitMathSqrt(expr->arguments()); |
| 1963 } else if (strcmp("_CallFunction", *name->ToCString()) == 0) { |
| 1964 EmitCallFunction(expr->arguments()); |
| 1965 } else if (strcmp("_RegExpConstructResult", *name->ToCString()) == 0) { |
| 1966 EmitRegExpConstructResult(expr->arguments()); |
| 1967 } else if (strcmp("_SwapElements", *name->ToCString()) == 0) { |
| 1968 EmitSwapElements(expr->arguments()); |
| 1969 } else if (strcmp("_GetFromCache", *name->ToCString()) == 0) { |
| 1970 EmitGetFromCache(expr->arguments()); |
| 1971 } else { |
| 1972 UNREACHABLE(); |
| 1973 } |
| 1974 } |
| 1975 |
| 1976 |
| 1977 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) { |
| 1978 ASSERT(args->length() == 1); |
| 1979 |
| 1980 VisitForValue(args->at(0), kAccumulator); |
| 1981 |
| 1982 Label materialize_true, materialize_false; |
| 1983 Label* if_true = NULL; |
| 1984 Label* if_false = NULL; |
| 1985 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 1986 |
| 1987 __ test(eax, Immediate(kSmiTagMask)); |
| 1988 __ j(zero, if_true); |
| 1989 __ jmp(if_false); |
| 1990 |
| 1991 Apply(context_, if_true, if_false); |
| 1992 } |
| 1993 |
| 1994 |
| 1995 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 1996 ASSERT(args->length() == 1); |
| 1997 |
| 1998 VisitForValue(args->at(0), kAccumulator); |
| 1999 |
| 2000 Label materialize_true, materialize_false; |
| 2001 Label* if_true = NULL; |
| 2002 Label* if_false = NULL; |
| 2003 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2004 |
| 2005 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 2006 __ j(zero, if_true); |
| 2007 __ jmp(if_false); |
| 2008 |
| 2009 Apply(context_, if_true, if_false); |
| 2010 } |
| 2011 |
| 2012 |
| 2013 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) { |
| 2014 ASSERT(args->length() == 1); |
| 2015 |
| 2016 VisitForValue(args->at(0), kAccumulator); |
| 2017 |
| 2018 Label materialize_true, materialize_false; |
| 2019 Label* if_true = NULL; |
| 2020 Label* if_false = NULL; |
| 2021 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2022 |
| 2023 __ test(eax, Immediate(kSmiTagMask)); |
| 2024 __ j(zero, if_false); |
| 2025 __ cmp(eax, Factory::null_value()); |
| 2026 __ j(equal, if_true); |
| 2027 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2028 // Undetectable objects behave like undefined when tested with typeof. |
| 2029 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2030 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 2031 __ j(not_zero, if_false); |
| 2032 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 2033 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 2034 __ j(less, if_false); |
| 2035 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 2036 __ j(less_equal, if_true); |
| 2037 __ jmp(if_false); |
| 2038 |
| 2039 Apply(context_, if_true, if_false); |
| 2040 } |
| 2041 |
| 2042 |
| 2043 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2044 ASSERT(args->length() == 1); |
| 2045 |
| 2046 VisitForValue(args->at(0), kAccumulator); |
| 2047 |
| 2048 Label materialize_true, materialize_false; |
| 2049 Label* if_true = NULL; |
| 2050 Label* if_false = NULL; |
| 2051 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2052 |
| 2053 __ test(eax, Immediate(kSmiTagMask)); |
| 2054 __ j(zero, if_false); |
| 2055 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2056 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2057 __ test(ebx, Immediate(1 << Map::kIsUndetectable)); |
| 2058 __ j(not_zero, if_true); |
| 2059 __ jmp(if_false); |
| 2060 |
| 2061 Apply(context_, if_true, if_false); |
| 2062 } |
| 2063 |
| 2064 |
| 2065 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) { |
| 2066 ASSERT(args->length() == 1); |
| 2067 |
| 2068 VisitForValue(args->at(0), kAccumulator); |
| 2069 |
| 2070 Label materialize_true, materialize_false; |
| 2071 Label* if_true = NULL; |
| 2072 Label* if_false = NULL; |
| 2073 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2074 |
| 2075 __ test(eax, Immediate(kSmiTagMask)); |
| 2076 __ j(zero, if_false); |
| 2077 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2078 __ j(equal, if_true); |
| 2079 __ jmp(if_false); |
| 2080 |
| 2081 Apply(context_, if_true, if_false); |
| 2082 } |
| 2083 |
| 2084 |
| 2085 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2086 ASSERT(args->length() == 1); |
| 2087 |
| 2088 VisitForValue(args->at(0), kAccumulator); |
| 2089 |
| 2090 Label materialize_true, materialize_false; |
| 2091 Label* if_true = NULL; |
| 2092 Label* if_false = NULL; |
| 2093 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2094 |
| 2095 __ test(eax, Immediate(kSmiTagMask)); |
| 2096 __ j(equal, if_false); |
| 2097 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
| 2098 __ j(equal, if_true); |
| 2099 __ jmp(if_false); |
| 2100 |
| 2101 Apply(context_, if_true, if_false); |
| 2102 } |
| 2103 |
| 2104 |
| 2105 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2106 ASSERT(args->length() == 1); |
| 2107 |
| 2108 VisitForValue(args->at(0), kAccumulator); |
| 2109 |
| 2110 Label materialize_true, materialize_false; |
| 2111 Label* if_true = NULL; |
| 2112 Label* if_false = NULL; |
| 2113 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2114 |
| 2115 __ test(eax, Immediate(kSmiTagMask)); |
| 2116 __ j(equal, if_false); |
| 2117 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx); |
| 2118 __ j(equal, if_true); |
| 2119 __ jmp(if_false); |
| 2120 |
| 2121 Apply(context_, if_true, if_false); |
| 2122 } |
| 2123 |
| 2124 |
| 2125 |
| 2126 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| 2127 ASSERT(args->length() == 0); |
| 2128 |
| 2129 Label materialize_true, materialize_false; |
| 2130 Label* if_true = NULL; |
| 2131 Label* if_false = NULL; |
| 2132 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2133 |
| 2134 // Get the frame pointer for the calling frame. |
| 2135 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2136 |
| 2137 // Skip the arguments adaptor frame if it exists. |
| 2138 Label check_frame_marker; |
| 2139 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset), |
| 2140 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2141 __ j(not_equal, &check_frame_marker); |
| 2142 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset)); |
| 2143 |
| 2144 // Check the marker in the calling frame. |
| 2145 __ bind(&check_frame_marker); |
| 2146 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset), |
| 2147 Immediate(Smi::FromInt(StackFrame::CONSTRUCT))); |
| 2148 __ j(equal, if_true); |
| 2149 __ jmp(if_false); |
| 2150 |
| 2151 Apply(context_, if_true, if_false); |
| 2152 } |
| 2153 |
| 2154 |
| 2155 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2156 ASSERT(args->length() == 2); |
| 2157 |
| 2158 // Load the two objects into registers and perform the comparison. |
| 2159 VisitForValue(args->at(0), kStack); |
| 2160 VisitForValue(args->at(1), kAccumulator); |
| 2161 |
| 2162 Label materialize_true, materialize_false; |
| 2163 Label* if_true = NULL; |
| 2164 Label* if_false = NULL; |
| 2165 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 2166 |
| 2167 __ pop(ebx); |
| 2168 __ cmp(eax, Operand(ebx)); |
| 2169 __ j(equal, if_true); |
| 2170 __ jmp(if_false); |
| 2171 |
| 2172 Apply(context_, if_true, if_false); |
| 2173 } |
| 2174 |
| 2175 |
| 2176 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2177 ASSERT(args->length() == 1); |
| 2178 |
| 2179 // ArgumentsAccessStub expects the key in edx and the formal |
| 2180 // parameter count in eax. |
| 2181 VisitForValue(args->at(0), kAccumulator); |
| 2182 __ mov(edx, eax); |
| 2183 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 2184 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2185 __ CallStub(&stub); |
| 2186 Apply(context_, eax); |
| 2187 } |
| 2188 |
| 2189 |
| 2190 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2191 ASSERT(args->length() == 0); |
| 2192 |
| 2193 Label exit; |
| 2194 // Get the number of formal parameters. |
| 2195 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); |
| 2196 |
| 2197 // Check if the calling frame is an arguments adaptor frame. |
| 2198 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2199 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), |
| 2200 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2201 __ j(not_equal, &exit); |
| 2202 |
| 2203 // Arguments adaptor case: Read the arguments length from the |
| 2204 // adaptor frame. |
| 2205 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2206 |
| 2207 __ bind(&exit); |
| 2208 if (FLAG_debug_code) __ AbortIfNotSmi(eax); |
| 2209 Apply(context_, eax); |
| 2210 } |
| 2211 |
| 2212 |
| 2213 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
| 2214 ASSERT(args->length() == 1); |
| 2215 Label done, null, function, non_function_constructor; |
| 2216 |
| 2217 VisitForValue(args->at(0), kAccumulator); |
| 2218 |
| 2219 // If the object is a smi, we return null. |
| 2220 __ test(eax, Immediate(kSmiTagMask)); |
| 2221 __ j(zero, &null); |
| 2222 |
| 2223 // Check that the object is a JS object but take special care of JS |
| 2224 // functions to make sure they have 'Function' as their class. |
| 2225 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2226 __ movzx_b(ebx, FieldOperand(eax, Map::kInstanceTypeOffset)); |
| 2227 __ cmp(ebx, FIRST_JS_OBJECT_TYPE); |
| 2228 __ j(less, &null); |
| 2229 |
| 2230 // As long as JS_FUNCTION_TYPE is the last instance type and it is |
| 2231 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
| 2232 // LAST_JS_OBJECT_TYPE. |
| 2233 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| 2234 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
| 2235 __ cmp(ebx, JS_FUNCTION_TYPE); |
| 2236 __ j(equal, &function); |
| 2237 |
| 2238 // Check if the constructor in the map is a function. |
| 2239 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); |
| 2240 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2241 __ j(not_equal, &non_function_constructor); |
| 2242 |
| 2243 // eax now contains the constructor function. Grab the |
| 2244 // instance class name from there. |
| 2245 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
| 2246 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); |
| 2247 __ jmp(&done); |
| 2248 |
| 2249 // Functions have class 'Function'. |
| 2250 __ bind(&function); |
| 2251 __ mov(eax, Factory::function_class_symbol()); |
| 2252 __ jmp(&done); |
| 2253 |
| 2254 // Objects with a non-function constructor have class 'Object'. |
| 2255 __ bind(&non_function_constructor); |
| 2256 __ mov(eax, Factory::Object_symbol()); |
| 2257 __ jmp(&done); |
| 2258 |
| 2259 // Non-JS objects have class null. |
| 2260 __ bind(&null); |
| 2261 __ mov(eax, Factory::null_value()); |
| 2262 |
| 2263 // All done. |
| 2264 __ bind(&done); |
| 2265 |
| 2266 Apply(context_, eax); |
| 2267 } |
| 2268 |
| 2269 |
| 2270 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) { |
| 2271 // Conditionally generate a log call. |
| 2272 // Args: |
| 2273 // 0 (literal string): The type of logging (corresponds to the flags). |
| 2274 // This is used to determine whether or not to generate the log call. |
| 2275 // 1 (string): Format string. Access the string at argument index 2 |
| 2276 // with '%2s' (see Logger::LogRuntime for all the formats). |
| 2277 // 2 (array): Arguments to the format string. |
| 2278 ASSERT_EQ(args->length(), 3); |
| 2279 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 2280 if (CodeGenerator::ShouldGenerateLog(args->at(0))) { |
| 2281 VisitForValue(args->at(1), kStack); |
| 2282 VisitForValue(args->at(2), kStack); |
| 2283 __ CallRuntime(Runtime::kLog, 2); |
| 2284 } |
| 2285 #endif |
| 2286 // Finally, we're expected to leave a value on the top of the stack. |
| 2287 __ mov(eax, Factory::undefined_value()); |
| 2288 Apply(context_, eax); |
| 2289 } |
| 2290 |
| 2291 |
| 2292 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) { |
| 2293 ASSERT(args->length() == 0); |
| 2294 |
| 2295 Label slow_allocate_heapnumber; |
| 2296 Label heapnumber_allocated; |
| 2297 |
| 2298 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber); |
| 2299 __ jmp(&heapnumber_allocated); |
| 2300 |
| 2301 __ bind(&slow_allocate_heapnumber); |
| 2302 // To allocate a heap number, and ensure that it is not a smi, we |
| 2303 // call the runtime function FUnaryMinus on 0, returning the double |
| 2304 // -0.0. A new, distinct heap number is returned each time. |
| 2305 __ push(Immediate(Smi::FromInt(0))); |
| 2306 __ CallRuntime(Runtime::kNumberUnaryMinus, 1); |
| 2307 __ mov(edi, eax); |
| 2308 |
| 2309 __ bind(&heapnumber_allocated); |
| 2310 |
| 2311 __ PrepareCallCFunction(0, ebx); |
| 2312 __ CallCFunction(ExternalReference::random_uint32_function(), 0); |
| 2313 |
| 2314 // Convert 32 random bits in eax to 0.(32 random bits) in a double |
| 2315 // by computing: |
| 2316 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
| 2317 // This is implemented on both SSE2 and FPU. |
| 2318 if (CpuFeatures::IsSupported(SSE2)) { |
| 2319 CpuFeatures::Scope fscope(SSE2); |
| 2320 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
| 2321 __ movd(xmm1, Operand(ebx)); |
| 2322 __ movd(xmm0, Operand(eax)); |
| 2323 __ cvtss2sd(xmm1, xmm1); |
| 2324 __ pxor(xmm0, xmm1); |
| 2325 __ subsd(xmm0, xmm1); |
| 2326 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0); |
| 2327 } else { |
| 2328 // 0x4130000000000000 is 1.0 x 2^20 as a double. |
| 2329 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset), |
| 2330 Immediate(0x41300000)); |
| 2331 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax); |
| 2332 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset)); |
| 2333 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0)); |
| 2334 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset)); |
| 2335 __ fsubp(1); |
| 2336 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset)); |
| 2337 } |
| 2338 __ mov(eax, edi); |
| 2339 Apply(context_, eax); |
| 2340 } |
| 2341 |
| 2342 |
| 2343 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) { |
| 2344 // Load the arguments on the stack and call the stub. |
| 2345 SubStringStub stub; |
| 2346 ASSERT(args->length() == 3); |
| 2347 VisitForValue(args->at(0), kStack); |
| 2348 VisitForValue(args->at(1), kStack); |
| 2349 VisitForValue(args->at(2), kStack); |
| 2350 __ CallStub(&stub); |
| 2351 Apply(context_, eax); |
| 2352 } |
| 2353 |
| 2354 |
| 2355 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) { |
| 2356 // Load the arguments on the stack and call the stub. |
| 2357 RegExpExecStub stub; |
| 2358 ASSERT(args->length() == 4); |
| 2359 VisitForValue(args->at(0), kStack); |
| 2360 VisitForValue(args->at(1), kStack); |
| 2361 VisitForValue(args->at(2), kStack); |
| 2362 VisitForValue(args->at(3), kStack); |
| 2363 __ CallStub(&stub); |
| 2364 Apply(context_, eax); |
| 2365 } |
| 2366 |
| 2367 |
| 2368 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { |
| 2369 ASSERT(args->length() == 1); |
| 2370 |
| 2371 VisitForValue(args->at(0), kAccumulator); // Load the object. |
| 2372 |
| 2373 Label done; |
| 2374 // If the object is a smi return the object. |
| 2375 __ test(eax, Immediate(kSmiTagMask)); |
| 2376 __ j(zero, &done); |
| 2377 // If the object is not a value type, return the object. |
| 2378 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); |
| 2379 __ j(not_equal, &done); |
| 2380 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 2381 |
| 2382 __ bind(&done); |
| 2383 Apply(context_, eax); |
| 2384 } |
| 2385 |
| 2386 |
| 2387 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { |
| 2388 // Load the arguments on the stack and call the runtime function. |
| 2389 ASSERT(args->length() == 2); |
| 2390 VisitForValue(args->at(0), kStack); |
| 2391 VisitForValue(args->at(1), kStack); |
| 2392 __ CallRuntime(Runtime::kMath_pow, 2); |
| 2393 Apply(context_, eax); |
| 2394 } |
| 2395 |
| 2396 |
| 2397 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2398 ASSERT(args->length() == 2); |
| 2399 |
| 2400 VisitForValue(args->at(0), kStack); // Load the object. |
| 2401 VisitForValue(args->at(1), kAccumulator); // Load the value. |
| 2402 __ pop(ebx); // eax = value. ebx = object. |
| 2403 |
| 2404 Label done; |
| 2405 // If the object is a smi, return the value. |
| 2406 __ test(ebx, Immediate(kSmiTagMask)); |
| 2407 __ j(zero, &done); |
| 2408 |
| 2409 // If the object is not a value type, return the value. |
| 2410 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); |
| 2411 __ j(not_equal, &done); |
| 2412 |
| 2413 // Store the value. |
| 2414 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
| 2415 // Update the write barrier. Save the value as it will be |
| 2416 // overwritten by the write barrier code and is needed afterward. |
| 2417 __ mov(edx, eax); |
| 2418 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx); |
| 2419 |
| 2420 __ bind(&done); |
| 2421 Apply(context_, eax); |
| 2422 } |
| 2423 |
| 2424 |
| 2425 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
| 2426 ASSERT_EQ(args->length(), 1); |
| 2427 |
| 2428 // Load the argument on the stack and call the stub. |
| 2429 VisitForValue(args->at(0), kStack); |
| 2430 |
| 2431 NumberToStringStub stub; |
| 2432 __ CallStub(&stub); |
| 2433 Apply(context_, eax); |
| 2434 } |
| 2435 |
| 2436 |
| 2437 void FullCodeGenerator::EmitCharFromCode(ZoneList<Expression*>* args) { |
| 2438 ASSERT(args->length() == 1); |
| 2439 |
| 2440 VisitForValue(args->at(0), kAccumulator); |
| 2441 |
| 2442 Label slow_case, done; |
| 2443 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 2444 ASSERT(kSmiTag == 0); |
| 2445 ASSERT(kSmiShiftSize == 0); |
| 2446 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 2447 __ test(eax, |
| 2448 Immediate(kSmiTagMask | |
| 2449 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 2450 __ j(not_zero, &slow_case); |
| 2451 __ Set(ebx, Immediate(Factory::single_character_string_cache())); |
| 2452 ASSERT(kSmiTag == 0); |
| 2453 ASSERT(kSmiTagSize == 1); |
| 2454 ASSERT(kSmiShiftSize == 0); |
| 2455 // At this point code register contains smi tagged ascii char code. |
| 2456 __ mov(ebx, FieldOperand(ebx, |
| 2457 eax, times_half_pointer_size, |
| 2458 FixedArray::kHeaderSize)); |
| 2459 __ cmp(ebx, Factory::undefined_value()); |
| 2460 __ j(equal, &slow_case); |
| 2461 __ mov(eax, ebx); |
| 2462 __ jmp(&done); |
| 2463 |
| 2464 __ bind(&slow_case); |
| 2465 __ push(eax); |
| 2466 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 2467 |
| 2468 __ bind(&done); |
| 2469 Apply(context_, eax); |
| 2470 } |
| 2471 |
| 2472 |
| 2473 void FullCodeGenerator::EmitFastCharCodeAt(ZoneList<Expression*>* args) { |
| 2474 // TODO(fsc): Port the complete implementation from the classic back-end. |
| 2475 // Move the undefined value into the result register, which will |
| 2476 // trigger the slow case. |
| 2477 __ Set(eax, Immediate(Factory::undefined_value())); |
| 2478 Apply(context_, eax); |
| 2479 } |
| 2480 |
| 2481 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) { |
| 2482 ASSERT_EQ(2, args->length()); |
| 2483 |
| 2484 VisitForValue(args->at(0), kStack); |
| 2485 VisitForValue(args->at(1), kStack); |
| 2486 |
| 2487 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 2488 __ CallStub(&stub); |
| 2489 Apply(context_, eax); |
| 2490 } |
| 2491 |
| 2492 |
| 2493 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) { |
| 2494 ASSERT_EQ(2, args->length()); |
| 2495 |
| 2496 VisitForValue(args->at(0), kStack); |
| 2497 VisitForValue(args->at(1), kStack); |
| 2498 |
| 2499 StringCompareStub stub; |
| 2500 __ CallStub(&stub); |
| 2501 Apply(context_, eax); |
| 2502 } |
| 2503 |
| 2504 |
| 2505 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { |
| 2506 // Load the argument on the stack and call the stub. |
| 2507 TranscendentalCacheStub stub(TranscendentalCache::SIN); |
| 2508 ASSERT(args->length() == 1); |
| 2509 VisitForValue(args->at(0), kStack); |
| 2510 __ CallStub(&stub); |
| 2511 Apply(context_, eax); |
| 2512 } |
| 2513 |
| 2514 |
| 2515 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { |
| 2516 // Load the argument on the stack and call the stub. |
| 2517 TranscendentalCacheStub stub(TranscendentalCache::COS); |
| 2518 ASSERT(args->length() == 1); |
| 2519 VisitForValue(args->at(0), kStack); |
| 2520 __ CallStub(&stub); |
| 2521 Apply(context_, eax); |
| 2522 } |
| 2523 |
| 2524 |
| 2525 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { |
| 2526 // Load the argument on the stack and call the runtime function. |
| 2527 ASSERT(args->length() == 1); |
| 2528 VisitForValue(args->at(0), kStack); |
| 2529 __ CallRuntime(Runtime::kMath_sqrt, 1); |
| 2530 Apply(context_, eax); |
| 2531 } |
| 2532 |
| 2533 |
| 2534 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) { |
| 2535 ASSERT(args->length() >= 2); |
| 2536 |
| 2537 int arg_count = args->length() - 2; // For receiver and function. |
| 2538 VisitForValue(args->at(0), kStack); // Receiver. |
| 2539 for (int i = 0; i < arg_count; i++) { |
| 2540 VisitForValue(args->at(i + 1), kStack); |
| 2541 } |
| 2542 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function. |
| 2543 |
| 2544 // InvokeFunction requires function in edi. Move it in there. |
| 2545 if (!result_register().is(edi)) __ mov(edi, result_register()); |
| 2546 ParameterCount count(arg_count); |
| 2547 __ InvokeFunction(edi, count, CALL_FUNCTION); |
| 2548 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2549 Apply(context_, eax); |
| 2550 } |
| 2551 |
| 2552 |
| 2553 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 2554 ASSERT(args->length() == 3); |
| 2555 VisitForValue(args->at(0), kStack); |
| 2556 VisitForValue(args->at(1), kStack); |
| 2557 VisitForValue(args->at(2), kStack); |
| 2558 __ CallRuntime(Runtime::kRegExpConstructResult, 3); |
| 2559 Apply(context_, eax); |
| 2560 } |
| 2561 |
| 2562 |
| 2563 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { |
| 2564 ASSERT(args->length() == 3); |
| 2565 VisitForValue(args->at(0), kStack); |
| 2566 VisitForValue(args->at(1), kStack); |
| 2567 VisitForValue(args->at(2), kStack); |
| 2568 __ CallRuntime(Runtime::kSwapElements, 3); |
| 2569 Apply(context_, eax); |
| 2570 } |
| 2571 |
| 2572 |
| 2573 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
| 2574 ASSERT_EQ(2, args->length()); |
| 2575 |
| 2576 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 2577 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 2578 |
| 2579 Handle<FixedArray> jsfunction_result_caches( |
| 2580 Top::global_context()->jsfunction_result_caches()); |
| 2581 if (jsfunction_result_caches->length() <= cache_id) { |
| 2582 __ Abort("Attempt to use undefined cache."); |
| 2583 __ mov(eax, Factory::undefined_value()); |
| 2584 Apply(context_, eax); |
| 2585 return; |
| 2586 } |
| 2587 |
| 2588 VisitForValue(args->at(1), kAccumulator); |
| 2589 |
| 2590 Register key = eax; |
| 2591 Register cache = ebx; |
| 2592 Register tmp = ecx; |
| 2593 __ mov(cache, CodeGenerator::ContextOperand(esi, Context::GLOBAL_INDEX)); |
| 2594 __ mov(cache, |
| 2595 FieldOperand(cache, GlobalObject::kGlobalContextOffset)); |
| 2596 __ mov(cache, |
| 2597 CodeGenerator::ContextOperand( |
| 2598 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
| 2599 __ mov(cache, |
| 2600 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
| 2601 |
| 2602 Label done, not_found; |
| 2603 // tmp now holds finger offset as a smi. |
| 2604 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 2605 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset)); |
| 2606 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp)); |
| 2607 __ j(not_equal, ¬_found); |
| 2608 |
| 2609 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1)); |
| 2610 __ jmp(&done); |
| 2611 |
| 2612 __ bind(¬_found); |
| 2613 // Call runtime to perform the lookup. |
| 2614 __ push(cache); |
| 2615 __ push(key); |
| 2616 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 2617 |
| 2618 __ bind(&done); |
| 2619 Apply(context_, eax); |
| 2620 } |
| 2621 |
| 2622 |
| 1450 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 2623 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 2624 Handle<String> name = expr->name(); |
| 2625 if (name->length() > 0 && name->Get(0) == '_') { |
| 2626 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 2627 EmitInlineRuntimeCall(expr); |
| 2628 return; |
| 2629 } |
| 2630 |
| 1451 Comment cmnt(masm_, "[ CallRuntime"); | 2631 Comment cmnt(masm_, "[ CallRuntime"); |
| 1452 ZoneList<Expression*>* args = expr->arguments(); | 2632 ZoneList<Expression*>* args = expr->arguments(); |
| 1453 | 2633 |
| 1454 if (expr->is_jsruntime()) { | 2634 if (expr->is_jsruntime()) { |
| 1455 // Prepare for calling JS runtime function. | 2635 // Prepare for calling JS runtime function. |
| 1456 __ mov(eax, CodeGenerator::GlobalObject()); | 2636 __ mov(eax, CodeGenerator::GlobalObject()); |
| 1457 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); | 2637 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); |
| 1458 } | 2638 } |
| 1459 | 2639 |
| 1460 // Push the arguments ("left-to-right"). | 2640 // Push the arguments ("left-to-right"). |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1474 } else { | 2654 } else { |
| 1475 // Call the C runtime function. | 2655 // Call the C runtime function. |
| 1476 __ CallRuntime(expr->function(), arg_count); | 2656 __ CallRuntime(expr->function(), arg_count); |
| 1477 } | 2657 } |
| 1478 Apply(context_, eax); | 2658 Apply(context_, eax); |
| 1479 } | 2659 } |
| 1480 | 2660 |
| 1481 | 2661 |
| 1482 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 2662 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 1483 switch (expr->op()) { | 2663 switch (expr->op()) { |
| 2664 case Token::DELETE: { |
| 2665 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 2666 Property* prop = expr->expression()->AsProperty(); |
| 2667 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); |
| 2668 if (prop == NULL && var == NULL) { |
| 2669 // Result of deleting non-property, non-variable reference is true. |
| 2670 // The subexpression may have side effects. |
| 2671 VisitForEffect(expr->expression()); |
| 2672 Apply(context_, true); |
| 2673 } else if (var != NULL && |
| 2674 !var->is_global() && |
| 2675 var->slot() != NULL && |
| 2676 var->slot()->type() != Slot::LOOKUP) { |
| 2677 // Result of deleting non-global, non-dynamic variables is false. |
| 2678 // The subexpression does not have side effects. |
| 2679 Apply(context_, false); |
| 2680 } else { |
| 2681 // Property or variable reference. Call the delete builtin with |
| 2682 // object and property name as arguments. |
| 2683 if (prop != NULL) { |
| 2684 VisitForValue(prop->obj(), kStack); |
| 2685 VisitForValue(prop->key(), kStack); |
| 2686 } else if (var->is_global()) { |
| 2687 __ push(CodeGenerator::GlobalObject()); |
| 2688 __ push(Immediate(var->name())); |
| 2689 } else { |
| 2690 // Non-global variable. Call the runtime to look up the context |
| 2691 // where the variable was introduced. |
| 2692 __ push(context_register()); |
| 2693 __ push(Immediate(var->name())); |
| 2694 __ CallRuntime(Runtime::kLookupContext, 2); |
| 2695 __ push(eax); |
| 2696 __ push(Immediate(var->name())); |
| 2697 } |
| 2698 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 2699 Apply(context_, eax); |
| 2700 } |
| 2701 break; |
| 2702 } |
| 2703 |
| 1484 case Token::VOID: { | 2704 case Token::VOID: { |
| 1485 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 2705 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 1486 VisitForEffect(expr->expression()); | 2706 VisitForEffect(expr->expression()); |
| 1487 switch (context_) { | 2707 switch (context_) { |
| 1488 case Expression::kUninitialized: | 2708 case Expression::kUninitialized: |
| 1489 UNREACHABLE(); | 2709 UNREACHABLE(); |
| 1490 break; | 2710 break; |
| 1491 case Expression::kEffect: | 2711 case Expression::kEffect: |
| 1492 break; | 2712 break; |
| 1493 case Expression::kValue: | 2713 case Expression::kValue: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1514 case Expression::kTest: | 2734 case Expression::kTest: |
| 1515 case Expression::kValueTest: | 2735 case Expression::kValueTest: |
| 1516 __ jmp(false_label_); | 2736 __ jmp(false_label_); |
| 1517 break; | 2737 break; |
| 1518 } | 2738 } |
| 1519 break; | 2739 break; |
| 1520 } | 2740 } |
| 1521 | 2741 |
| 1522 case Token::NOT: { | 2742 case Token::NOT: { |
| 1523 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 2743 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 1524 Label materialize_true, materialize_false, done; | 2744 Label materialize_true, materialize_false; |
| 1525 // Initially assume a pure test context. Notice that the labels are | 2745 Label* if_true = NULL; |
| 1526 // swapped. | 2746 Label* if_false = NULL; |
| 1527 Label* if_true = false_label_; | 2747 |
| 1528 Label* if_false = true_label_; | 2748 // Notice that the labels are swapped. |
| 1529 switch (context_) { | 2749 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true); |
| 1530 case Expression::kUninitialized: | 2750 |
| 1531 UNREACHABLE(); | |
| 1532 break; | |
| 1533 case Expression::kEffect: | |
| 1534 if_true = &done; | |
| 1535 if_false = &done; | |
| 1536 break; | |
| 1537 case Expression::kValue: | |
| 1538 if_true = &materialize_false; | |
| 1539 if_false = &materialize_true; | |
| 1540 break; | |
| 1541 case Expression::kTest: | |
| 1542 break; | |
| 1543 case Expression::kValueTest: | |
| 1544 if_false = &materialize_true; | |
| 1545 break; | |
| 1546 case Expression::kTestValue: | |
| 1547 if_true = &materialize_false; | |
| 1548 break; | |
| 1549 } | |
| 1550 VisitForControl(expr->expression(), if_true, if_false); | 2751 VisitForControl(expr->expression(), if_true, if_false); |
| 2752 |
| 1551 Apply(context_, if_false, if_true); // Labels swapped. | 2753 Apply(context_, if_false, if_true); // Labels swapped. |
| 1552 break; | 2754 break; |
| 1553 } | 2755 } |
| 1554 | 2756 |
| 1555 case Token::TYPEOF: { | 2757 case Token::TYPEOF: { |
| 1556 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 2758 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 1557 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 2759 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 1558 if (proxy != NULL && | 2760 if (proxy != NULL && |
| 1559 !proxy->var()->is_this() && | 2761 !proxy->var()->is_this() && |
| 1560 proxy->var()->is_global()) { | 2762 proxy->var()->is_global()) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 } | 2838 } |
| 1637 | 2839 |
| 1638 default: | 2840 default: |
| 1639 UNREACHABLE(); | 2841 UNREACHABLE(); |
| 1640 } | 2842 } |
| 1641 } | 2843 } |
| 1642 | 2844 |
| 1643 | 2845 |
| 1644 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 2846 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| 1645 Comment cmnt(masm_, "[ CountOperation"); | 2847 Comment cmnt(masm_, "[ CountOperation"); |
| 2848 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 2849 // as the left-hand side. |
| 2850 if (!expr->expression()->IsValidLeftHandSide()) { |
| 2851 VisitForEffect(expr->expression()); |
| 2852 return; |
| 2853 } |
| 1646 | 2854 |
| 1647 // Expression can only be a property, a global or a (parameter or local) | 2855 // Expression can only be a property, a global or a (parameter or local) |
| 1648 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 2856 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. |
| 1649 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 2857 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1650 LhsKind assign_type = VARIABLE; | 2858 LhsKind assign_type = VARIABLE; |
| 1651 Property* prop = expr->expression()->AsProperty(); | 2859 Property* prop = expr->expression()->AsProperty(); |
| 1652 // In case of a property we use the uninitialized expression context | 2860 // In case of a property we use the uninitialized expression context |
| 1653 // of the key to detect a named property. | 2861 // of the key to detect a named property. |
| 1654 if (prop != NULL) { | 2862 if (prop != NULL) { |
| 1655 assign_type = | 2863 assign_type = |
| 1656 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 2864 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 1657 } | 2865 } |
| 1658 | 2866 |
| 1659 // Evaluate expression and get value. | 2867 // Evaluate expression and get value. |
| 1660 if (assign_type == VARIABLE) { | 2868 if (assign_type == VARIABLE) { |
| 1661 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 2869 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 1662 Location saved_location = location_; | 2870 Location saved_location = location_; |
| 1663 location_ = kAccumulator; | 2871 location_ = kAccumulator; |
| 1664 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), | 2872 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), |
| 1665 Expression::kValue); | 2873 Expression::kValue); |
| 1666 location_ = saved_location; | 2874 location_ = saved_location; |
| 1667 } else { | 2875 } else { |
| 1668 // Reserve space for result of postfix operation. | 2876 // Reserve space for result of postfix operation. |
| 1669 if (expr->is_postfix() && context_ != Expression::kEffect) { | 2877 if (expr->is_postfix() && context_ != Expression::kEffect) { |
| 1670 __ push(Immediate(Smi::FromInt(0))); | 2878 __ push(Immediate(Smi::FromInt(0))); |
| 1671 } | 2879 } |
| 1672 if (assign_type == NAMED_PROPERTY) { | 2880 if (assign_type == NAMED_PROPERTY) { |
| 1673 // Put the object both on the stack and in the accumulator. | 2881 // Put the object both on the stack and in the accumulator. |
| 1674 VisitForValue(prop->obj(), kAccumulator); | 2882 VisitForValue(prop->obj(), kAccumulator); |
| 1675 __ push(eax); | 2883 __ push(eax); |
| 1676 EmitNamedPropertyLoad(prop); | 2884 EmitNamedPropertyLoad(prop); |
| 1677 } else { | 2885 } else { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1747 NO_OVERWRITE, | 2955 NO_OVERWRITE, |
| 1748 NO_GENERIC_BINARY_FLAGS, | 2956 NO_GENERIC_BINARY_FLAGS, |
| 1749 TypeInfo::Unknown()); | 2957 TypeInfo::Unknown()); |
| 1750 stub.GenerateCall(masm(), eax, Smi::FromInt(1)); | 2958 stub.GenerateCall(masm(), eax, Smi::FromInt(1)); |
| 1751 __ bind(&done); | 2959 __ bind(&done); |
| 1752 | 2960 |
| 1753 // Store the value returned in eax. | 2961 // Store the value returned in eax. |
| 1754 switch (assign_type) { | 2962 switch (assign_type) { |
| 1755 case VARIABLE: | 2963 case VARIABLE: |
| 1756 if (expr->is_postfix()) { | 2964 if (expr->is_postfix()) { |
| 2965 // Perform the assignment as if via '='. |
| 1757 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 2966 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 2967 Token::ASSIGN, |
| 1758 Expression::kEffect); | 2968 Expression::kEffect); |
| 1759 // For all contexts except kEffect: We have the result on | 2969 // For all contexts except kEffect: We have the result on |
| 1760 // top of the stack. | 2970 // top of the stack. |
| 1761 if (context_ != Expression::kEffect) { | 2971 if (context_ != Expression::kEffect) { |
| 1762 ApplyTOS(context_); | 2972 ApplyTOS(context_); |
| 1763 } | 2973 } |
| 1764 } else { | 2974 } else { |
| 2975 // Perform the assignment as if via '='. |
| 1765 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 2976 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 2977 Token::ASSIGN, |
| 1766 context_); | 2978 context_); |
| 1767 } | 2979 } |
| 1768 break; | 2980 break; |
| 1769 case NAMED_PROPERTY: { | 2981 case NAMED_PROPERTY: { |
| 1770 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 2982 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1771 __ pop(edx); | 2983 __ pop(edx); |
| 1772 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2984 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 1773 __ call(ic, RelocInfo::CODE_TARGET); | 2985 __ call(ic, RelocInfo::CODE_TARGET); |
| 1774 // This nop signals to the IC that there is no inlined code at the call | 2986 // This nop signals to the IC that there is no inlined code at the call |
| 1775 // site for it to patch. | 2987 // site for it to patch. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1833 VisitForValue(expr->right(), kAccumulator); | 3045 VisitForValue(expr->right(), kAccumulator); |
| 1834 EmitBinaryOp(expr->op(), context_); | 3046 EmitBinaryOp(expr->op(), context_); |
| 1835 break; | 3047 break; |
| 1836 | 3048 |
| 1837 default: | 3049 default: |
| 1838 UNREACHABLE(); | 3050 UNREACHABLE(); |
| 1839 } | 3051 } |
| 1840 } | 3052 } |
| 1841 | 3053 |
| 1842 | 3054 |
| 3055 void FullCodeGenerator::EmitNullCompare(bool strict, |
| 3056 Register obj, |
| 3057 Register null_const, |
| 3058 Label* if_true, |
| 3059 Label* if_false, |
| 3060 Register scratch) { |
| 3061 __ cmp(obj, Operand(null_const)); |
| 3062 if (strict) { |
| 3063 __ j(equal, if_true); |
| 3064 } else { |
| 3065 __ j(equal, if_true); |
| 3066 __ cmp(obj, Factory::undefined_value()); |
| 3067 __ j(equal, if_true); |
| 3068 __ test(obj, Immediate(kSmiTagMask)); |
| 3069 __ j(zero, if_false); |
| 3070 // It can be an undetectable object. |
| 3071 __ mov(scratch, FieldOperand(obj, HeapObject::kMapOffset)); |
| 3072 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset)); |
| 3073 __ test(scratch, Immediate(1 << Map::kIsUndetectable)); |
| 3074 __ j(not_zero, if_true); |
| 3075 } |
| 3076 __ jmp(if_false); |
| 3077 } |
| 3078 |
| 3079 |
| 1843 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3080 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 1844 Comment cmnt(masm_, "[ CompareOperation"); | 3081 Comment cmnt(masm_, "[ CompareOperation"); |
| 1845 | 3082 |
| 1846 // Always perform the comparison for its control flow. Pack the result | 3083 // Always perform the comparison for its control flow. Pack the result |
| 1847 // into the expression's context after the comparison is performed. | 3084 // into the expression's context after the comparison is performed. |
| 1848 Label materialize_true, materialize_false, done; | 3085 |
| 1849 // Initially assume we are in a test context. | 3086 Label materialize_true, materialize_false; |
| 1850 Label* if_true = true_label_; | 3087 Label* if_true = NULL; |
| 1851 Label* if_false = false_label_; | 3088 Label* if_false = NULL; |
| 1852 switch (context_) { | 3089 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); |
| 1853 case Expression::kUninitialized: | |
| 1854 UNREACHABLE(); | |
| 1855 break; | |
| 1856 case Expression::kEffect: | |
| 1857 if_true = &done; | |
| 1858 if_false = &done; | |
| 1859 break; | |
| 1860 case Expression::kValue: | |
| 1861 if_true = &materialize_true; | |
| 1862 if_false = &materialize_false; | |
| 1863 break; | |
| 1864 case Expression::kTest: | |
| 1865 break; | |
| 1866 case Expression::kValueTest: | |
| 1867 if_true = &materialize_true; | |
| 1868 break; | |
| 1869 case Expression::kTestValue: | |
| 1870 if_false = &materialize_false; | |
| 1871 break; | |
| 1872 } | |
| 1873 | 3090 |
| 1874 VisitForValue(expr->left(), kStack); | 3091 VisitForValue(expr->left(), kStack); |
| 1875 switch (expr->op()) { | 3092 switch (expr->op()) { |
| 1876 case Token::IN: | 3093 case Token::IN: |
| 1877 VisitForValue(expr->right(), kStack); | 3094 VisitForValue(expr->right(), kStack); |
| 1878 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3095 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 1879 __ cmp(eax, Factory::true_value()); | 3096 __ cmp(eax, Factory::true_value()); |
| 1880 __ j(equal, if_true); | 3097 __ j(equal, if_true); |
| 1881 __ jmp(if_false); | 3098 __ jmp(if_false); |
| 1882 break; | 3099 break; |
| 1883 | 3100 |
| 1884 case Token::INSTANCEOF: { | 3101 case Token::INSTANCEOF: { |
| 1885 VisitForValue(expr->right(), kStack); | 3102 VisitForValue(expr->right(), kStack); |
| 1886 InstanceofStub stub; | 3103 InstanceofStub stub; |
| 1887 __ CallStub(&stub); | 3104 __ CallStub(&stub); |
| 1888 __ test(eax, Operand(eax)); | 3105 __ test(eax, Operand(eax)); |
| 1889 __ j(zero, if_true); // The stub returns 0 for true. | 3106 __ j(zero, if_true); // The stub returns 0 for true. |
| 1890 __ jmp(if_false); | 3107 __ jmp(if_false); |
| 1891 break; | 3108 break; |
| 1892 } | 3109 } |
| 1893 | 3110 |
| 1894 default: { | 3111 default: { |
| 1895 VisitForValue(expr->right(), kAccumulator); | 3112 VisitForValue(expr->right(), kAccumulator); |
| 1896 Condition cc = no_condition; | 3113 Condition cc = no_condition; |
| 1897 bool strict = false; | 3114 bool strict = false; |
| 1898 switch (expr->op()) { | 3115 switch (expr->op()) { |
| 1899 case Token::EQ_STRICT: | 3116 case Token::EQ_STRICT: |
| 1900 strict = true; | 3117 strict = true; |
| 1901 // Fall through | 3118 // Fall through |
| 1902 case Token::EQ: | 3119 case Token::EQ: { |
| 1903 cc = equal; | 3120 cc = equal; |
| 1904 __ pop(edx); | 3121 __ pop(edx); |
| 3122 // If either operand is constant null we do a fast compare |
| 3123 // against null. |
| 3124 Literal* right_literal = expr->right()->AsLiteral(); |
| 3125 Literal* left_literal = expr->left()->AsLiteral(); |
| 3126 if (right_literal != NULL && right_literal->handle()->IsNull()) { |
| 3127 EmitNullCompare(strict, edx, eax, if_true, if_false, ecx); |
| 3128 Apply(context_, if_true, if_false); |
| 3129 return; |
| 3130 } else if (left_literal != NULL && left_literal->handle()->IsNull()) { |
| 3131 EmitNullCompare(strict, eax, edx, if_true, if_false, ecx); |
| 3132 Apply(context_, if_true, if_false); |
| 3133 return; |
| 3134 } |
| 1905 break; | 3135 break; |
| 3136 } |
| 1906 case Token::LT: | 3137 case Token::LT: |
| 1907 cc = less; | 3138 cc = less; |
| 1908 __ pop(edx); | 3139 __ pop(edx); |
| 1909 break; | 3140 break; |
| 1910 case Token::GT: | 3141 case Token::GT: |
| 1911 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 3142 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
| 1912 cc = less; | 3143 cc = less; |
| 1913 __ mov(edx, result_register()); | 3144 __ mov(edx, result_register()); |
| 1914 __ pop(eax); | 3145 __ pop(eax); |
| 1915 break; | 3146 break; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2005 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 3236 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 2006 __ mov(Operand(esp, 0), edx); | 3237 __ mov(Operand(esp, 0), edx); |
| 2007 // And return. | 3238 // And return. |
| 2008 __ ret(0); | 3239 __ ret(0); |
| 2009 } | 3240 } |
| 2010 | 3241 |
| 2011 | 3242 |
| 2012 #undef __ | 3243 #undef __ |
| 2013 | 3244 |
| 2014 } } // namespace v8::internal | 3245 } } // namespace v8::internal |
| OLD | NEW |