Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(532)

Side by Side Diff: src/x64/full-codegen-x64.cc

Issue 2084017: Version 2.2.11... (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/frames-x64.cc ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 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.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h" 28 #include "v8.h"
29 29
30 #if defined(V8_TARGET_ARCH_X64)
31
30 #include "codegen-inl.h" 32 #include "codegen-inl.h"
31 #include "compiler.h" 33 #include "compiler.h"
32 #include "debug.h" 34 #include "debug.h"
33 #include "full-codegen.h" 35 #include "full-codegen.h"
34 #include "parser.h" 36 #include "parser.h"
35 #include "scopes.h" 37 #include "scopes.h"
36 38
37 namespace v8 { 39 namespace v8 {
38 namespace internal { 40 namespace internal {
39 41
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 74 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
73 for (int i = 0; i < locals_count; i++) { 75 for (int i = 0; i < locals_count; i++) {
74 __ push(rdx); 76 __ push(rdx);
75 } 77 }
76 } 78 }
77 } 79 }
78 80
79 bool function_in_register = true; 81 bool function_in_register = true;
80 82
81 // Possibly allocate a local context. 83 // Possibly allocate a local context.
82 if (scope()->num_heap_slots() > 0) { 84 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
85 if (heap_slots > 0) {
83 Comment cmnt(masm_, "[ Allocate local context"); 86 Comment cmnt(masm_, "[ Allocate local context");
84 // Argument to NewContext is the function, which is still in rdi. 87 // Argument to NewContext is the function, which is still in rdi.
85 __ push(rdi); 88 __ push(rdi);
86 __ CallRuntime(Runtime::kNewContext, 1); 89 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
90 FastNewContextStub stub(heap_slots);
91 __ CallStub(&stub);
92 } else {
93 __ CallRuntime(Runtime::kNewContext, 1);
94 }
87 function_in_register = false; 95 function_in_register = false;
88 // Context is returned in both rax and rsi. It replaces the context 96 // Context is returned in both rax and rsi. It replaces the context
89 // passed to us. It's saved in the stack and kept live in rsi. 97 // passed to us. It's saved in the stack and kept live in rsi.
90 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); 98 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
91 99
92 // Copy any necessary parameters into the context. 100 // Copy any necessary parameters into the context.
93 int num_parameters = scope()->num_parameters(); 101 int num_parameters = scope()->num_parameters();
94 for (int i = 0; i < num_parameters; i++) { 102 for (int i = 0; i < num_parameters; i++) {
95 Slot* slot = scope()->parameter(i)->slot(); 103 Slot* slot = scope()->parameter(i)->slot();
96 if (slot != NULL && slot->type() == Slot::CONTEXT) { 104 if (slot != NULL && slot->type() == Slot::CONTEXT) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 // Store new arguments object in both "arguments" and ".arguments" slots. 144 // Store new arguments object in both "arguments" and ".arguments" slots.
137 __ movq(rcx, rax); 145 __ movq(rcx, rax);
138 Move(arguments->slot(), rax, rbx, rdx); 146 Move(arguments->slot(), rax, rbx, rdx);
139 Slot* dot_arguments_slot = 147 Slot* dot_arguments_slot =
140 scope()->arguments_shadow()->AsVariable()->slot(); 148 scope()->arguments_shadow()->AsVariable()->slot();
141 Move(dot_arguments_slot, rcx, rbx, rdx); 149 Move(dot_arguments_slot, rcx, rbx, rdx);
142 } 150 }
143 } 151 }
144 152
145 { Comment cmnt(masm_, "[ Declarations"); 153 { Comment cmnt(masm_, "[ Declarations");
146 VisitDeclarations(scope()->declarations()); 154 // For named function expressions, declare the function name as a
155 // constant.
156 if (scope()->is_function_scope() && scope()->function() != NULL) {
157 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
158 }
159 // Visit all the explicit declarations unless there is an illegal
160 // redeclaration.
161 if (scope()->HasIllegalRedeclaration()) {
162 scope()->VisitIllegalRedeclaration(this);
163 } else {
164 VisitDeclarations(scope()->declarations());
165 }
147 } 166 }
148 167
149 { Comment cmnt(masm_, "[ Stack check"); 168 { Comment cmnt(masm_, "[ Stack check");
150 Label ok; 169 Label ok;
151 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 170 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
152 __ j(above_equal, &ok); 171 __ j(above_equal, &ok);
153 StackCheckStub stub; 172 StackCheckStub stub;
154 __ CallStub(&stub); 173 __ CallStub(&stub);
155 __ bind(&ok); 174 __ bind(&ok);
156 } 175 }
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 __ movq(result_register(), reg); 439 __ movq(result_register(), reg);
421 __ movq(Operand(rsp, 0), result_register()); 440 __ movq(Operand(rsp, 0), result_register());
422 break; 441 break;
423 } 442 }
424 DoTest(context); 443 DoTest(context);
425 break; 444 break;
426 } 445 }
427 } 446 }
428 447
429 448
449 void FullCodeGenerator::PrepareTest(Label* materialize_true,
450 Label* materialize_false,
451 Label** if_true,
452 Label** if_false) {
453 switch (context_) {
454 case Expression::kUninitialized:
455 UNREACHABLE();
456 break;
457 case Expression::kEffect:
458 // In an effect context, the true and the false case branch to the
459 // same label.
460 *if_true = *if_false = materialize_true;
461 break;
462 case Expression::kValue:
463 *if_true = materialize_true;
464 *if_false = materialize_false;
465 break;
466 case Expression::kTest:
467 *if_true = true_label_;
468 *if_false = false_label_;
469 break;
470 case Expression::kValueTest:
471 *if_true = materialize_true;
472 *if_false = false_label_;
473 break;
474 case Expression::kTestValue:
475 *if_true = true_label_;
476 *if_false = materialize_false;
477 break;
478 }
479 }
480
481
430 void FullCodeGenerator::Apply(Expression::Context context, 482 void FullCodeGenerator::Apply(Expression::Context context,
431 Label* materialize_true, 483 Label* materialize_true,
432 Label* materialize_false) { 484 Label* materialize_false) {
433 switch (context) { 485 switch (context) {
434 case Expression::kUninitialized: 486 case Expression::kUninitialized:
435 487
436 case Expression::kEffect: 488 case Expression::kEffect:
437 ASSERT_EQ(materialize_true, materialize_false); 489 ASSERT_EQ(materialize_true, materialize_false);
438 __ bind(materialize_true); 490 __ bind(materialize_true);
439 break; 491 break;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 case kStack: 537 case kStack:
486 __ Push(Factory::false_value()); 538 __ Push(Factory::false_value());
487 break; 539 break;
488 } 540 }
489 __ jmp(false_label_); 541 __ jmp(false_label_);
490 break; 542 break;
491 } 543 }
492 } 544 }
493 545
494 546
547 // Convert constant control flow (true or false) to the result expected for
548 // a given expression context.
549 void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
550 switch (context) {
551 case Expression::kUninitialized:
552 UNREACHABLE();
553 break;
554 case Expression::kEffect:
555 break;
556 case Expression::kValue: {
557 Heap::RootListIndex value_root_index =
558 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
559 switch (location_) {
560 case kAccumulator:
561 __ LoadRoot(result_register(), value_root_index);
562 break;
563 case kStack:
564 __ PushRoot(value_root_index);
565 break;
566 }
567 break;
568 }
569 case Expression::kTest:
570 __ jmp(flag ? true_label_ : false_label_);
571 break;
572 case Expression::kTestValue:
573 switch (location_) {
574 case kAccumulator:
575 // If value is false it's needed.
576 if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
577 break;
578 case kStack:
579 // If value is false it's needed.
580 if (!flag) __ PushRoot(Heap::kFalseValueRootIndex);
581 break;
582 }
583 __ jmp(flag ? true_label_ : false_label_);
584 break;
585 case Expression::kValueTest:
586 switch (location_) {
587 case kAccumulator:
588 // If value is true it's needed.
589 if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
590 break;
591 case kStack:
592 // If value is true it's needed.
593 if (flag) __ PushRoot(Heap::kTrueValueRootIndex);
594 break;
595 }
596 __ jmp(flag ? true_label_ : false_label_);
597 break;
598 }
599 }
600
601
495 void FullCodeGenerator::DoTest(Expression::Context context) { 602 void FullCodeGenerator::DoTest(Expression::Context context) {
496 // The value to test is in the accumulator. If the value might be needed 603 // The value to test is in the accumulator. If the value might be needed
497 // on the stack (value/test and test/value contexts with a stack location 604 // on the stack (value/test and test/value contexts with a stack location
498 // desired), then the value is already duplicated on the stack. 605 // desired), then the value is already duplicated on the stack.
499 ASSERT_NE(NULL, true_label_); 606 ASSERT_NE(NULL, true_label_);
500 ASSERT_NE(NULL, false_label_); 607 ASSERT_NE(NULL, false_label_);
501 608
502 // In value/test and test/value expression contexts with stack as the 609 // In value/test and test/value expression contexts with stack as the
503 // desired location, there is already an extra value on the stack. Use a 610 // desired location, there is already an extra value on the stack. Use a
504 // label to discard it if unneeded. 611 // label to discard it if unneeded.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 MemOperand location = EmitSlotSearch(dst, scratch1); 767 MemOperand location = EmitSlotSearch(dst, scratch1);
661 __ movq(location, src); 768 __ movq(location, src);
662 // Emit the write barrier code if the location is in the heap. 769 // Emit the write barrier code if the location is in the heap.
663 if (dst->type() == Slot::CONTEXT) { 770 if (dst->type() == Slot::CONTEXT) {
664 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 771 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
665 __ RecordWrite(scratch1, offset, src, scratch2); 772 __ RecordWrite(scratch1, offset, src, scratch2);
666 } 773 }
667 } 774 }
668 775
669 776
670 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 777 void FullCodeGenerator::EmitDeclaration(Variable* variable,
778 Variable::Mode mode,
779 FunctionLiteral* function) {
671 Comment cmnt(masm_, "[ Declaration"); 780 Comment cmnt(masm_, "[ Declaration");
672 Variable* var = decl->proxy()->var(); 781 ASSERT(variable != NULL); // Must have been resolved.
673 ASSERT(var != NULL); // Must have been resolved. 782 Slot* slot = variable->slot();
674 Slot* slot = var->slot(); 783 Property* prop = variable->AsProperty();
675 Property* prop = var->AsProperty();
676 784
677 if (slot != NULL) { 785 if (slot != NULL) {
678 switch (slot->type()) { 786 switch (slot->type()) {
679 case Slot::PARAMETER: 787 case Slot::PARAMETER:
680 case Slot::LOCAL: 788 case Slot::LOCAL:
681 if (decl->mode() == Variable::CONST) { 789 if (mode == Variable::CONST) {
682 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 790 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
683 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); 791 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
684 } else if (decl->fun() != NULL) { 792 } else if (function != NULL) {
685 VisitForValue(decl->fun(), kAccumulator); 793 VisitForValue(function, kAccumulator);
686 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 794 __ movq(Operand(rbp, SlotOffset(slot)), result_register());
687 } 795 }
688 break; 796 break;
689 797
690 case Slot::CONTEXT: 798 case Slot::CONTEXT:
691 // We bypass the general EmitSlotSearch because we know more about 799 // We bypass the general EmitSlotSearch because we know more about
692 // this specific context. 800 // this specific context.
693 801
694 // The variable in the decl always resides in the current context. 802 // The variable in the decl always resides in the current context.
695 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); 803 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
696 if (FLAG_debug_code) { 804 if (FLAG_debug_code) {
697 // Check if we have the correct context pointer. 805 // Check if we have the correct context pointer.
698 __ movq(rbx, 806 __ movq(rbx,
699 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); 807 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX));
700 __ cmpq(rbx, rsi); 808 __ cmpq(rbx, rsi);
701 __ Check(equal, "Unexpected declaration in current context."); 809 __ Check(equal, "Unexpected declaration in current context.");
702 } 810 }
703 if (decl->mode() == Variable::CONST) { 811 if (mode == Variable::CONST) {
704 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 812 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
705 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 813 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
706 kScratchRegister); 814 kScratchRegister);
707 // No write barrier since the hole value is in old space. 815 // No write barrier since the hole value is in old space.
708 } else if (decl->fun() != NULL) { 816 } else if (function != NULL) {
709 VisitForValue(decl->fun(), kAccumulator); 817 VisitForValue(function, kAccumulator);
710 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 818 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
711 result_register()); 819 result_register());
712 int offset = Context::SlotOffset(slot->index()); 820 int offset = Context::SlotOffset(slot->index());
713 __ movq(rbx, rsi); 821 __ movq(rbx, rsi);
714 __ RecordWrite(rbx, offset, result_register(), rcx); 822 __ RecordWrite(rbx, offset, result_register(), rcx);
715 } 823 }
716 break; 824 break;
717 825
718 case Slot::LOOKUP: { 826 case Slot::LOOKUP: {
719 __ push(rsi); 827 __ push(rsi);
720 __ Push(var->name()); 828 __ Push(variable->name());
721 // Declaration nodes are always introduced in one of two modes. 829 // Declaration nodes are always introduced in one of two modes.
722 ASSERT(decl->mode() == Variable::VAR || 830 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
723 decl->mode() == Variable::CONST); 831 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
724 PropertyAttributes attr =
725 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
726 __ Push(Smi::FromInt(attr)); 832 __ Push(Smi::FromInt(attr));
727 // Push initial value, if any. 833 // Push initial value, if any.
728 // Note: For variables we must not push an initial value (such as 834 // Note: For variables we must not push an initial value (such as
729 // 'undefined') because we may have a (legal) redeclaration and we 835 // 'undefined') because we may have a (legal) redeclaration and we
730 // must not destroy the current value. 836 // must not destroy the current value.
731 if (decl->mode() == Variable::CONST) { 837 if (mode == Variable::CONST) {
732 __ PushRoot(Heap::kTheHoleValueRootIndex); 838 __ PushRoot(Heap::kTheHoleValueRootIndex);
733 } else if (decl->fun() != NULL) { 839 } else if (function != NULL) {
734 VisitForValue(decl->fun(), kStack); 840 VisitForValue(function, kStack);
735 } else { 841 } else {
736 __ Push(Smi::FromInt(0)); // no initial value! 842 __ Push(Smi::FromInt(0)); // no initial value!
737 } 843 }
738 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 844 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
739 break; 845 break;
740 } 846 }
741 } 847 }
742 848
743 } else if (prop != NULL) { 849 } else if (prop != NULL) {
744 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { 850 if (function != NULL || mode == Variable::CONST) {
745 // We are declaring a function or constant that rewrites to a 851 // We are declaring a function or constant that rewrites to a
746 // property. Use (keyed) IC to set the initial value. 852 // property. Use (keyed) IC to set the initial value.
747 VisitForValue(prop->obj(), kStack); 853 VisitForValue(prop->obj(), kStack);
748 VisitForValue(prop->key(), kStack); 854 if (function != NULL) {
749 855 VisitForValue(prop->key(), kStack);
750 if (decl->fun() != NULL) { 856 VisitForValue(function, kAccumulator);
751 VisitForValue(decl->fun(), kAccumulator); 857 __ pop(rcx);
752 } else { 858 } else {
859 VisitForValue(prop->key(), kAccumulator);
860 __ movq(rcx, result_register());
753 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); 861 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
754 } 862 }
863 __ pop(rdx);
755 864
756 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 865 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
757 __ call(ic, RelocInfo::CODE_TARGET); 866 __ call(ic, RelocInfo::CODE_TARGET);
758 // Absence of a test rax instruction following the call 867 // Absence of a test rax instruction following the call
759 // indicates that none of the load was inlined. 868 // indicates that none of the load was inlined.
760 __ nop(); 869 __ nop();
761
762 // Value in rax is ignored (declarations are statements). Receiver
763 // and key on stack are discarded.
764 __ Drop(2);
765 } 870 }
766 } 871 }
767 } 872 }
768 873
769 874
875 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
876 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
877 }
878
879
770 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 880 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
771 // Call the runtime to declare the globals. 881 // Call the runtime to declare the globals.
772 __ push(rsi); // The context is the first argument. 882 __ push(rsi); // The context is the first argument.
773 __ Push(pairs); 883 __ Push(pairs);
774 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 884 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
775 __ CallRuntime(Runtime::kDeclareGlobals, 3); 885 __ CallRuntime(Runtime::kDeclareGlobals, 3);
776 // Return value is ignored. 886 // Return value is ignored.
777 } 887 }
778 888
779 889
780 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 890 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
781 Comment cmnt(masm_, "[ FunctionLiteral"); 891 Comment cmnt(masm_, "[ SwitchStatement");
782 892 Breakable nested_statement(this, stmt);
783 // Build the shared function info and instantiate the function based 893 SetStatementPosition(stmt);
784 // on it. 894 // Keep the switch value on the stack until a case matches.
785 Handle<SharedFunctionInfo> function_info = 895 VisitForValue(stmt->tag(), kStack);
786 Compiler::BuildFunctionInfo(expr, script(), this); 896
787 if (HasStackOverflow()) return; 897 ZoneList<CaseClause*>* clauses = stmt->cases();
788 898 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
789 // Create a new closure. 899
790 __ push(rsi); 900 Label next_test; // Recycled for each test.
791 __ Push(function_info); 901 // Compile all the tests with branches to their bodies.
792 __ CallRuntime(Runtime::kNewClosure, 2); 902 for (int i = 0; i < clauses->length(); i++) {
903 CaseClause* clause = clauses->at(i);
904 // The default is not a test, but remember it as final fall through.
905 if (clause->is_default()) {
906 default_clause = clause;
907 continue;
908 }
909
910 Comment cmnt(masm_, "[ Case comparison");
911 __ bind(&next_test);
912 next_test.Unuse();
913
914 // Compile the label expression.
915 VisitForValue(clause->label(), kAccumulator);
916
917 // Perform the comparison as if via '==='. The comparison stub expects
918 // the smi vs. smi case to be handled before it is called.
919 Label slow_case;
920 __ movq(rdx, Operand(rsp, 0)); // Switch value.
921 __ JumpIfNotBothSmi(rdx, rax, &slow_case);
922 __ SmiCompare(rdx, rax);
923 __ j(not_equal, &next_test);
924 __ Drop(1); // Switch value is no longer needed.
925 __ jmp(clause->body_target()->entry_label());
926
927 __ bind(&slow_case);
928 CompareStub stub(equal, true);
929 __ CallStub(&stub);
930 __ testq(rax, rax);
931 __ j(not_equal, &next_test);
932 __ Drop(1); // Switch value is no longer needed.
933 __ jmp(clause->body_target()->entry_label());
934 }
935
936 // Discard the test value and jump to the default if present, otherwise to
937 // the end of the statement.
938 __ bind(&next_test);
939 __ Drop(1); // Switch value is no longer needed.
940 if (default_clause == NULL) {
941 __ jmp(nested_statement.break_target());
942 } else {
943 __ jmp(default_clause->body_target()->entry_label());
944 }
945
946 // Compile all the case bodies.
947 for (int i = 0; i < clauses->length(); i++) {
948 Comment cmnt(masm_, "[ Case body");
949 CaseClause* clause = clauses->at(i);
950 __ bind(clause->body_target()->entry_label());
951 VisitStatements(clause->statements());
952 }
953
954 __ bind(nested_statement.break_target());
955 }
956
957
958 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
959 Comment cmnt(masm_, "[ ForInStatement");
960 SetStatementPosition(stmt);
961
962 Label loop, exit;
963 ForIn loop_statement(this, stmt);
964 increment_loop_depth();
965
966 // Get the object to enumerate over. Both SpiderMonkey and JSC
967 // ignore null and undefined in contrast to the specification; see
968 // ECMA-262 section 12.6.4.
969 VisitForValue(stmt->enumerable(), kAccumulator);
970 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
971 __ j(equal, &exit);
972 __ CompareRoot(rax, Heap::kNullValueRootIndex);
973 __ j(equal, &exit);
974
975 // Convert the object to a JS object.
976 Label convert, done_convert;
977 __ JumpIfSmi(rax, &convert);
978 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
979 __ j(above_equal, &done_convert);
980 __ bind(&convert);
981 __ push(rax);
982 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
983 __ bind(&done_convert);
984 __ push(rax);
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(rax); // 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 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1001 Heap::kMetaMapRootIndex);
1002 __ j(not_equal, &fixed_array);
1003
1004 // We got a map in register rax. Get the enumeration cache from it.
1005 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset));
1006 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
1007 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1008
1009 // Setup the four remaining stack slots.
1010 __ push(rax); // Map.
1011 __ push(rdx); // Enumeration cache.
1012 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
1013 __ Integer32ToSmi(rax, rax);
1014 __ push(rax); // Enumeration cache length (as smi).
1015 __ Push(Smi::FromInt(0)); // Initial index.
1016 __ jmp(&loop);
1017
1018 // We got a fixed array in register rax. Iterate through that.
1019 __ bind(&fixed_array);
1020 __ Push(Smi::FromInt(0)); // Map (0) - force slow check.
1021 __ push(rax);
1022 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1023 __ Integer32ToSmi(rax, rax);
1024 __ push(rax); // Fixed array length (as smi).
1025 __ Push(Smi::FromInt(0)); // Initial index.
1026
1027 // Generate code for doing the condition check.
1028 __ bind(&loop);
1029 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1030 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
1031 __ j(above_equal, loop_statement.break_target());
1032
1033 // Get the current entry of the array into register rbx.
1034 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
1035 SmiIndex index = __ SmiToIndex(rax, rax, kPointerSizeLog2);
1036 __ movq(rbx, FieldOperand(rbx,
1037 index.reg,
1038 index.scale,
1039 FixedArray::kHeaderSize));
1040
1041 // Get the expected map from the stack or a zero map in the
1042 // permanent slow case into register rdx.
1043 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
1044
1045 // Check if the expected map still matches that of the enumerable.
1046 // If not, we have to filter the key.
1047 Label update_each;
1048 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1049 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
1050 __ j(equal, &update_each);
1051
1052 // Convert the entry to a string or null if it isn't a property
1053 // anymore. If the property has been removed while iterating, we
1054 // just skip it.
1055 __ push(rcx); // Enumerable.
1056 __ push(rbx); // Current entry.
1057 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1058 __ CompareRoot(rax, Heap::kNullValueRootIndex);
1059 __ j(equal, loop_statement.continue_target());
1060 __ movq(rbx, rax);
1061
1062 // Update the 'each' property or variable from the possibly filtered
1063 // entry in register rbx.
1064 __ bind(&update_each);
1065 __ movq(result_register(), rbx);
1066 // Perform the assignment as if via '='.
1067 EmitAssignment(stmt->each());
1068
1069 // Generate code for the body of the loop.
1070 Label stack_limit_hit, stack_check_done;
1071 Visit(stmt->body());
1072
1073 __ StackLimitCheck(&stack_limit_hit);
1074 __ bind(&stack_check_done);
1075
1076 // Generate code for going to the next element by incrementing the
1077 // index (smi) stored on top of the stack.
1078 __ bind(loop_statement.continue_target());
1079 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1080 __ jmp(&loop);
1081
1082 // Slow case for the stack limit check.
1083 StackCheckStub stack_check_stub;
1084 __ bind(&stack_limit_hit);
1085 __ CallStub(&stack_check_stub);
1086 __ jmp(&stack_check_done);
1087
1088 // Remove the pointers stored on the stack.
1089 __ bind(loop_statement.break_target());
1090 __ addq(rsp, Immediate(5 * kPointerSize));
1091
1092 // Exit and decrement the loop depth.
1093 __ bind(&exit);
1094 decrement_loop_depth();
1095 }
1096
1097
1098 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
1099 // Use the fast case closure allocation code that allocates in new
1100 // space for nested functions that don't need literals cloning.
1101 if (scope()->is_function_scope() && info->num_literals() == 0) {
1102 FastNewClosureStub stub;
1103 __ Push(info);
1104 __ CallStub(&stub);
1105 } else {
1106 __ push(rsi);
1107 __ Push(info);
1108 __ CallRuntime(Runtime::kNewClosure, 2);
1109 }
793 Apply(context_, rax); 1110 Apply(context_, rax);
794 } 1111 }
795 1112
796 1113
797 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 1114 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
798 Comment cmnt(masm_, "[ VariableProxy"); 1115 Comment cmnt(masm_, "[ VariableProxy");
799 EmitVariableLoad(expr->var(), context_); 1116 EmitVariableLoad(expr->var(), context_);
800 } 1117 }
801 1118
802 1119
(...skipping 23 matching lines...) Expand all
826 Comment cmnt(masm_, "Lookup slot"); 1143 Comment cmnt(masm_, "Lookup slot");
827 __ push(rsi); // Context. 1144 __ push(rsi); // Context.
828 __ Push(var->name()); 1145 __ Push(var->name());
829 __ CallRuntime(Runtime::kLoadContextSlot, 2); 1146 __ CallRuntime(Runtime::kLoadContextSlot, 2);
830 Apply(context, rax); 1147 Apply(context, rax);
831 1148
832 } else if (slot != NULL) { 1149 } else if (slot != NULL) {
833 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 1150 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
834 ? "Context slot" 1151 ? "Context slot"
835 : "Stack slot"); 1152 : "Stack slot");
836 Apply(context, slot); 1153 if (var->mode() == Variable::CONST) {
1154 // Constants may be the hole value if they have not been initialized.
1155 // Unhole them.
1156 Label done;
1157 MemOperand slot_operand = EmitSlotSearch(slot, rax);
1158 __ movq(rax, slot_operand);
1159 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1160 __ j(not_equal, &done);
1161 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1162 __ bind(&done);
1163 Apply(context, rax);
1164 } else {
1165 Apply(context, slot);
1166 }
837 1167
838 } else { 1168 } else {
839 Comment cmnt(masm_, "Rewritten parameter"); 1169 Comment cmnt(masm_, "Rewritten parameter");
840 ASSERT_NOT_NULL(property); 1170 ASSERT_NOT_NULL(property);
841 // Rewritten parameter accesses are of the form "slot[literal]". 1171 // Rewritten parameter accesses are of the form "slot[literal]".
842 1172
843 // Assert that the object is in a slot. 1173 // Assert that the object is in a slot.
844 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 1174 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
845 ASSERT_NOT_NULL(object_var); 1175 ASSERT_NOT_NULL(object_var);
846 Slot* object_slot = object_var->slot(); 1176 Slot* object_slot = object_var->slot();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 if (result_saved) { 1292 if (result_saved) {
963 ApplyTOS(context_); 1293 ApplyTOS(context_);
964 } else { 1294 } else {
965 Apply(context_, rax); 1295 Apply(context_, rax);
966 } 1296 }
967 } 1297 }
968 1298
969 1299
970 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1300 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
971 Comment cmnt(masm_, "[ ArrayLiteral"); 1301 Comment cmnt(masm_, "[ ArrayLiteral");
1302
1303 ZoneList<Expression*>* subexprs = expr->values();
1304 int length = subexprs->length();
1305
972 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 1306 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
973 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); 1307 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
974 __ Push(Smi::FromInt(expr->literal_index())); 1308 __ Push(Smi::FromInt(expr->literal_index()));
975 __ Push(expr->constant_elements()); 1309 __ Push(expr->constant_elements());
976 if (expr->depth() > 1) { 1310 if (expr->depth() > 1) {
977 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 1311 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1312 } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
1313 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
978 } else { 1314 } else {
979 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 1315 FastCloneShallowArrayStub stub(length);
1316 __ CallStub(&stub);
980 } 1317 }
981 1318
982 bool result_saved = false; // Is the result saved to the stack? 1319 bool result_saved = false; // Is the result saved to the stack?
983 1320
984 // Emit code to evaluate all the non-constant subexpressions and to store 1321 // Emit code to evaluate all the non-constant subexpressions and to store
985 // them into the newly cloned array. 1322 // them into the newly cloned array.
986 ZoneList<Expression*>* subexprs = expr->values(); 1323 for (int i = 0; i < length; i++) {
987 for (int i = 0, len = subexprs->length(); i < len; i++) {
988 Expression* subexpr = subexprs->at(i); 1324 Expression* subexpr = subexprs->at(i);
989 // If the subexpression is a literal or a simple materialized literal it 1325 // If the subexpression is a literal or a simple materialized literal it
990 // is already set in the cloned array. 1326 // is already set in the cloned array.
991 if (subexpr->AsLiteral() != NULL || 1327 if (subexpr->AsLiteral() != NULL ||
992 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1328 CompileTimeValue::IsCompileTimeValue(subexpr)) {
993 continue; 1329 continue;
994 } 1330 }
995 1331
996 if (!result_saved) { 1332 if (!result_saved) {
997 __ push(rax); 1333 __ push(rax);
(...skipping 14 matching lines...) Expand all
1012 if (result_saved) { 1348 if (result_saved) {
1013 ApplyTOS(context_); 1349 ApplyTOS(context_);
1014 } else { 1350 } else {
1015 Apply(context_, rax); 1351 Apply(context_, rax);
1016 } 1352 }
1017 } 1353 }
1018 1354
1019 1355
1020 void FullCodeGenerator::VisitAssignment(Assignment* expr) { 1356 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1021 Comment cmnt(masm_, "[ Assignment"); 1357 Comment cmnt(masm_, "[ Assignment");
1022 ASSERT(expr->op() != Token::INIT_CONST); 1358 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1359 // on the left-hand side.
1360 if (!expr->target()->IsValidLeftHandSide()) {
1361 VisitForEffect(expr->target());
1362 return;
1363 }
1364
1023 // Left-hand side can only be a property, a global or a (parameter or local) 1365 // Left-hand side can only be a property, a global or a (parameter or local)
1024 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1366 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1025 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1367 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1026 LhsKind assign_type = VARIABLE; 1368 LhsKind assign_type = VARIABLE;
1027 Property* prop = expr->target()->AsProperty(); 1369 Property* prop = expr->target()->AsProperty();
1028 if (prop != NULL) { 1370 if (prop != NULL) {
1029 assign_type = 1371 assign_type =
1030 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1372 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1031 } 1373 }
1032 1374
1033 // Evaluate LHS expression. 1375 // Evaluate LHS expression.
1034 switch (assign_type) { 1376 switch (assign_type) {
1035 case VARIABLE: 1377 case VARIABLE:
1036 // Nothing to do here. 1378 // Nothing to do here.
1037 break; 1379 break;
1038 case NAMED_PROPERTY: 1380 case NAMED_PROPERTY:
1039 if (expr->is_compound()) { 1381 if (expr->is_compound()) {
1040 // We need the receiver both on the stack and in the accumulator. 1382 // We need the receiver both on the stack and in the accumulator.
1041 VisitForValue(prop->obj(), kAccumulator); 1383 VisitForValue(prop->obj(), kAccumulator);
1042 __ push(result_register()); 1384 __ push(result_register());
1043 } else { 1385 } else {
1044 VisitForValue(prop->obj(), kStack); 1386 VisitForValue(prop->obj(), kStack);
1045 } 1387 }
1046 break; 1388 break;
1047 case KEYED_PROPERTY: 1389 case KEYED_PROPERTY:
1048 VisitForValue(prop->obj(), kStack); 1390 if (expr->is_compound()) {
1049 VisitForValue(prop->key(), kStack); 1391 VisitForValue(prop->obj(), kStack);
1392 VisitForValue(prop->key(), kAccumulator);
1393 __ movq(rdx, Operand(rsp, 0));
1394 __ push(rax);
1395 } else {
1396 VisitForValue(prop->obj(), kStack);
1397 VisitForValue(prop->key(), kStack);
1398 }
1050 break; 1399 break;
1051 } 1400 }
1052 1401
1053 // If we have a compound assignment: Get value of LHS expression and 1402 // If we have a compound assignment: Get value of LHS expression and
1054 // store in on top of the stack. 1403 // store in on top of the stack.
1055 if (expr->is_compound()) { 1404 if (expr->is_compound()) {
1056 Location saved_location = location_; 1405 Location saved_location = location_;
1057 location_ = kStack; 1406 location_ = kStack;
1058 switch (assign_type) { 1407 switch (assign_type) {
1059 case VARIABLE: 1408 case VARIABLE:
(...skipping 24 matching lines...) Expand all
1084 location_ = saved_location; 1433 location_ = saved_location;
1085 } 1434 }
1086 1435
1087 // Record source position before possible IC call. 1436 // Record source position before possible IC call.
1088 SetSourcePosition(expr->position()); 1437 SetSourcePosition(expr->position());
1089 1438
1090 // Store the value. 1439 // Store the value.
1091 switch (assign_type) { 1440 switch (assign_type) {
1092 case VARIABLE: 1441 case VARIABLE:
1093 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1442 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1443 expr->op(),
1094 context_); 1444 context_);
1095 break; 1445 break;
1096 case NAMED_PROPERTY: 1446 case NAMED_PROPERTY:
1097 EmitNamedPropertyAssignment(expr); 1447 EmitNamedPropertyAssignment(expr);
1098 break; 1448 break;
1099 case KEYED_PROPERTY: 1449 case KEYED_PROPERTY:
1100 EmitKeyedPropertyAssignment(expr); 1450 EmitKeyedPropertyAssignment(expr);
1101 break; 1451 break;
1102 } 1452 }
1103 } 1453 }
(...skipping 21 matching lines...) Expand all
1125 Expression::Context context) { 1475 Expression::Context context) {
1126 __ push(result_register()); 1476 __ push(result_register());
1127 GenericBinaryOpStub stub(op, 1477 GenericBinaryOpStub stub(op,
1128 NO_OVERWRITE, 1478 NO_OVERWRITE,
1129 NO_GENERIC_BINARY_FLAGS); 1479 NO_GENERIC_BINARY_FLAGS);
1130 __ CallStub(&stub); 1480 __ CallStub(&stub);
1131 Apply(context, rax); 1481 Apply(context, rax);
1132 } 1482 }
1133 1483
1134 1484
1485 void FullCodeGenerator::EmitAssignment(Expression* expr) {
1486 // Invalid left-hand sides are rewritten to have a 'throw
1487 // ReferenceError' on the left-hand side.
1488 if (!expr->IsValidLeftHandSide()) {
1489 VisitForEffect(expr);
1490 return;
1491 }
1492
1493 // Left-hand side can only be a property, a global or a (parameter or local)
1494 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1495 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1496 LhsKind assign_type = VARIABLE;
1497 Property* prop = expr->AsProperty();
1498 if (prop != NULL) {
1499 assign_type = (prop->key()->IsPropertyName())
1500 ? NAMED_PROPERTY
1501 : KEYED_PROPERTY;
1502 }
1503
1504 switch (assign_type) {
1505 case VARIABLE: {
1506 Variable* var = expr->AsVariableProxy()->var();
1507 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1508 break;
1509 }
1510 case NAMED_PROPERTY: {
1511 __ push(rax); // Preserve value.
1512 VisitForValue(prop->obj(), kAccumulator);
1513 __ movq(rdx, rax);
1514 __ pop(rax); // Restore value.
1515 __ Move(rcx, prop->key()->AsLiteral()->handle());
1516 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1517 __ call(ic, RelocInfo::CODE_TARGET);
1518 __ nop(); // Signal no inlined code.
1519 break;
1520 }
1521 case KEYED_PROPERTY: {
1522 __ push(rax); // Preserve value.
1523 VisitForValue(prop->obj(), kStack);
1524 VisitForValue(prop->key(), kStack);
1525 __ movq(rax, Operand(rsp, 2 * kPointerSize));
1526 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1527 __ call(ic, RelocInfo::CODE_TARGET);
1528 __ nop(); // Signal no inlined code.
1529 __ Drop(3); // Receiver, key, and extra copy of value.
1530 break;
1531 }
1532 }
1533 }
1534
1535
1135 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1536 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1537 Token::Value op,
1136 Expression::Context context) { 1538 Expression::Context context) {
1137 // Three main cases: non-this global variables, lookup slots, and 1539 // Left-hand sides that rewrite to explicit property accesses do not reach
1138 // all other types of slots. Left-hand-side parameters that rewrite 1540 // here.
1139 // to explicit property accesses do not reach here.
1140 ASSERT(var != NULL); 1541 ASSERT(var != NULL);
1141 ASSERT(var->is_global() || var->slot() != NULL); 1542 ASSERT(var->is_global() || var->slot() != NULL);
1142 Slot* slot = var->slot(); 1543
1143 if (var->is_global()) { 1544 if (var->is_global()) {
1144 ASSERT(!var->is_this()); 1545 ASSERT(!var->is_this());
1145 // Assignment to a global variable. Use inline caching for the 1546 // Assignment to a global variable. Use inline caching for the
1146 // assignment. Right-hand-side value is passed in rax, variable name in 1547 // assignment. Right-hand-side value is passed in rax, variable name in
1147 // rcx, and the global object in rdx. 1548 // rcx, and the global object on the stack.
1148 __ Move(rcx, var->name()); 1549 __ Move(rcx, var->name());
1149 __ movq(rdx, CodeGenerator::GlobalObject()); 1550 __ movq(rdx, CodeGenerator::GlobalObject());
1150 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1551 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1151 __ Call(ic, RelocInfo::CODE_TARGET); 1552 __ Call(ic, RelocInfo::CODE_TARGET);
1152 Apply(context, rax); 1553 __ nop();
1153 1554
1154 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 1555 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1155 __ push(result_register()); // Value. 1556 // Perform the assignment for non-const variables and for initialization
1156 __ push(rsi); // Context. 1557 // of const variables. Const assignments are simply skipped.
1157 __ Push(var->name()); 1558 Label done;
1158 __ CallRuntime(Runtime::kStoreContextSlot, 3); 1559 Slot* slot = var->slot();
1159 Apply(context, rax);
1160
1161 } else if (var->slot() != NULL) {
1162 switch (slot->type()) { 1560 switch (slot->type()) {
1561 case Slot::PARAMETER:
1163 case Slot::LOCAL: 1562 case Slot::LOCAL:
1164 case Slot::PARAMETER: 1563 if (op == Token::INIT_CONST) {
1165 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 1564 // Detect const reinitialization by checking for the hole value.
1565 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1566 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1567 __ j(not_equal, &done);
1568 }
1569 // Perform the assignment.
1570 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1166 break; 1571 break;
1167 1572
1168 case Slot::CONTEXT: { 1573 case Slot::CONTEXT: {
1169 MemOperand target = EmitSlotSearch(slot, rcx); 1574 MemOperand target = EmitSlotSearch(slot, rcx);
1170 __ movq(target, result_register()); 1575 if (op == Token::INIT_CONST) {
1171 1576 // Detect const reinitialization by checking for the hole value.
1172 // RecordWrite may destroy all its register arguments. 1577 __ movq(rdx, target);
1173 __ movq(rdx, result_register()); 1578 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1579 __ j(not_equal, &done);
1580 }
1581 // Perform the assignment and issue the write barrier.
1582 __ movq(target, rax);
1583 // The value of the assignment is in rax. RecordWrite clobbers its
1584 // register arguments.
1585 __ movq(rdx, rax);
1174 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1586 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1175 __ RecordWrite(rcx, offset, rdx, rbx); 1587 __ RecordWrite(rcx, offset, rdx, rbx);
1176 break; 1588 break;
1177 } 1589 }
1178 1590
1179 case Slot::LOOKUP: 1591 case Slot::LOOKUP:
1180 UNREACHABLE(); 1592 // Call the runtime for the assignment. The runtime will ignore
1593 // const reinitialization.
1594 __ push(rax); // Value.
1595 __ push(rsi); // Context.
1596 __ Push(var->name());
1597 if (op == Token::INIT_CONST) {
1598 // The runtime will ignore const redeclaration.
1599 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1600 } else {
1601 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1602 }
1181 break; 1603 break;
1182 } 1604 }
1183 Apply(context, result_register()); 1605 __ bind(&done);
1606 }
1184 1607
1185 } else { 1608 Apply(context, rax);
1186 // Variables rewritten as properties are not treated as variables in
1187 // assignments.
1188 UNREACHABLE();
1189 }
1190 } 1609 }
1191 1610
1192 1611
1193 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1612 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1194 // Assignment to a property, using a named store IC. 1613 // Assignment to a property, using a named store IC.
1195 Property* prop = expr->target()->AsProperty(); 1614 Property* prop = expr->target()->AsProperty();
1196 ASSERT(prop != NULL); 1615 ASSERT(prop != NULL);
1197 ASSERT(prop->key()->AsLiteral() != NULL); 1616 ASSERT(prop->key()->AsLiteral() != NULL);
1198 1617
1199 // If the assignment starts a block of assignments to the same object, 1618 // If the assignment starts a block of assignments to the same object,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1238 // change to slow case to avoid the quadratic behavior of repeatedly 1657 // change to slow case to avoid the quadratic behavior of repeatedly
1239 // adding fast properties. 1658 // adding fast properties.
1240 if (expr->starts_initialization_block()) { 1659 if (expr->starts_initialization_block()) {
1241 __ push(result_register()); 1660 __ push(result_register());
1242 // Receiver is now under the key and value. 1661 // Receiver is now under the key and value.
1243 __ push(Operand(rsp, 2 * kPointerSize)); 1662 __ push(Operand(rsp, 2 * kPointerSize));
1244 __ CallRuntime(Runtime::kToSlowProperties, 1); 1663 __ CallRuntime(Runtime::kToSlowProperties, 1);
1245 __ pop(result_register()); 1664 __ pop(result_register());
1246 } 1665 }
1247 1666
1667 __ pop(rcx);
1668 if (expr->ends_initialization_block()) {
1669 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1670 } else {
1671 __ pop(rdx);
1672 }
1248 // Record source code position before IC call. 1673 // Record source code position before IC call.
1249 SetSourcePosition(expr->position()); 1674 SetSourcePosition(expr->position());
1250 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1675 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1251 __ Call(ic, RelocInfo::CODE_TARGET); 1676 __ Call(ic, RelocInfo::CODE_TARGET);
1252 // This nop signals to the IC that there is no inlined code at the call 1677 // This nop signals to the IC that there is no inlined code at the call
1253 // site for it to patch. 1678 // site for it to patch.
1254 __ nop(); 1679 __ nop();
1255 1680
1256 // If the assignment ends an initialization block, revert to fast case. 1681 // If the assignment ends an initialization block, revert to fast case.
1257 if (expr->ends_initialization_block()) { 1682 if (expr->ends_initialization_block()) {
1683 __ pop(rdx);
1258 __ push(rax); // Result of assignment, saved even if not needed. 1684 __ push(rax); // Result of assignment, saved even if not needed.
1259 // Receiver is under the key and value. 1685 __ push(rdx);
1260 __ push(Operand(rsp, 2 * kPointerSize));
1261 __ CallRuntime(Runtime::kToFastProperties, 1); 1686 __ CallRuntime(Runtime::kToFastProperties, 1);
1262 __ pop(rax); 1687 __ pop(rax);
1263 } 1688 }
1264 1689
1265 // Receiver and key are still on stack. 1690 Apply(context_, rax);
1266 DropAndApply(2, context_, rax);
1267 } 1691 }
1268 1692
1269 1693
1270 void FullCodeGenerator::VisitProperty(Property* expr) { 1694 void FullCodeGenerator::VisitProperty(Property* expr) {
1271 Comment cmnt(masm_, "[ Property"); 1695 Comment cmnt(masm_, "[ Property");
1272 Expression* key = expr->key(); 1696 Expression* key = expr->key();
1273 1697
1274 // Evaluate receiver. 1698 // Evaluate receiver.
1275 VisitForValue(expr->obj(), kStack); 1699 VisitForValue(expr->obj(), kStack);
1276 1700
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1312 1736
1313 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1737 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1314 // Code common for calls using the call stub. 1738 // Code common for calls using the call stub.
1315 ZoneList<Expression*>* args = expr->arguments(); 1739 ZoneList<Expression*>* args = expr->arguments();
1316 int arg_count = args->length(); 1740 int arg_count = args->length();
1317 for (int i = 0; i < arg_count; i++) { 1741 for (int i = 0; i < arg_count; i++) {
1318 VisitForValue(args->at(i), kStack); 1742 VisitForValue(args->at(i), kStack);
1319 } 1743 }
1320 // Record source position for debugger. 1744 // Record source position for debugger.
1321 SetSourcePosition(expr->position()); 1745 SetSourcePosition(expr->position());
1322 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1746 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1747 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1323 __ CallStub(&stub); 1748 __ CallStub(&stub);
1324 // Restore context register. 1749 // Restore context register.
1325 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1750 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1326 // Discard the function left on TOS. 1751 // Discard the function left on TOS.
1327 DropAndApply(1, context_, rax); 1752 DropAndApply(1, context_, rax);
1328 } 1753 }
1329 1754
1330 1755
1331 void FullCodeGenerator::VisitCall(Call* expr) { 1756 void FullCodeGenerator::VisitCall(Call* expr) {
1332 Comment cmnt(masm_, "[ Call"); 1757 Comment cmnt(masm_, "[ Call");
1333 Expression* fun = expr->expression(); 1758 Expression* fun = expr->expression();
1334 Variable* var = fun->AsVariableProxy()->AsVariable(); 1759 Variable* var = fun->AsVariableProxy()->AsVariable();
1335 1760
1336 if (var != NULL && var->is_possibly_eval()) { 1761 if (var != NULL && var->is_possibly_eval()) {
1337 // Call to the identifier 'eval'. 1762 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1338 UNREACHABLE(); 1763 // resolve the function we need to call and the receiver of the
1764 // call. The we call the resolved function using the given
1765 // arguments.
1766 VisitForValue(fun, kStack);
1767 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
1768
1769 // Push the arguments.
1770 ZoneList<Expression*>* args = expr->arguments();
1771 int arg_count = args->length();
1772 for (int i = 0; i < arg_count; i++) {
1773 VisitForValue(args->at(i), kStack);
1774 }
1775
1776 // Push copy of the function - found below the arguments.
1777 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
1778
1779 // Push copy of the first argument or undefined if it doesn't exist.
1780 if (arg_count > 0) {
1781 __ push(Operand(rsp, arg_count * kPointerSize));
1782 } else {
1783 __ PushRoot(Heap::kUndefinedValueRootIndex);
1784 }
1785
1786 // Push the receiver of the enclosing function and do runtime call.
1787 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
1788 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1789
1790 // The runtime call returns a pair of values in rax (function) and
1791 // rdx (receiver). Touch up the stack with the right values.
1792 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
1793 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
1794
1795 // Record source position for debugger.
1796 SetSourcePosition(expr->position());
1797 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1798 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1799 __ CallStub(&stub);
1800 // Restore context register.
1801 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1802 DropAndApply(1, context_, rax);
1339 } else if (var != NULL && !var->is_this() && var->is_global()) { 1803 } else if (var != NULL && !var->is_this() && var->is_global()) {
1340 // Call to a global variable. 1804 // Call to a global variable.
1341 // Push global object as receiver for the call IC lookup. 1805 // Push global object as receiver for the call IC lookup.
1342 __ push(CodeGenerator::GlobalObject()); 1806 __ push(CodeGenerator::GlobalObject());
1343 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1807 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1344 } else if (var != NULL && var->slot() != NULL && 1808 } else if (var != NULL && var->slot() != NULL &&
1345 var->slot()->type() == Slot::LOOKUP) { 1809 var->slot()->type() == Slot::LOOKUP) {
1346 // Call to a lookup slot. 1810 // Call to a lookup slot (dynamically introduced variable). Call
1347 UNREACHABLE(); 1811 // the runtime to find the function to call (returned in rax) and
1812 // the object holding it (returned in rdx).
1813 __ push(context_register());
1814 __ Push(var->name());
1815 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1816 __ push(rax); // Function.
1817 __ push(rdx); // Receiver.
1818 EmitCallWithStub(expr);
1348 } else if (fun->AsProperty() != NULL) { 1819 } else if (fun->AsProperty() != NULL) {
1349 // Call to an object property. 1820 // Call to an object property.
1350 Property* prop = fun->AsProperty(); 1821 Property* prop = fun->AsProperty();
1351 Literal* key = prop->key()->AsLiteral(); 1822 Literal* key = prop->key()->AsLiteral();
1352 if (key != NULL && key->handle()->IsSymbol()) { 1823 if (key != NULL && key->handle()->IsSymbol()) {
1353 // Call to a named property, use call IC. 1824 // Call to a named property, use call IC.
1354 VisitForValue(prop->obj(), kStack); 1825 VisitForValue(prop->obj(), kStack);
1355 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1826 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1356 } else { 1827 } else {
1357 // Call to a keyed property, use keyed load IC followed by function 1828 // Call to a keyed property, use keyed load IC followed by function
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); 1899 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
1429 1900
1430 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1901 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1431 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1902 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1432 1903
1433 // Replace function on TOS with result in rax, or pop it. 1904 // Replace function on TOS with result in rax, or pop it.
1434 DropAndApply(1, context_, rax); 1905 DropAndApply(1, context_, rax);
1435 } 1906 }
1436 1907
1437 1908
1909 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
1910 Handle<String> name = expr->name();
1911 if (strcmp("_IsSmi", *name->ToCString()) == 0) {
1912 EmitIsSmi(expr->arguments());
1913 } else if (strcmp("_IsNonNegativeSmi", *name->ToCString()) == 0) {
1914 EmitIsNonNegativeSmi(expr->arguments());
1915 } else if (strcmp("_IsObject", *name->ToCString()) == 0) {
1916 EmitIsObject(expr->arguments());
1917 } else if (strcmp("_IsUndetectableObject", *name->ToCString()) == 0) {
1918 EmitIsUndetectableObject(expr->arguments());
1919 } else if (strcmp("_IsFunction", *name->ToCString()) == 0) {
1920 EmitIsFunction(expr->arguments());
1921 } else if (strcmp("_IsArray", *name->ToCString()) == 0) {
1922 EmitIsArray(expr->arguments());
1923 } else if (strcmp("_IsRegExp", *name->ToCString()) == 0) {
1924 EmitIsRegExp(expr->arguments());
1925 } else if (strcmp("_IsConstructCall", *name->ToCString()) == 0) {
1926 EmitIsConstructCall(expr->arguments());
1927 } else if (strcmp("_ObjectEquals", *name->ToCString()) == 0) {
1928 EmitObjectEquals(expr->arguments());
1929 } else if (strcmp("_Arguments", *name->ToCString()) == 0) {
1930 EmitArguments(expr->arguments());
1931 } else if (strcmp("_ArgumentsLength", *name->ToCString()) == 0) {
1932 EmitArgumentsLength(expr->arguments());
1933 } else if (strcmp("_ClassOf", *name->ToCString()) == 0) {
1934 EmitClassOf(expr->arguments());
1935 } else if (strcmp("_Log", *name->ToCString()) == 0) {
1936 EmitLog(expr->arguments());
1937 } else if (strcmp("_RandomHeapNumber", *name->ToCString()) == 0) {
1938 EmitRandomHeapNumber(expr->arguments());
1939 } else if (strcmp("_SubString", *name->ToCString()) == 0) {
1940 EmitSubString(expr->arguments());
1941 } else if (strcmp("_RegExpExec", *name->ToCString()) == 0) {
1942 EmitRegExpExec(expr->arguments());
1943 } else if (strcmp("_ValueOf", *name->ToCString()) == 0) {
1944 EmitValueOf(expr->arguments());
1945 } else if (strcmp("_SetValueOf", *name->ToCString()) == 0) {
1946 EmitSetValueOf(expr->arguments());
1947 } else if (strcmp("_NumberToString", *name->ToCString()) == 0) {
1948 EmitNumberToString(expr->arguments());
1949 } else if (strcmp("_CharFromCode", *name->ToCString()) == 0) {
1950 EmitCharFromCode(expr->arguments());
1951 } else if (strcmp("_FastCharCodeAt", *name->ToCString()) == 0) {
1952 EmitFastCharCodeAt(expr->arguments());
1953 } else if (strcmp("_StringAdd", *name->ToCString()) == 0) {
1954 EmitStringAdd(expr->arguments());
1955 } else if (strcmp("_StringCompare", *name->ToCString()) == 0) {
1956 EmitStringCompare(expr->arguments());
1957 } else if (strcmp("_MathPow", *name->ToCString()) == 0) {
1958 EmitMathPow(expr->arguments());
1959 } else if (strcmp("_MathSin", *name->ToCString()) == 0) {
1960 EmitMathSin(expr->arguments());
1961 } else if (strcmp("_MathCos", *name->ToCString()) == 0) {
1962 EmitMathCos(expr->arguments());
1963 } else if (strcmp("_MathSqrt", *name->ToCString()) == 0) {
1964 EmitMathSqrt(expr->arguments());
1965 } else if (strcmp("_CallFunction", *name->ToCString()) == 0) {
1966 EmitCallFunction(expr->arguments());
1967 } else if (strcmp("_RegExpConstructResult", *name->ToCString()) == 0) {
1968 EmitRegExpConstructResult(expr->arguments());
1969 } else if (strcmp("_SwapElements", *name->ToCString()) == 0) {
1970 EmitSwapElements(expr->arguments());
1971 } else if (strcmp("_GetFromCache", *name->ToCString()) == 0) {
1972 EmitGetFromCache(expr->arguments());
1973 } else {
1974 UNREACHABLE();
1975 }
1976 }
1977
1978
1979 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1980 ASSERT(args->length() == 1);
1981
1982 VisitForValue(args->at(0), kAccumulator);
1983
1984 Label materialize_true, materialize_false;
1985 Label* if_true = NULL;
1986 Label* if_false = NULL;
1987 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1988
1989 __ JumpIfSmi(rax, if_true);
1990 __ jmp(if_false);
1991
1992 Apply(context_, if_true, if_false);
1993 }
1994
1995
1996 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1997 ASSERT(args->length() == 1);
1998
1999 VisitForValue(args->at(0), kAccumulator);
2000
2001 Label materialize_true, materialize_false;
2002 Label* if_true = NULL;
2003 Label* if_false = NULL;
2004 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2005
2006 Condition positive_smi = __ CheckPositiveSmi(rax);
2007 __ j(positive_smi, if_true);
2008 __ jmp(if_false);
2009
2010 Apply(context_, if_true, if_false);
2011 }
2012
2013
2014 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2015 ASSERT(args->length() == 1);
2016
2017 VisitForValue(args->at(0), kAccumulator);
2018
2019 Label materialize_true, materialize_false;
2020 Label* if_true = NULL;
2021 Label* if_false = NULL;
2022 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2023
2024 __ JumpIfSmi(rax, if_false);
2025 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2026 __ j(equal, if_true);
2027 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2028 // Undetectable objects behave like undefined when tested with typeof.
2029 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2030 Immediate(1 << Map::kIsUndetectable));
2031 __ j(not_zero, if_false);
2032 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
2033 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
2034 __ j(below, if_false);
2035 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
2036 __ j(below_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 __ JumpIfSmi(rax, if_false);
2054 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2055 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2056 Immediate(1 << Map::kIsUndetectable));
2057 __ j(not_zero, if_true);
2058 __ jmp(if_false);
2059
2060 Apply(context_, if_true, if_false);
2061 }
2062
2063
2064 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2065 ASSERT(args->length() == 1);
2066
2067 VisitForValue(args->at(0), kAccumulator);
2068
2069 Label materialize_true, materialize_false;
2070 Label* if_true = NULL;
2071 Label* if_false = NULL;
2072 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2073
2074 __ JumpIfSmi(rax, if_false);
2075 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2076 __ j(equal, if_true);
2077 __ jmp(if_false);
2078
2079 Apply(context_, if_true, if_false);
2080 }
2081
2082
2083 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2084 ASSERT(args->length() == 1);
2085
2086 VisitForValue(args->at(0), kAccumulator);
2087
2088 Label materialize_true, materialize_false;
2089 Label* if_true = NULL;
2090 Label* if_false = NULL;
2091 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2092
2093 __ JumpIfSmi(rax, if_false);
2094 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2095 __ j(equal, if_true);
2096 __ jmp(if_false);
2097
2098 Apply(context_, if_true, if_false);
2099 }
2100
2101
2102 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2103 ASSERT(args->length() == 1);
2104
2105 VisitForValue(args->at(0), kAccumulator);
2106
2107 Label materialize_true, materialize_false;
2108 Label* if_true = NULL;
2109 Label* if_false = NULL;
2110 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2111
2112 __ JumpIfSmi(rax, if_false);
2113 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
2114 __ j(equal, if_true);
2115 __ jmp(if_false);
2116
2117 Apply(context_, if_true, if_false);
2118 }
2119
2120
2121
2122 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2123 ASSERT(args->length() == 0);
2124
2125 Label materialize_true, materialize_false;
2126 Label* if_true = NULL;
2127 Label* if_false = NULL;
2128 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2129
2130 // Get the frame pointer for the calling frame.
2131 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2132
2133 // Skip the arguments adaptor frame if it exists.
2134 Label check_frame_marker;
2135 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset),
2136 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2137 __ j(not_equal, &check_frame_marker);
2138 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2139
2140 // Check the marker in the calling frame.
2141 __ bind(&check_frame_marker);
2142 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
2143 Smi::FromInt(StackFrame::CONSTRUCT));
2144 __ j(equal, if_true);
2145 __ jmp(if_false);
2146
2147 Apply(context_, if_true, if_false);
2148 }
2149
2150
2151 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2152 ASSERT(args->length() == 2);
2153
2154 // Load the two objects into registers and perform the comparison.
2155 VisitForValue(args->at(0), kStack);
2156 VisitForValue(args->at(1), kAccumulator);
2157
2158 Label materialize_true, materialize_false;
2159 Label* if_true = NULL;
2160 Label* if_false = NULL;
2161 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2162
2163 __ pop(rbx);
2164 __ cmpq(rax, rbx);
2165 __ j(equal, if_true);
2166 __ jmp(if_false);
2167
2168 Apply(context_, if_true, if_false);
2169 }
2170
2171
2172 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2173 ASSERT(args->length() == 1);
2174
2175 // ArgumentsAccessStub expects the key in edx and the formal
2176 // parameter count in eax.
2177 VisitForValue(args->at(0), kAccumulator);
2178 __ movq(rdx, rax);
2179 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2180 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2181 __ CallStub(&stub);
2182 Apply(context_, rax);
2183 }
2184
2185
2186 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2187 ASSERT(args->length() == 0);
2188
2189 Label exit;
2190 // Get the number of formal parameters.
2191 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2192
2193 // Check if the calling frame is an arguments adaptor frame.
2194 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2195 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
2196 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2197 __ j(not_equal, &exit);
2198
2199 // Arguments adaptor case: Read the arguments length from the
2200 // adaptor frame.
2201 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2202
2203 __ bind(&exit);
2204 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
2205 Apply(context_, rax);
2206 }
2207
2208
2209 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2210 ASSERT(args->length() == 1);
2211 Label done, null, function, non_function_constructor;
2212
2213 VisitForValue(args->at(0), kAccumulator);
2214
2215 // If the object is a smi, we return null.
2216 __ JumpIfSmi(rax, &null);
2217
2218 // Check that the object is a JS object but take special care of JS
2219 // functions to make sure they have 'Function' as their class.
2220 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
2221 __ j(below, &null);
2222
2223 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2224 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2225 // LAST_JS_OBJECT_TYPE.
2226 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2227 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
2228 __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
2229 __ j(equal, &function);
2230
2231 // Check if the constructor in the map is a function.
2232 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2233 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2234 __ j(not_equal, &non_function_constructor);
2235
2236 // rax now contains the constructor function. Grab the
2237 // instance class name from there.
2238 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2239 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2240 __ jmp(&done);
2241
2242 // Functions have class 'Function'.
2243 __ bind(&function);
2244 __ Move(rax, Factory::function_class_symbol());
2245 __ jmp(&done);
2246
2247 // Objects with a non-function constructor have class 'Object'.
2248 __ bind(&non_function_constructor);
2249 __ Move(rax, Factory::Object_symbol());
2250 __ jmp(&done);
2251
2252 // Non-JS objects have class null.
2253 __ bind(&null);
2254 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2255
2256 // All done.
2257 __ bind(&done);
2258
2259 Apply(context_, rax);
2260 }
2261
2262
2263 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2264 // Conditionally generate a log call.
2265 // Args:
2266 // 0 (literal string): The type of logging (corresponds to the flags).
2267 // This is used to determine whether or not to generate the log call.
2268 // 1 (string): Format string. Access the string at argument index 2
2269 // with '%2s' (see Logger::LogRuntime for all the formats).
2270 // 2 (array): Arguments to the format string.
2271 ASSERT_EQ(args->length(), 3);
2272 #ifdef ENABLE_LOGGING_AND_PROFILING
2273 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2274 VisitForValue(args->at(1), kStack);
2275 VisitForValue(args->at(2), kStack);
2276 __ CallRuntime(Runtime::kLog, 2);
2277 }
2278 #endif
2279 // Finally, we're expected to leave a value on the top of the stack.
2280 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2281 Apply(context_, rax);
2282 }
2283
2284
2285 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2286 ASSERT(args->length() == 0);
2287
2288 Label slow_allocate_heapnumber;
2289 Label heapnumber_allocated;
2290
2291 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2292 __ jmp(&heapnumber_allocated);
2293
2294 __ bind(&slow_allocate_heapnumber);
2295 // To allocate a heap number, and ensure that it is not a smi, we
2296 // call the runtime function FUnaryMinus on 0, returning the double
2297 // -0.0. A new, distinct heap number is returned each time.
2298 __ Push(Smi::FromInt(0));
2299 __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
2300 __ movq(rbx, rax);
2301
2302 __ bind(&heapnumber_allocated);
2303
2304 // Return a random uint32 number in rax.
2305 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
2306 __ PrepareCallCFunction(0);
2307 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2308
2309 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2310 // by computing:
2311 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2312 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2313 __ movd(xmm1, rcx);
2314 __ movd(xmm0, rax);
2315 __ cvtss2sd(xmm1, xmm1);
2316 __ xorpd(xmm0, xmm1);
2317 __ subsd(xmm0, xmm1);
2318 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2319
2320 __ movq(rax, rbx);
2321 Apply(context_, rax);
2322 }
2323
2324
2325 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2326 // Load the arguments on the stack and call the stub.
2327 SubStringStub stub;
2328 ASSERT(args->length() == 3);
2329 VisitForValue(args->at(0), kStack);
2330 VisitForValue(args->at(1), kStack);
2331 VisitForValue(args->at(2), kStack);
2332 __ CallStub(&stub);
2333 Apply(context_, rax);
2334 }
2335
2336
2337 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2338 // Load the arguments on the stack and call the stub.
2339 RegExpExecStub stub;
2340 ASSERT(args->length() == 4);
2341 VisitForValue(args->at(0), kStack);
2342 VisitForValue(args->at(1), kStack);
2343 VisitForValue(args->at(2), kStack);
2344 VisitForValue(args->at(3), kStack);
2345 __ CallStub(&stub);
2346 Apply(context_, rax);
2347 }
2348
2349
2350 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2351 ASSERT(args->length() == 1);
2352
2353 VisitForValue(args->at(0), kAccumulator); // Load the object.
2354
2355 Label done;
2356 // If the object is a smi return the object.
2357 __ JumpIfSmi(rax, &done);
2358 // If the object is not a value type, return the object.
2359 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2360 __ j(not_equal, &done);
2361 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2362
2363 __ bind(&done);
2364 Apply(context_, rax);
2365 }
2366
2367
2368 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2369 // Load the arguments on the stack and call the runtime function.
2370 ASSERT(args->length() == 2);
2371 VisitForValue(args->at(0), kStack);
2372 VisitForValue(args->at(1), kStack);
2373 __ CallRuntime(Runtime::kMath_pow, 2);
2374 Apply(context_, rax);
2375 }
2376
2377
2378 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2379 ASSERT(args->length() == 2);
2380
2381 VisitForValue(args->at(0), kStack); // Load the object.
2382 VisitForValue(args->at(1), kAccumulator); // Load the value.
2383 __ pop(rbx); // rax = value. ebx = object.
2384
2385 Label done;
2386 // If the object is a smi, return the value.
2387 __ JumpIfSmi(rbx, &done);
2388
2389 // If the object is not a value type, return the value.
2390 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2391 __ j(not_equal, &done);
2392
2393 // Store the value.
2394 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2395 // Update the write barrier. Save the value as it will be
2396 // overwritten by the write barrier code and is needed afterward.
2397 __ movq(rdx, rax);
2398 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
2399
2400 __ bind(&done);
2401 Apply(context_, rax);
2402 }
2403
2404
2405 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2406 ASSERT_EQ(args->length(), 1);
2407
2408 // Load the argument on the stack and call the stub.
2409 VisitForValue(args->at(0), kStack);
2410
2411 NumberToStringStub stub;
2412 __ CallStub(&stub);
2413 Apply(context_, rax);
2414 }
2415
2416
2417 void FullCodeGenerator::EmitCharFromCode(ZoneList<Expression*>* args) {
2418 ASSERT(args->length() == 1);
2419
2420 VisitForValue(args->at(0), kAccumulator);
2421
2422 Label slow_case, done;
2423 // Fast case of Heap::LookupSingleCharacterStringFromCode.
2424 __ JumpIfNotSmi(rax, &slow_case);
2425 __ SmiToInteger32(rcx, rax);
2426 __ cmpl(rcx, Immediate(String::kMaxAsciiCharCode));
2427 __ j(above, &slow_case);
2428
2429 __ Move(rbx, Factory::single_character_string_cache());
2430 __ movq(rbx, FieldOperand(rbx,
2431 rcx,
2432 times_pointer_size,
2433 FixedArray::kHeaderSize));
2434
2435 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
2436 __ j(equal, &slow_case);
2437 __ movq(rax, rbx);
2438 __ jmp(&done);
2439
2440 __ bind(&slow_case);
2441 __ push(rax);
2442 __ CallRuntime(Runtime::kCharFromCode, 1);
2443
2444 __ bind(&done);
2445 Apply(context_, rax);
2446 }
2447
2448
2449 void FullCodeGenerator::EmitFastCharCodeAt(ZoneList<Expression*>* args) {
2450 // TODO(fsc): Port the complete implementation from the classic back-end.
2451 // Move the undefined value into the result register, which will
2452 // trigger the slow case.
2453 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2454 Apply(context_, rax);
2455 }
2456
2457 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2458 ASSERT_EQ(2, args->length());
2459
2460 VisitForValue(args->at(0), kStack);
2461 VisitForValue(args->at(1), kStack);
2462
2463 StringAddStub stub(NO_STRING_ADD_FLAGS);
2464 __ CallStub(&stub);
2465 Apply(context_, rax);
2466 }
2467
2468
2469 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2470 ASSERT_EQ(2, args->length());
2471
2472 VisitForValue(args->at(0), kStack);
2473 VisitForValue(args->at(1), kStack);
2474
2475 StringCompareStub stub;
2476 __ CallStub(&stub);
2477 Apply(context_, rax);
2478 }
2479
2480
2481 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2482 // Load the argument on the stack and call the stub.
2483 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2484 ASSERT(args->length() == 1);
2485 VisitForValue(args->at(0), kStack);
2486 __ CallStub(&stub);
2487 Apply(context_, rax);
2488 }
2489
2490
2491 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2492 // Load the argument on the stack and call the stub.
2493 TranscendentalCacheStub stub(TranscendentalCache::COS);
2494 ASSERT(args->length() == 1);
2495 VisitForValue(args->at(0), kStack);
2496 __ CallStub(&stub);
2497 Apply(context_, rax);
2498 }
2499
2500
2501 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2502 // Load the argument on the stack and call the runtime function.
2503 ASSERT(args->length() == 1);
2504 VisitForValue(args->at(0), kStack);
2505 __ CallRuntime(Runtime::kMath_sqrt, 1);
2506 Apply(context_, rax);
2507 }
2508
2509
2510 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2511 ASSERT(args->length() >= 2);
2512
2513 int arg_count = args->length() - 2; // For receiver and function.
2514 VisitForValue(args->at(0), kStack); // Receiver.
2515 for (int i = 0; i < arg_count; i++) {
2516 VisitForValue(args->at(i + 1), kStack);
2517 }
2518 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2519
2520 // InvokeFunction requires function in rdi. Move it in there.
2521 if (!result_register().is(rdi)) __ movq(rdi, result_register());
2522 ParameterCount count(arg_count);
2523 __ InvokeFunction(rdi, count, CALL_FUNCTION);
2524 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2525 Apply(context_, rax);
2526 }
2527
2528
2529 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2530 ASSERT(args->length() == 3);
2531 VisitForValue(args->at(0), kStack);
2532 VisitForValue(args->at(1), kStack);
2533 VisitForValue(args->at(2), kStack);
2534 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2535 Apply(context_, rax);
2536 }
2537
2538
2539 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2540 ASSERT(args->length() == 3);
2541 VisitForValue(args->at(0), kStack);
2542 VisitForValue(args->at(1), kStack);
2543 VisitForValue(args->at(2), kStack);
2544 __ CallRuntime(Runtime::kSwapElements, 3);
2545 Apply(context_, rax);
2546 }
2547
2548
2549 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2550 ASSERT_EQ(2, args->length());
2551
2552 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2553 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2554
2555 Handle<FixedArray> jsfunction_result_caches(
2556 Top::global_context()->jsfunction_result_caches());
2557 if (jsfunction_result_caches->length() <= cache_id) {
2558 __ Abort("Attempt to use undefined cache.");
2559 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2560 Apply(context_, rax);
2561 return;
2562 }
2563
2564 VisitForValue(args->at(1), kAccumulator);
2565
2566 Register key = rax;
2567 Register cache = rbx;
2568 Register tmp = rcx;
2569 __ movq(cache, CodeGenerator::ContextOperand(rsi, Context::GLOBAL_INDEX));
2570 __ movq(cache,
2571 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
2572 __ movq(cache,
2573 CodeGenerator::ContextOperand(
2574 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2575 __ movq(cache,
2576 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2577
2578 Label done, not_found;
2579 // tmp now holds finger offset as a smi.
2580 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2581 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
2582 SmiIndex index =
2583 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
2584 __ cmpq(key, FieldOperand(cache,
2585 index.reg,
2586 index.scale,
2587 FixedArray::kHeaderSize));
2588 __ j(not_equal, &not_found);
2589 __ movq(rax, FieldOperand(cache,
2590 index.reg,
2591 index.scale,
2592 FixedArray::kHeaderSize + kPointerSize));
2593 __ jmp(&done);
2594
2595 __ bind(&not_found);
2596 // Call runtime to perform the lookup.
2597 __ push(cache);
2598 __ push(key);
2599 __ CallRuntime(Runtime::kGetFromCache, 2);
2600
2601 __ bind(&done);
2602 Apply(context_, rax);
2603 }
2604
2605
1438 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2606 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2607 Handle<String> name = expr->name();
2608 if (name->length() > 0 && name->Get(0) == '_') {
2609 Comment cmnt(masm_, "[ InlineRuntimeCall");
2610 EmitInlineRuntimeCall(expr);
2611 return;
2612 }
2613
1439 Comment cmnt(masm_, "[ CallRuntime"); 2614 Comment cmnt(masm_, "[ CallRuntime");
1440 ZoneList<Expression*>* args = expr->arguments(); 2615 ZoneList<Expression*>* args = expr->arguments();
1441 2616
1442 if (expr->is_jsruntime()) { 2617 if (expr->is_jsruntime()) {
1443 // Prepare for calling JS runtime function. 2618 // Prepare for calling JS runtime function.
1444 __ movq(rax, CodeGenerator::GlobalObject()); 2619 __ movq(rax, CodeGenerator::GlobalObject());
1445 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); 2620 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
1446 } 2621 }
1447 2622
1448 // Push the arguments ("left-to-right"). 2623 // Push the arguments ("left-to-right").
(...skipping 12 matching lines...) Expand all
1461 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2636 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1462 } else { 2637 } else {
1463 __ CallRuntime(expr->function(), arg_count); 2638 __ CallRuntime(expr->function(), arg_count);
1464 } 2639 }
1465 Apply(context_, rax); 2640 Apply(context_, rax);
1466 } 2641 }
1467 2642
1468 2643
1469 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 2644 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1470 switch (expr->op()) { 2645 switch (expr->op()) {
2646 case Token::DELETE: {
2647 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2648 Property* prop = expr->expression()->AsProperty();
2649 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2650 if (prop == NULL && var == NULL) {
2651 // Result of deleting non-property, non-variable reference is true.
2652 // The subexpression may have side effects.
2653 VisitForEffect(expr->expression());
2654 Apply(context_, true);
2655 } else if (var != NULL &&
2656 !var->is_global() &&
2657 var->slot() != NULL &&
2658 var->slot()->type() != Slot::LOOKUP) {
2659 // Result of deleting non-global, non-dynamic variables is false.
2660 // The subexpression does not have side effects.
2661 Apply(context_, false);
2662 } else {
2663 // Property or variable reference. Call the delete builtin with
2664 // object and property name as arguments.
2665 if (prop != NULL) {
2666 VisitForValue(prop->obj(), kStack);
2667 VisitForValue(prop->key(), kStack);
2668 } else if (var->is_global()) {
2669 __ push(CodeGenerator::GlobalObject());
2670 __ Push(var->name());
2671 } else {
2672 // Non-global variable. Call the runtime to look up the context
2673 // where the variable was introduced.
2674 __ push(context_register());
2675 __ Push(var->name());
2676 __ CallRuntime(Runtime::kLookupContext, 2);
2677 __ push(rax);
2678 __ Push(var->name());
2679 }
2680 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
2681 Apply(context_, rax);
2682 }
2683 break;
2684 }
2685
1471 case Token::VOID: { 2686 case Token::VOID: {
1472 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 2687 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1473 VisitForEffect(expr->expression()); 2688 VisitForEffect(expr->expression());
1474 switch (context_) { 2689 switch (context_) {
1475 case Expression::kUninitialized: 2690 case Expression::kUninitialized:
1476 UNREACHABLE(); 2691 UNREACHABLE();
1477 break; 2692 break;
1478 case Expression::kEffect: 2693 case Expression::kEffect:
1479 break; 2694 break;
1480 case Expression::kValue: 2695 case Expression::kValue:
(...skipping 20 matching lines...) Expand all
1501 case Expression::kTest: 2716 case Expression::kTest:
1502 case Expression::kValueTest: 2717 case Expression::kValueTest:
1503 __ jmp(false_label_); 2718 __ jmp(false_label_);
1504 break; 2719 break;
1505 } 2720 }
1506 break; 2721 break;
1507 } 2722 }
1508 2723
1509 case Token::NOT: { 2724 case Token::NOT: {
1510 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 2725 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1511 Label materialize_true, materialize_false, done; 2726 Label materialize_true, materialize_false;
1512 // Initially assume a pure test context. Notice that the labels are 2727 Label* if_true = NULL;
1513 // swapped. 2728 Label* if_false = NULL;
1514 Label* if_true = false_label_; 2729
1515 Label* if_false = true_label_; 2730 // Notice that the labels are swapped.
1516 switch (context_) { 2731 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
1517 case Expression::kUninitialized: 2732
1518 UNREACHABLE();
1519 break;
1520 case Expression::kEffect:
1521 if_true = &done;
1522 if_false = &done;
1523 break;
1524 case Expression::kValue:
1525 if_true = &materialize_false;
1526 if_false = &materialize_true;
1527 break;
1528 case Expression::kTest:
1529 break;
1530 case Expression::kValueTest:
1531 if_false = &materialize_true;
1532 break;
1533 case Expression::kTestValue:
1534 if_true = &materialize_false;
1535 break;
1536 }
1537 VisitForControl(expr->expression(), if_true, if_false); 2733 VisitForControl(expr->expression(), if_true, if_false);
2734
1538 Apply(context_, if_false, if_true); // Labels swapped. 2735 Apply(context_, if_false, if_true); // Labels swapped.
1539 break; 2736 break;
1540 } 2737 }
1541 2738
1542 case Token::TYPEOF: { 2739 case Token::TYPEOF: {
1543 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 2740 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1544 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2741 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1545 if (proxy != NULL && 2742 if (proxy != NULL &&
1546 !proxy->var()->is_this() && 2743 !proxy->var()->is_this() &&
1547 proxy->var()->is_global()) { 2744 proxy->var()->is_global()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1623 2820
1624 default: 2821 default:
1625 UNREACHABLE(); 2822 UNREACHABLE();
1626 } 2823 }
1627 } 2824 }
1628 2825
1629 2826
1630 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 2827 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
1631 Comment cmnt(masm_, "[ CountOperation"); 2828 Comment cmnt(masm_, "[ CountOperation");
1632 2829
2830 // Invalid left-hand-sides are rewritten to have a 'throw
2831 // ReferenceError' as the left-hand side.
2832 if (!expr->expression()->IsValidLeftHandSide()) {
2833 VisitForEffect(expr->expression());
2834 return;
2835 }
2836
1633 // Expression can only be a property, a global or a (parameter or local) 2837 // Expression can only be a property, a global or a (parameter or local)
1634 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 2838 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1635 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 2839 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1636 LhsKind assign_type = VARIABLE; 2840 LhsKind assign_type = VARIABLE;
1637 Property* prop = expr->expression()->AsProperty(); 2841 Property* prop = expr->expression()->AsProperty();
1638 // In case of a property we use the uninitialized expression context 2842 // In case of a property we use the uninitialized expression context
1639 // of the key to detect a named property. 2843 // of the key to detect a named property.
1640 if (prop != NULL) { 2844 if (prop != NULL) {
1641 assign_type = 2845 assign_type =
1642 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 2846 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1643 } 2847 }
1644 2848
1645 // Evaluate expression and get value. 2849 // Evaluate expression and get value.
1646 if (assign_type == VARIABLE) { 2850 if (assign_type == VARIABLE) {
1647 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 2851 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1648 Location saved_location = location_; 2852 Location saved_location = location_;
1649 location_ = kAccumulator; 2853 location_ = kAccumulator;
1650 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 2854 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1651 Expression::kValue); 2855 Expression::kValue);
1652 location_ = saved_location; 2856 location_ = saved_location;
1653 } else { 2857 } else {
1654 // Reserve space for result of postfix operation. 2858 // Reserve space for result of postfix operation.
1655 if (expr->is_postfix() && context_ != Expression::kEffect) { 2859 if (expr->is_postfix() && context_ != Expression::kEffect) {
1656 __ Push(Smi::FromInt(0)); 2860 __ Push(Smi::FromInt(0));
1657 } 2861 }
1658 VisitForValue(prop->obj(), kStack); 2862 VisitForValue(prop->obj(), kStack);
1659 if (assign_type == NAMED_PROPERTY) { 2863 if (assign_type == NAMED_PROPERTY) {
1660 EmitNamedPropertyLoad(prop); 2864 EmitNamedPropertyLoad(prop);
1661 } else { 2865 } else {
1662 VisitForValue(prop->key(), kStack); 2866 VisitForValue(prop->key(), kStack);
1663 EmitKeyedPropertyLoad(prop); 2867 EmitKeyedPropertyLoad(prop);
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 GenericBinaryOpStub stub(expr->binary_op(), 2932 GenericBinaryOpStub stub(expr->binary_op(),
1729 NO_OVERWRITE, 2933 NO_OVERWRITE,
1730 NO_GENERIC_BINARY_FLAGS); 2934 NO_GENERIC_BINARY_FLAGS);
1731 stub.GenerateCall(masm_, rax, Smi::FromInt(1)); 2935 stub.GenerateCall(masm_, rax, Smi::FromInt(1));
1732 __ bind(&done); 2936 __ bind(&done);
1733 2937
1734 // Store the value returned in rax. 2938 // Store the value returned in rax.
1735 switch (assign_type) { 2939 switch (assign_type) {
1736 case VARIABLE: 2940 case VARIABLE:
1737 if (expr->is_postfix()) { 2941 if (expr->is_postfix()) {
2942 // Perform the assignment as if via '='.
1738 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 2943 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2944 Token::ASSIGN,
1739 Expression::kEffect); 2945 Expression::kEffect);
1740 // For all contexts except kEffect: We have the result on 2946 // For all contexts except kEffect: We have the result on
1741 // top of the stack. 2947 // top of the stack.
1742 if (context_ != Expression::kEffect) { 2948 if (context_ != Expression::kEffect) {
1743 ApplyTOS(context_); 2949 ApplyTOS(context_);
1744 } 2950 }
1745 } else { 2951 } else {
2952 // Perform the assignment as if via '='.
1746 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 2953 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2954 Token::ASSIGN,
1747 context_); 2955 context_);
1748 } 2956 }
1749 break; 2957 break;
1750 case NAMED_PROPERTY: { 2958 case NAMED_PROPERTY: {
1751 __ Move(rcx, prop->key()->AsLiteral()->handle()); 2959 __ Move(rcx, prop->key()->AsLiteral()->handle());
1752 __ pop(rdx); 2960 __ pop(rdx);
1753 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 2961 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1754 __ call(ic, RelocInfo::CODE_TARGET); 2962 __ call(ic, RelocInfo::CODE_TARGET);
1755 // This nop signals to the IC that there is no inlined code at the call 2963 // This nop signals to the IC that there is no inlined code at the call
1756 // site for it to patch. 2964 // site for it to patch.
1757 __ nop(); 2965 __ nop();
1758 if (expr->is_postfix()) { 2966 if (expr->is_postfix()) {
1759 if (context_ != Expression::kEffect) { 2967 if (context_ != Expression::kEffect) {
1760 ApplyTOS(context_); 2968 ApplyTOS(context_);
1761 } 2969 }
1762 } else { 2970 } else {
1763 Apply(context_, rax); 2971 Apply(context_, rax);
1764 } 2972 }
1765 break; 2973 break;
1766 } 2974 }
1767 case KEYED_PROPERTY: { 2975 case KEYED_PROPERTY: {
2976 __ pop(rcx);
2977 __ pop(rdx);
1768 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 2978 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1769 __ call(ic, RelocInfo::CODE_TARGET); 2979 __ call(ic, RelocInfo::CODE_TARGET);
1770 // This nop signals to the IC that there is no inlined code at the call 2980 // This nop signals to the IC that there is no inlined code at the call
1771 // site for it to patch. 2981 // site for it to patch.
1772 __ nop(); 2982 __ nop();
1773 if (expr->is_postfix()) { 2983 if (expr->is_postfix()) {
1774 __ Drop(2); // Result is on the stack under the key and the receiver.
1775 if (context_ != Expression::kEffect) { 2984 if (context_ != Expression::kEffect) {
1776 ApplyTOS(context_); 2985 ApplyTOS(context_);
1777 } 2986 }
1778 } else { 2987 } else {
1779 DropAndApply(2, context_, rax); 2988 Apply(context_, rax);
1780 } 2989 }
1781 break; 2990 break;
1782 } 2991 }
1783 } 2992 }
1784 } 2993 }
1785 2994
1786 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { 2995 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
1787 Comment cmnt(masm_, "[ BinaryOperation"); 2996 Comment cmnt(masm_, "[ BinaryOperation");
1788 switch (expr->op()) { 2997 switch (expr->op()) {
1789 case Token::COMMA: 2998 case Token::COMMA:
(...skipping 21 matching lines...) Expand all
1811 VisitForValue(expr->right(), kAccumulator); 3020 VisitForValue(expr->right(), kAccumulator);
1812 EmitBinaryOp(expr->op(), context_); 3021 EmitBinaryOp(expr->op(), context_);
1813 break; 3022 break;
1814 3023
1815 default: 3024 default:
1816 UNREACHABLE(); 3025 UNREACHABLE();
1817 } 3026 }
1818 } 3027 }
1819 3028
1820 3029
3030 void FullCodeGenerator::EmitNullCompare(bool strict,
3031 Register obj,
3032 Register null_const,
3033 Label* if_true,
3034 Label* if_false,
3035 Register scratch) {
3036 __ cmpq(obj, null_const);
3037 if (strict) {
3038 __ j(equal, if_true);
3039 } else {
3040 __ j(equal, if_true);
3041 __ CompareRoot(obj, Heap::kUndefinedValueRootIndex);
3042 __ j(equal, if_true);
3043 __ JumpIfSmi(obj, if_false);
3044 // It can be an undetectable object.
3045 __ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset));
3046 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
3047 Immediate(1 << Map::kIsUndetectable));
3048 __ j(not_zero, if_true);
3049 }
3050 __ jmp(if_false);
3051 }
3052
3053
1821 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 3054 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1822 Comment cmnt(masm_, "[ CompareOperation"); 3055 Comment cmnt(masm_, "[ CompareOperation");
1823 3056
1824 // Always perform the comparison for its control flow. Pack the result 3057 // Always perform the comparison for its control flow. Pack the result
1825 // into the expression's context after the comparison is performed. 3058 // into the expression's context after the comparison is performed.
1826 Label materialize_true, materialize_false, done; 3059 Label materialize_true, materialize_false;
1827 // Initially assume we are in a test context. 3060 Label* if_true = NULL;
1828 Label* if_true = true_label_; 3061 Label* if_false = NULL;
1829 Label* if_false = false_label_; 3062 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1830 switch (context_) {
1831 case Expression::kUninitialized:
1832 UNREACHABLE();
1833 break;
1834 case Expression::kEffect:
1835 if_true = &done;
1836 if_false = &done;
1837 break;
1838 case Expression::kValue:
1839 if_true = &materialize_true;
1840 if_false = &materialize_false;
1841 break;
1842 case Expression::kTest:
1843 break;
1844 case Expression::kValueTest:
1845 if_true = &materialize_true;
1846 break;
1847 case Expression::kTestValue:
1848 if_false = &materialize_false;
1849 break;
1850 }
1851 3063
1852 VisitForValue(expr->left(), kStack); 3064 VisitForValue(expr->left(), kStack);
1853 switch (expr->op()) { 3065 switch (expr->op()) {
1854 case Token::IN: 3066 case Token::IN:
1855 VisitForValue(expr->right(), kStack); 3067 VisitForValue(expr->right(), kStack);
1856 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 3068 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1857 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 3069 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
1858 __ j(equal, if_true); 3070 __ j(equal, if_true);
1859 __ jmp(if_false); 3071 __ jmp(if_false);
1860 break; 3072 break;
1861 3073
1862 case Token::INSTANCEOF: { 3074 case Token::INSTANCEOF: {
1863 VisitForValue(expr->right(), kStack); 3075 VisitForValue(expr->right(), kStack);
1864 InstanceofStub stub; 3076 InstanceofStub stub;
1865 __ CallStub(&stub); 3077 __ CallStub(&stub);
1866 __ testq(rax, rax); 3078 __ testq(rax, rax);
1867 __ j(zero, if_true); // The stub returns 0 for true. 3079 __ j(zero, if_true); // The stub returns 0 for true.
1868 __ jmp(if_false); 3080 __ jmp(if_false);
1869 break; 3081 break;
1870 } 3082 }
1871 3083
1872 default: { 3084 default: {
1873 VisitForValue(expr->right(), kAccumulator); 3085 VisitForValue(expr->right(), kAccumulator);
1874 Condition cc = no_condition; 3086 Condition cc = no_condition;
1875 bool strict = false; 3087 bool strict = false;
1876 switch (expr->op()) { 3088 switch (expr->op()) {
1877 case Token::EQ_STRICT: 3089 case Token::EQ_STRICT:
1878 strict = true; 3090 strict = true;
1879 // Fall through. 3091 // Fall through.
1880 case Token::EQ: 3092 case Token::EQ: {
1881 cc = equal; 3093 cc = equal;
1882 __ pop(rdx); 3094 __ pop(rdx);
3095 // If either operand is constant null we do a fast compare
3096 // against null.
3097 Literal* right_literal = expr->right()->AsLiteral();
3098 Literal* left_literal = expr->left()->AsLiteral();
3099 if (right_literal != NULL && right_literal->handle()->IsNull()) {
3100 EmitNullCompare(strict, rdx, rax, if_true, if_false, rcx);
3101 Apply(context_, if_true, if_false);
3102 return;
3103 } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3104 EmitNullCompare(strict, rax, rdx, if_true, if_false, rcx);
3105 Apply(context_, if_true, if_false);
3106 return;
3107 }
1883 break; 3108 break;
3109 }
1884 case Token::LT: 3110 case Token::LT:
1885 cc = less; 3111 cc = less;
1886 __ pop(rdx); 3112 __ pop(rdx);
1887 break; 3113 break;
1888 case Token::GT: 3114 case Token::GT:
1889 // Reverse left and right sizes to obtain ECMA-262 conversion order. 3115 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1890 cc = less; 3116 cc = less;
1891 __ movq(rdx, result_register()); 3117 __ movq(rdx, result_register());
1892 __ pop(rax); 3118 __ pop(rax);
1893 break; 3119 break;
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
1984 __ movq(Operand(rsp, 0), rdx); 3210 __ movq(Operand(rsp, 0), rdx);
1985 // And return. 3211 // And return.
1986 __ ret(0); 3212 __ ret(0);
1987 } 3213 }
1988 3214
1989 3215
1990 #undef __ 3216 #undef __
1991 3217
1992 3218
1993 } } // namespace v8::internal 3219 } } // namespace v8::internal
3220
3221 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/frames-x64.cc ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698