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

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

Issue 2071020: Reverting r4685, r4686, r4687 (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
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/codegen-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
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); 74 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
75 for (int i = 0; i < locals_count; i++) { 75 for (int i = 0; i < locals_count; i++) {
76 __ push(rdx); 76 __ push(rdx);
77 } 77 }
78 } 78 }
79 } 79 }
80 80
81 bool function_in_register = true; 81 bool function_in_register = true;
82 82
83 // Possibly allocate a local context. 83 // Possibly allocate a local context.
84 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 84 if (scope()->num_heap_slots() > 0) {
85 if (heap_slots > 0) {
86 Comment cmnt(masm_, "[ Allocate local context"); 85 Comment cmnt(masm_, "[ Allocate local context");
87 // Argument to NewContext is the function, which is still in rdi. 86 // Argument to NewContext is the function, which is still in rdi.
88 __ push(rdi); 87 __ push(rdi);
89 if (heap_slots <= FastNewContextStub::kMaximumSlots) { 88 __ CallRuntime(Runtime::kNewContext, 1);
90 FastNewContextStub stub(heap_slots);
91 __ CallStub(&stub);
92 } else {
93 __ CallRuntime(Runtime::kNewContext, 1);
94 }
95 function_in_register = false; 89 function_in_register = false;
96 // Context is returned in both rax and rsi. It replaces the context 90 // Context is returned in both rax and rsi. It replaces the context
97 // passed to us. It's saved in the stack and kept live in rsi. 91 // passed to us. It's saved in the stack and kept live in rsi.
98 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); 92 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
99 93
100 // Copy any necessary parameters into the context. 94 // Copy any necessary parameters into the context.
101 int num_parameters = scope()->num_parameters(); 95 int num_parameters = scope()->num_parameters();
102 for (int i = 0; i < num_parameters; i++) { 96 for (int i = 0; i < num_parameters; i++) {
103 Slot* slot = scope()->parameter(i)->slot(); 97 Slot* slot = scope()->parameter(i)->slot();
104 if (slot != NULL && slot->type() == Slot::CONTEXT) { 98 if (slot != NULL && slot->type() == Slot::CONTEXT) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 // Store new arguments object in both "arguments" and ".arguments" slots. 138 // Store new arguments object in both "arguments" and ".arguments" slots.
145 __ movq(rcx, rax); 139 __ movq(rcx, rax);
146 Move(arguments->slot(), rax, rbx, rdx); 140 Move(arguments->slot(), rax, rbx, rdx);
147 Slot* dot_arguments_slot = 141 Slot* dot_arguments_slot =
148 scope()->arguments_shadow()->AsVariable()->slot(); 142 scope()->arguments_shadow()->AsVariable()->slot();
149 Move(dot_arguments_slot, rcx, rbx, rdx); 143 Move(dot_arguments_slot, rcx, rbx, rdx);
150 } 144 }
151 } 145 }
152 146
153 { Comment cmnt(masm_, "[ Declarations"); 147 { Comment cmnt(masm_, "[ Declarations");
154 // For named function expressions, declare the function name as a 148 VisitDeclarations(scope()->declarations());
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 }
166 } 149 }
167 150
168 { Comment cmnt(masm_, "[ Stack check"); 151 { Comment cmnt(masm_, "[ Stack check");
169 Label ok; 152 Label ok;
170 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 153 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
171 __ j(above_equal, &ok); 154 __ j(above_equal, &ok);
172 StackCheckStub stub; 155 StackCheckStub stub;
173 __ CallStub(&stub); 156 __ CallStub(&stub);
174 __ bind(&ok); 157 __ bind(&ok);
175 } 158 }
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
439 __ movq(result_register(), reg); 422 __ movq(result_register(), reg);
440 __ movq(Operand(rsp, 0), result_register()); 423 __ movq(Operand(rsp, 0), result_register());
441 break; 424 break;
442 } 425 }
443 DoTest(context); 426 DoTest(context);
444 break; 427 break;
445 } 428 }
446 } 429 }
447 430
448 431
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
482 void FullCodeGenerator::Apply(Expression::Context context, 432 void FullCodeGenerator::Apply(Expression::Context context,
483 Label* materialize_true, 433 Label* materialize_true,
484 Label* materialize_false) { 434 Label* materialize_false) {
485 switch (context) { 435 switch (context) {
486 case Expression::kUninitialized: 436 case Expression::kUninitialized:
487 437
488 case Expression::kEffect: 438 case Expression::kEffect:
489 ASSERT_EQ(materialize_true, materialize_false); 439 ASSERT_EQ(materialize_true, materialize_false);
490 __ bind(materialize_true); 440 __ bind(materialize_true);
491 break; 441 break;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 case kStack: 487 case kStack:
538 __ Push(Factory::false_value()); 488 __ Push(Factory::false_value());
539 break; 489 break;
540 } 490 }
541 __ jmp(false_label_); 491 __ jmp(false_label_);
542 break; 492 break;
543 } 493 }
544 } 494 }
545 495
546 496
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
602 void FullCodeGenerator::DoTest(Expression::Context context) { 497 void FullCodeGenerator::DoTest(Expression::Context context) {
603 // The value to test is in the accumulator. If the value might be needed 498 // The value to test is in the accumulator. If the value might be needed
604 // on the stack (value/test and test/value contexts with a stack location 499 // on the stack (value/test and test/value contexts with a stack location
605 // desired), then the value is already duplicated on the stack. 500 // desired), then the value is already duplicated on the stack.
606 ASSERT_NE(NULL, true_label_); 501 ASSERT_NE(NULL, true_label_);
607 ASSERT_NE(NULL, false_label_); 502 ASSERT_NE(NULL, false_label_);
608 503
609 // In value/test and test/value expression contexts with stack as the 504 // In value/test and test/value expression contexts with stack as the
610 // desired location, there is already an extra value on the stack. Use a 505 // desired location, there is already an extra value on the stack. Use a
611 // label to discard it if unneeded. 506 // label to discard it if unneeded.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
767 MemOperand location = EmitSlotSearch(dst, scratch1); 662 MemOperand location = EmitSlotSearch(dst, scratch1);
768 __ movq(location, src); 663 __ movq(location, src);
769 // Emit the write barrier code if the location is in the heap. 664 // Emit the write barrier code if the location is in the heap.
770 if (dst->type() == Slot::CONTEXT) { 665 if (dst->type() == Slot::CONTEXT) {
771 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 666 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
772 __ RecordWrite(scratch1, offset, src, scratch2); 667 __ RecordWrite(scratch1, offset, src, scratch2);
773 } 668 }
774 } 669 }
775 670
776 671
777 void FullCodeGenerator::EmitDeclaration(Variable* variable, 672 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
778 Variable::Mode mode,
779 FunctionLiteral* function) {
780 Comment cmnt(masm_, "[ Declaration"); 673 Comment cmnt(masm_, "[ Declaration");
781 ASSERT(variable != NULL); // Must have been resolved. 674 Variable* var = decl->proxy()->var();
782 Slot* slot = variable->slot(); 675 ASSERT(var != NULL); // Must have been resolved.
783 Property* prop = variable->AsProperty(); 676 Slot* slot = var->slot();
677 Property* prop = var->AsProperty();
784 678
785 if (slot != NULL) { 679 if (slot != NULL) {
786 switch (slot->type()) { 680 switch (slot->type()) {
787 case Slot::PARAMETER: 681 case Slot::PARAMETER:
788 case Slot::LOCAL: 682 case Slot::LOCAL:
789 if (mode == Variable::CONST) { 683 if (decl->mode() == Variable::CONST) {
790 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 684 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
791 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); 685 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
792 } else if (function != NULL) { 686 } else if (decl->fun() != NULL) {
793 VisitForValue(function, kAccumulator); 687 VisitForValue(decl->fun(), kAccumulator);
794 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 688 __ movq(Operand(rbp, SlotOffset(slot)), result_register());
795 } 689 }
796 break; 690 break;
797 691
798 case Slot::CONTEXT: 692 case Slot::CONTEXT:
799 // We bypass the general EmitSlotSearch because we know more about 693 // We bypass the general EmitSlotSearch because we know more about
800 // this specific context. 694 // this specific context.
801 695
802 // The variable in the decl always resides in the current context. 696 // The variable in the decl always resides in the current context.
803 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); 697 ASSERT_EQ(0, scope()->ContextChainLength(var->scope()));
804 if (FLAG_debug_code) { 698 if (FLAG_debug_code) {
805 // Check if we have the correct context pointer. 699 // Check if we have the correct context pointer.
806 __ movq(rbx, 700 __ movq(rbx,
807 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); 701 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX));
808 __ cmpq(rbx, rsi); 702 __ cmpq(rbx, rsi);
809 __ Check(equal, "Unexpected declaration in current context."); 703 __ Check(equal, "Unexpected declaration in current context.");
810 } 704 }
811 if (mode == Variable::CONST) { 705 if (decl->mode() == Variable::CONST) {
812 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 706 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
813 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 707 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
814 kScratchRegister); 708 kScratchRegister);
815 // No write barrier since the hole value is in old space. 709 // No write barrier since the hole value is in old space.
816 } else if (function != NULL) { 710 } else if (decl->fun() != NULL) {
817 VisitForValue(function, kAccumulator); 711 VisitForValue(decl->fun(), kAccumulator);
818 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 712 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
819 result_register()); 713 result_register());
820 int offset = Context::SlotOffset(slot->index()); 714 int offset = Context::SlotOffset(slot->index());
821 __ movq(rbx, rsi); 715 __ movq(rbx, rsi);
822 __ RecordWrite(rbx, offset, result_register(), rcx); 716 __ RecordWrite(rbx, offset, result_register(), rcx);
823 } 717 }
824 break; 718 break;
825 719
826 case Slot::LOOKUP: { 720 case Slot::LOOKUP: {
827 __ push(rsi); 721 __ push(rsi);
828 __ Push(variable->name()); 722 __ Push(var->name());
829 // Declaration nodes are always introduced in one of two modes. 723 // Declaration nodes are always introduced in one of two modes.
830 ASSERT(mode == Variable::VAR || mode == Variable::CONST); 724 ASSERT(decl->mode() == Variable::VAR ||
831 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY; 725 decl->mode() == Variable::CONST);
726 PropertyAttributes attr =
727 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
832 __ Push(Smi::FromInt(attr)); 728 __ Push(Smi::FromInt(attr));
833 // Push initial value, if any. 729 // Push initial value, if any.
834 // Note: For variables we must not push an initial value (such as 730 // Note: For variables we must not push an initial value (such as
835 // 'undefined') because we may have a (legal) redeclaration and we 731 // 'undefined') because we may have a (legal) redeclaration and we
836 // must not destroy the current value. 732 // must not destroy the current value.
837 if (mode == Variable::CONST) { 733 if (decl->mode() == Variable::CONST) {
838 __ PushRoot(Heap::kTheHoleValueRootIndex); 734 __ PushRoot(Heap::kTheHoleValueRootIndex);
839 } else if (function != NULL) { 735 } else if (decl->fun() != NULL) {
840 VisitForValue(function, kStack); 736 VisitForValue(decl->fun(), kStack);
841 } else { 737 } else {
842 __ Push(Smi::FromInt(0)); // no initial value! 738 __ Push(Smi::FromInt(0)); // no initial value!
843 } 739 }
844 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 740 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
845 break; 741 break;
846 } 742 }
847 } 743 }
848 744
849 } else if (prop != NULL) { 745 } else if (prop != NULL) {
850 if (function != NULL || mode == Variable::CONST) { 746 if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
851 // We are declaring a function or constant that rewrites to a 747 // We are declaring a function or constant that rewrites to a
852 // property. Use (keyed) IC to set the initial value. 748 // property. Use (keyed) IC to set the initial value.
853 VisitForValue(prop->obj(), kStack); 749 VisitForValue(prop->obj(), kStack);
854 VisitForValue(prop->key(), kStack); 750 VisitForValue(prop->key(), kStack);
855 751
856 if (function != NULL) { 752 if (decl->fun() != NULL) {
857 VisitForValue(function, kAccumulator); 753 VisitForValue(decl->fun(), kAccumulator);
858 } else { 754 } else {
859 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); 755 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
860 } 756 }
861 757
862 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 758 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
863 __ call(ic, RelocInfo::CODE_TARGET); 759 __ call(ic, RelocInfo::CODE_TARGET);
864 // Absence of a test rax instruction following the call 760 // Absence of a test rax instruction following the call
865 // indicates that none of the load was inlined. 761 // indicates that none of the load was inlined.
866 __ nop(); 762 __ nop();
867 763
868 // Value in rax is ignored (declarations are statements). Receiver 764 // Value in rax is ignored (declarations are statements). Receiver
869 // and key on stack are discarded. 765 // and key on stack are discarded.
870 __ Drop(2); 766 __ Drop(2);
871 } 767 }
872 } 768 }
873 } 769 }
874 770
875 771
876 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
877 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
878 }
879
880
881 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 772 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
882 // Call the runtime to declare the globals. 773 // Call the runtime to declare the globals.
883 __ push(rsi); // The context is the first argument. 774 __ push(rsi); // The context is the first argument.
884 __ Push(pairs); 775 __ Push(pairs);
885 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 776 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
886 __ CallRuntime(Runtime::kDeclareGlobals, 3); 777 __ CallRuntime(Runtime::kDeclareGlobals, 3);
887 // Return value is ignored. 778 // Return value is ignored.
888 } 779 }
889 780
890 781
891 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 782 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
892 Comment cmnt(masm_, "[ SwitchStatement"); 783 UNREACHABLE();
893 Breakable nested_statement(this, stmt);
894 SetStatementPosition(stmt);
895 // Keep the switch value on the stack until a case matches.
896 VisitForValue(stmt->tag(), kStack);
897
898 ZoneList<CaseClause*>* clauses = stmt->cases();
899 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
900
901 Label next_test; // Recycled for each test.
902 // Compile all the tests with branches to their bodies.
903 for (int i = 0; i < clauses->length(); i++) {
904 CaseClause* clause = clauses->at(i);
905 // The default is not a test, but remember it as final fall through.
906 if (clause->is_default()) {
907 default_clause = clause;
908 continue;
909 }
910
911 Comment cmnt(masm_, "[ Case comparison");
912 __ bind(&next_test);
913 next_test.Unuse();
914
915 // Compile the label expression.
916 VisitForValue(clause->label(), kAccumulator);
917
918 // Perform the comparison as if via '==='. The comparison stub expects
919 // the smi vs. smi case to be handled before it is called.
920 Label slow_case;
921 __ movq(rdx, Operand(rsp, 0)); // Switch value.
922 __ JumpIfNotBothSmi(rdx, rax, &slow_case);
923 __ SmiCompare(rdx, rax);
924 __ j(not_equal, &next_test);
925 __ Drop(1); // Switch value is no longer needed.
926 __ jmp(clause->body_target()->entry_label());
927
928 __ bind(&slow_case);
929 CompareStub stub(equal, true);
930 __ CallStub(&stub);
931 __ testq(rax, rax);
932 __ j(not_equal, &next_test);
933 __ Drop(1); // Switch value is no longer needed.
934 __ jmp(clause->body_target()->entry_label());
935 }
936
937 // Discard the test value and jump to the default if present, otherwise to
938 // the end of the statement.
939 __ bind(&next_test);
940 __ Drop(1); // Switch value is no longer needed.
941 if (default_clause == NULL) {
942 __ jmp(nested_statement.break_target());
943 } else {
944 __ jmp(default_clause->body_target()->entry_label());
945 }
946
947 // Compile all the case bodies.
948 for (int i = 0; i < clauses->length(); i++) {
949 Comment cmnt(masm_, "[ Case body");
950 CaseClause* clause = clauses->at(i);
951 __ bind(clause->body_target()->entry_label());
952 VisitStatements(clause->statements());
953 }
954
955 __ bind(nested_statement.break_target());
956 } 784 }
957 785
958 786
959 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 787 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
960 Comment cmnt(masm_, "[ ForInStatement"); 788 UNREACHABLE();
961 SetStatementPosition(stmt);
962
963 Label loop, exit;
964 ForIn loop_statement(this, stmt);
965 increment_loop_depth();
966
967 // Get the object to enumerate over. Both SpiderMonkey and JSC
968 // ignore null and undefined in contrast to the specification; see
969 // ECMA-262 section 12.6.4.
970 VisitForValue(stmt->enumerable(), kAccumulator);
971 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
972 __ j(equal, &exit);
973 __ CompareRoot(rax, Heap::kNullValueRootIndex);
974 __ j(equal, &exit);
975
976 // Convert the object to a JS object.
977 Label convert, done_convert;
978 __ JumpIfSmi(rax, &convert);
979 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx);
980 __ j(above_equal, &done_convert);
981 __ bind(&convert);
982 __ push(rax);
983 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
984 __ bind(&done_convert);
985 __ push(rax);
986
987 // TODO(kasperl): Check cache validity in generated code. This is a
988 // fast case for the JSObject::IsSimpleEnum cache validity
989 // checks. If we cannot guarantee cache validity, call the runtime
990 // system to check cache validity or get the property names in a
991 // fixed array.
992
993 // Get the set of properties to enumerate.
994 __ push(rax); // Duplicate the enumerable object on the stack.
995 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
996
997 // If we got a map from the runtime call, we can do a fast
998 // modification check. Otherwise, we got a fixed array, and we have
999 // to do a slow check.
1000 Label fixed_array;
1001 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1002 Heap::kMetaMapRootIndex);
1003 __ j(not_equal, &fixed_array);
1004
1005 // We got a map in register rax. Get the enumeration cache from it.
1006 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset));
1007 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
1008 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1009
1010 // Setup the four remaining stack slots.
1011 __ push(rax); // Map.
1012 __ push(rdx); // Enumeration cache.
1013 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
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 __ push(rax); // Fixed array length (as smi).
1024 __ Push(Smi::FromInt(0)); // Initial index.
1025
1026 // Generate code for doing the condition check.
1027 __ bind(&loop);
1028 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1029 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
1030 __ j(above_equal, loop_statement.break_target());
1031
1032 // Get the current entry of the array into register rbx.
1033 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
1034 SmiIndex index = __ SmiToIndex(rax, rax, kPointerSizeLog2);
1035 __ movq(rbx, FieldOperand(rbx,
1036 index.reg,
1037 index.scale,
1038 FixedArray::kHeaderSize));
1039
1040 // Get the expected map from the stack or a zero map in the
1041 // permanent slow case into register rdx.
1042 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
1043
1044 // Check if the expected map still matches that of the enumerable.
1045 // If not, we have to filter the key.
1046 Label update_each;
1047 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1048 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
1049 __ j(equal, &update_each);
1050
1051 // Convert the entry to a string or null if it isn't a property
1052 // anymore. If the property has been removed while iterating, we
1053 // just skip it.
1054 __ push(rcx); // Enumerable.
1055 __ push(rbx); // Current entry.
1056 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1057 __ CompareRoot(rax, Heap::kNullValueRootIndex);
1058 __ j(equal, loop_statement.continue_target());
1059 __ movq(rbx, rax);
1060
1061 // Update the 'each' property or variable from the possibly filtered
1062 // entry in register rbx.
1063 __ bind(&update_each);
1064 __ movq(result_register(), rbx);
1065 // Perform the assignment as if via '='.
1066 EmitAssignment(stmt->each());
1067
1068 // Generate code for the body of the loop.
1069 Label stack_limit_hit, stack_check_done;
1070 Visit(stmt->body());
1071
1072 __ StackLimitCheck(&stack_limit_hit);
1073 __ bind(&stack_check_done);
1074
1075 // Generate code for going to the next element by incrementing the
1076 // index (smi) stored on top of the stack.
1077 __ bind(loop_statement.continue_target());
1078 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1079 __ jmp(&loop);
1080
1081 // Slow case for the stack limit check.
1082 StackCheckStub stack_check_stub;
1083 __ bind(&stack_limit_hit);
1084 __ CallStub(&stack_check_stub);
1085 __ jmp(&stack_check_done);
1086
1087 // Remove the pointers stored on the stack.
1088 __ bind(loop_statement.break_target());
1089 __ addq(rsp, Immediate(5 * kPointerSize));
1090
1091 // Exit and decrement the loop depth.
1092 __ bind(&exit);
1093 decrement_loop_depth();
1094 } 789 }
1095 790
1096 791
1097 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { 792 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
1098 // Use the fast case closure allocation code that allocates in new 793 // Use the fast case closure allocation code that allocates in new
1099 // space for nested functions that don't need literals cloning. 794 // space for nested functions that don't need literals cloning.
1100 if (scope()->is_function_scope() && info->num_literals() == 0) { 795 if (scope()->is_function_scope() && info->num_literals() == 0) {
1101 FastNewClosureStub stub; 796 FastNewClosureStub stub;
1102 __ Push(info); 797 __ Push(info);
1103 __ CallStub(&stub); 798 __ CallStub(&stub);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1142 Comment cmnt(masm_, "Lookup slot"); 837 Comment cmnt(masm_, "Lookup slot");
1143 __ push(rsi); // Context. 838 __ push(rsi); // Context.
1144 __ Push(var->name()); 839 __ Push(var->name());
1145 __ CallRuntime(Runtime::kLoadContextSlot, 2); 840 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1146 Apply(context, rax); 841 Apply(context, rax);
1147 842
1148 } else if (slot != NULL) { 843 } else if (slot != NULL) {
1149 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 844 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1150 ? "Context slot" 845 ? "Context slot"
1151 : "Stack slot"); 846 : "Stack slot");
1152 if (var->mode() == Variable::CONST) { 847 Apply(context, slot);
1153 // Constants may be the hole value if they have not been initialized.
1154 // Unhole them.
1155 Label done;
1156 MemOperand slot_operand = EmitSlotSearch(slot, rax);
1157 __ movq(rax, slot_operand);
1158 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1159 __ j(not_equal, &done);
1160 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1161 __ bind(&done);
1162 Apply(context, rax);
1163 } else {
1164 Apply(context, slot);
1165 }
1166 848
1167 } else { 849 } else {
1168 Comment cmnt(masm_, "Rewritten parameter"); 850 Comment cmnt(masm_, "Rewritten parameter");
1169 ASSERT_NOT_NULL(property); 851 ASSERT_NOT_NULL(property);
1170 // Rewritten parameter accesses are of the form "slot[literal]". 852 // Rewritten parameter accesses are of the form "slot[literal]".
1171 853
1172 // Assert that the object is in a slot. 854 // Assert that the object is in a slot.
1173 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 855 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1174 ASSERT_NOT_NULL(object_var); 856 ASSERT_NOT_NULL(object_var);
1175 Slot* object_slot = object_var->slot(); 857 Slot* object_slot = object_var->slot();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1291 if (result_saved) { 973 if (result_saved) {
1292 ApplyTOS(context_); 974 ApplyTOS(context_);
1293 } else { 975 } else {
1294 Apply(context_, rax); 976 Apply(context_, rax);
1295 } 977 }
1296 } 978 }
1297 979
1298 980
1299 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 981 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1300 Comment cmnt(masm_, "[ ArrayLiteral"); 982 Comment cmnt(masm_, "[ ArrayLiteral");
1301
1302 ZoneList<Expression*>* subexprs = expr->values();
1303 int length = subexprs->length();
1304
1305 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 983 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1306 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); 984 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1307 __ Push(Smi::FromInt(expr->literal_index())); 985 __ Push(Smi::FromInt(expr->literal_index()));
1308 __ Push(expr->constant_elements()); 986 __ Push(expr->constant_elements());
1309 if (expr->depth() > 1) { 987 if (expr->depth() > 1) {
1310 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 988 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1311 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { 989 } else {
1312 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 990 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
1313 } else {
1314 FastCloneShallowArrayStub stub(length);
1315 __ CallStub(&stub);
1316 } 991 }
1317 992
1318 bool result_saved = false; // Is the result saved to the stack? 993 bool result_saved = false; // Is the result saved to the stack?
1319 994
1320 // Emit code to evaluate all the non-constant subexpressions and to store 995 // Emit code to evaluate all the non-constant subexpressions and to store
1321 // them into the newly cloned array. 996 // them into the newly cloned array.
1322 for (int i = 0; i < length; i++) { 997 ZoneList<Expression*>* subexprs = expr->values();
998 for (int i = 0, len = subexprs->length(); i < len; i++) {
1323 Expression* subexpr = subexprs->at(i); 999 Expression* subexpr = subexprs->at(i);
1324 // If the subexpression is a literal or a simple materialized literal it 1000 // If the subexpression is a literal or a simple materialized literal it
1325 // is already set in the cloned array. 1001 // is already set in the cloned array.
1326 if (subexpr->AsLiteral() != NULL || 1002 if (subexpr->AsLiteral() != NULL ||
1327 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1003 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1328 continue; 1004 continue;
1329 } 1005 }
1330 1006
1331 if (!result_saved) { 1007 if (!result_saved) {
1332 __ push(rax); 1008 __ push(rax);
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 Expression::Context context) { 1150 Expression::Context context) {
1475 __ push(result_register()); 1151 __ push(result_register());
1476 GenericBinaryOpStub stub(op, 1152 GenericBinaryOpStub stub(op,
1477 NO_OVERWRITE, 1153 NO_OVERWRITE,
1478 NO_GENERIC_BINARY_FLAGS); 1154 NO_GENERIC_BINARY_FLAGS);
1479 __ CallStub(&stub); 1155 __ CallStub(&stub);
1480 Apply(context, rax); 1156 Apply(context, rax);
1481 } 1157 }
1482 1158
1483 1159
1484 void FullCodeGenerator::EmitAssignment(Expression* expr) {
1485 // Invalid left-hand sides are rewritten to have a 'throw
1486 // ReferenceError' on the left-hand side.
1487 if (!expr->IsValidLeftHandSide()) {
1488 VisitForEffect(expr);
1489 return;
1490 }
1491
1492 // Left-hand side can only be a property, a global or a (parameter or local)
1493 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1494 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1495 LhsKind assign_type = VARIABLE;
1496 Property* prop = expr->AsProperty();
1497 if (prop != NULL) {
1498 assign_type = (prop->key()->IsPropertyName())
1499 ? NAMED_PROPERTY
1500 : KEYED_PROPERTY;
1501 }
1502
1503 switch (assign_type) {
1504 case VARIABLE: {
1505 Variable* var = expr->AsVariableProxy()->var();
1506 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1507 break;
1508 }
1509 case NAMED_PROPERTY: {
1510 __ push(rax); // Preserve value.
1511 VisitForValue(prop->obj(), kAccumulator);
1512 __ movq(rdx, rax);
1513 __ pop(rax); // Restore value.
1514 __ Move(rcx, prop->key()->AsLiteral()->handle());
1515 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1516 __ call(ic, RelocInfo::CODE_TARGET);
1517 __ nop(); // Signal no inlined code.
1518 break;
1519 }
1520 case KEYED_PROPERTY: {
1521 __ push(rax); // Preserve value.
1522 VisitForValue(prop->obj(), kStack);
1523 VisitForValue(prop->key(), kStack);
1524 __ movq(rax, Operand(rsp, 2 * kPointerSize));
1525 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1526 __ call(ic, RelocInfo::CODE_TARGET);
1527 __ nop(); // Signal no inlined code.
1528 __ Drop(3); // Receiver, key, and extra copy of value.
1529 break;
1530 }
1531 }
1532 }
1533
1534
1535 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1160 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1536 Token::Value op, 1161 Token::Value op,
1537 Expression::Context context) { 1162 Expression::Context context) {
1538 // Left-hand sides that rewrite to explicit property accesses do not reach 1163 // Left-hand sides that rewrite to explicit property accesses do not reach
1539 // here. 1164 // here.
1540 ASSERT(var != NULL); 1165 ASSERT(var != NULL);
1541 ASSERT(var->is_global() || var->slot() != NULL); 1166 ASSERT(var->is_global() || var->slot() != NULL);
1542 1167
1543 if (var->is_global()) { 1168 if (var->is_global()) {
1544 ASSERT(!var->is_this()); 1169 ASSERT(!var->is_this());
(...skipping 10 matching lines...) Expand all
1555 // Perform the assignment for non-const variables and for initialization 1180 // Perform the assignment for non-const variables and for initialization
1556 // of const variables. Const assignments are simply skipped. 1181 // of const variables. Const assignments are simply skipped.
1557 Label done; 1182 Label done;
1558 Slot* slot = var->slot(); 1183 Slot* slot = var->slot();
1559 switch (slot->type()) { 1184 switch (slot->type()) {
1560 case Slot::PARAMETER: 1185 case Slot::PARAMETER:
1561 case Slot::LOCAL: 1186 case Slot::LOCAL:
1562 if (op == Token::INIT_CONST) { 1187 if (op == Token::INIT_CONST) {
1563 // Detect const reinitialization by checking for the hole value. 1188 // Detect const reinitialization by checking for the hole value.
1564 __ movq(rdx, Operand(rbp, SlotOffset(slot))); 1189 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1565 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); 1190 __ Cmp(rdx, Factory::the_hole_value());
1566 __ j(not_equal, &done); 1191 __ j(not_equal, &done);
1567 } 1192 }
1568 // Perform the assignment. 1193 // Perform the assignment.
1569 __ movq(Operand(rbp, SlotOffset(slot)), rax); 1194 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1570 break; 1195 break;
1571 1196
1572 case Slot::CONTEXT: { 1197 case Slot::CONTEXT: {
1573 MemOperand target = EmitSlotSearch(slot, rcx); 1198 MemOperand target = EmitSlotSearch(slot, rcx);
1574 if (op == Token::INIT_CONST) { 1199 if (op == Token::INIT_CONST) {
1575 // Detect const reinitialization by checking for the hole value. 1200 // Detect const reinitialization by checking for the hole value.
1576 __ movq(rdx, target); 1201 __ movq(rdx, target);
1577 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); 1202 __ Cmp(rdx, Factory::the_hole_value());
1578 __ j(not_equal, &done); 1203 __ j(not_equal, &done);
1579 } 1204 }
1580 // Perform the assignment and issue the write barrier. 1205 // Perform the assignment and issue the write barrier.
1581 __ movq(target, rax); 1206 __ movq(target, rax);
1582 // The value of the assignment is in rax. RecordWrite clobbers its 1207 // The value of the assignment is in rax. RecordWrite clobbers its
1583 // register arguments. 1208 // register arguments.
1584 __ movq(rdx, rax); 1209 __ movq(rdx, rax);
1585 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1210 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1586 __ RecordWrite(rcx, offset, rdx, rbx); 1211 __ RecordWrite(rcx, offset, rdx, rbx);
1587 break; 1212 break;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1730 1355
1731 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1356 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1732 // Code common for calls using the call stub. 1357 // Code common for calls using the call stub.
1733 ZoneList<Expression*>* args = expr->arguments(); 1358 ZoneList<Expression*>* args = expr->arguments();
1734 int arg_count = args->length(); 1359 int arg_count = args->length();
1735 for (int i = 0; i < arg_count; i++) { 1360 for (int i = 0; i < arg_count; i++) {
1736 VisitForValue(args->at(i), kStack); 1361 VisitForValue(args->at(i), kStack);
1737 } 1362 }
1738 // Record source position for debugger. 1363 // Record source position for debugger.
1739 SetSourcePosition(expr->position()); 1364 SetSourcePosition(expr->position());
1740 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 1365 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
1741 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1742 __ CallStub(&stub); 1366 __ CallStub(&stub);
1743 // Restore context register. 1367 // Restore context register.
1744 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1368 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1745 // Discard the function left on TOS. 1369 // Discard the function left on TOS.
1746 DropAndApply(1, context_, rax); 1370 DropAndApply(1, context_, rax);
1747 } 1371 }
1748 1372
1749 1373
1750 void FullCodeGenerator::VisitCall(Call* expr) { 1374 void FullCodeGenerator::VisitCall(Call* expr) {
1751 Comment cmnt(masm_, "[ Call"); 1375 Comment cmnt(masm_, "[ Call");
1752 Expression* fun = expr->expression(); 1376 Expression* fun = expr->expression();
1753 Variable* var = fun->AsVariableProxy()->AsVariable(); 1377 Variable* var = fun->AsVariableProxy()->AsVariable();
1754 1378
1755 if (var != NULL && var->is_possibly_eval()) { 1379 if (var != NULL && var->is_possibly_eval()) {
1756 // In a call to eval, we first call %ResolvePossiblyDirectEval to 1380 // Call to the identifier 'eval'.
1757 // resolve the function we need to call and the receiver of the 1381 UNREACHABLE();
1758 // call. The we call the resolved function using the given
1759 // arguments.
1760 VisitForValue(fun, kStack);
1761 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
1762
1763 // Push the arguments.
1764 ZoneList<Expression*>* args = expr->arguments();
1765 int arg_count = args->length();
1766 for (int i = 0; i < arg_count; i++) {
1767 VisitForValue(args->at(i), kStack);
1768 }
1769
1770 // Push copy of the function - found below the arguments.
1771 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
1772
1773 // Push copy of the first argument or undefined if it doesn't exist.
1774 if (arg_count > 0) {
1775 __ push(Operand(rsp, arg_count * kPointerSize));
1776 } else {
1777 __ PushRoot(Heap::kUndefinedValueRootIndex);
1778 }
1779
1780 // Push the receiver of the enclosing function and do runtime call.
1781 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
1782 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1783
1784 // The runtime call returns a pair of values in rax (function) and
1785 // rdx (receiver). Touch up the stack with the right values.
1786 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
1787 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
1788
1789 // Record source position for debugger.
1790 SetSourcePosition(expr->position());
1791 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1792 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1793 __ CallStub(&stub);
1794 // Restore context register.
1795 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1796 DropAndApply(1, context_, rax);
1797 } else if (var != NULL && !var->is_this() && var->is_global()) { 1382 } else if (var != NULL && !var->is_this() && var->is_global()) {
1798 // Call to a global variable. 1383 // Call to a global variable.
1799 // Push global object as receiver for the call IC lookup. 1384 // Push global object as receiver for the call IC lookup.
1800 __ push(CodeGenerator::GlobalObject()); 1385 __ push(CodeGenerator::GlobalObject());
1801 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1386 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1802 } else if (var != NULL && var->slot() != NULL && 1387 } else if (var != NULL && var->slot() != NULL &&
1803 var->slot()->type() == Slot::LOOKUP) { 1388 var->slot()->type() == Slot::LOOKUP) {
1804 // Call to a lookup slot (dynamically introduced variable). Call 1389 // Call to a lookup slot.
1805 // the runtime to find the function to call (returned in rax) and 1390 UNREACHABLE();
1806 // the object holding it (returned in rdx).
1807 __ push(context_register());
1808 __ Push(var->name());
1809 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1810 __ push(rax); // Function.
1811 __ push(rdx); // Receiver.
1812 EmitCallWithStub(expr);
1813 } else if (fun->AsProperty() != NULL) { 1391 } else if (fun->AsProperty() != NULL) {
1814 // Call to an object property. 1392 // Call to an object property.
1815 Property* prop = fun->AsProperty(); 1393 Property* prop = fun->AsProperty();
1816 Literal* key = prop->key()->AsLiteral(); 1394 Literal* key = prop->key()->AsLiteral();
1817 if (key != NULL && key->handle()->IsSymbol()) { 1395 if (key != NULL && key->handle()->IsSymbol()) {
1818 // Call to a named property, use call IC. 1396 // Call to a named property, use call IC.
1819 VisitForValue(prop->obj(), kStack); 1397 VisitForValue(prop->obj(), kStack);
1820 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1398 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1821 } else { 1399 } else {
1822 // Call to a keyed property, use keyed load IC followed by function 1400 // Call to a keyed property, use keyed load IC followed by function
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1893 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); 1471 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
1894 1472
1895 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1473 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1896 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1474 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1897 1475
1898 // Replace function on TOS with result in rax, or pop it. 1476 // Replace function on TOS with result in rax, or pop it.
1899 DropAndApply(1, context_, rax); 1477 DropAndApply(1, context_, rax);
1900 } 1478 }
1901 1479
1902 1480
1903 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
1904 Handle<String> name = expr->name();
1905 if (strcmp("_IsSmi", *name->ToCString()) == 0) {
1906 EmitIsSmi(expr->arguments());
1907 } else if (strcmp("_IsNonNegativeSmi", *name->ToCString()) == 0) {
1908 EmitIsNonNegativeSmi(expr->arguments());
1909 } else if (strcmp("_IsObject", *name->ToCString()) == 0) {
1910 EmitIsObject(expr->arguments());
1911 } else if (strcmp("_IsUndetectableObject", *name->ToCString()) == 0) {
1912 EmitIsUndetectableObject(expr->arguments());
1913 } else if (strcmp("_IsFunction", *name->ToCString()) == 0) {
1914 EmitIsFunction(expr->arguments());
1915 } else if (strcmp("_IsArray", *name->ToCString()) == 0) {
1916 EmitIsArray(expr->arguments());
1917 } else if (strcmp("_IsRegExp", *name->ToCString()) == 0) {
1918 EmitIsRegExp(expr->arguments());
1919 } else if (strcmp("_IsConstructCall", *name->ToCString()) == 0) {
1920 EmitIsConstructCall(expr->arguments());
1921 } else if (strcmp("_ObjectEquals", *name->ToCString()) == 0) {
1922 EmitObjectEquals(expr->arguments());
1923 } else if (strcmp("_Arguments", *name->ToCString()) == 0) {
1924 EmitArguments(expr->arguments());
1925 } else if (strcmp("_ArgumentsLength", *name->ToCString()) == 0) {
1926 EmitArgumentsLength(expr->arguments());
1927 } else if (strcmp("_ClassOf", *name->ToCString()) == 0) {
1928 EmitClassOf(expr->arguments());
1929 } else if (strcmp("_Log", *name->ToCString()) == 0) {
1930 EmitLog(expr->arguments());
1931 } else if (strcmp("_RandomHeapNumber", *name->ToCString()) == 0) {
1932 EmitRandomHeapNumber(expr->arguments());
1933 } else if (strcmp("_SubString", *name->ToCString()) == 0) {
1934 EmitSubString(expr->arguments());
1935 } else if (strcmp("_RegExpExec", *name->ToCString()) == 0) {
1936 EmitRegExpExec(expr->arguments());
1937 } else if (strcmp("_ValueOf", *name->ToCString()) == 0) {
1938 EmitValueOf(expr->arguments());
1939 } else if (strcmp("_SetValueOf", *name->ToCString()) == 0) {
1940 EmitSetValueOf(expr->arguments());
1941 } else if (strcmp("_NumberToString", *name->ToCString()) == 0) {
1942 EmitNumberToString(expr->arguments());
1943 } else if (strcmp("_CharFromCode", *name->ToCString()) == 0) {
1944 EmitCharFromCode(expr->arguments());
1945 } else if (strcmp("_FastCharCodeAt", *name->ToCString()) == 0) {
1946 EmitFastCharCodeAt(expr->arguments());
1947 } else if (strcmp("_StringAdd", *name->ToCString()) == 0) {
1948 EmitStringAdd(expr->arguments());
1949 } else if (strcmp("_StringCompare", *name->ToCString()) == 0) {
1950 EmitStringCompare(expr->arguments());
1951 } else if (strcmp("_MathPow", *name->ToCString()) == 0) {
1952 EmitMathPow(expr->arguments());
1953 } else if (strcmp("_MathSin", *name->ToCString()) == 0) {
1954 EmitMathSin(expr->arguments());
1955 } else if (strcmp("_MathCos", *name->ToCString()) == 0) {
1956 EmitMathCos(expr->arguments());
1957 } else if (strcmp("_MathSqrt", *name->ToCString()) == 0) {
1958 EmitMathSqrt(expr->arguments());
1959 } else if (strcmp("_CallFunction", *name->ToCString()) == 0) {
1960 EmitCallFunction(expr->arguments());
1961 } else if (strcmp("_RegExpConstructResult", *name->ToCString()) == 0) {
1962 EmitRegExpConstructResult(expr->arguments());
1963 } else if (strcmp("_SwapElements", *name->ToCString()) == 0) {
1964 EmitSwapElements(expr->arguments());
1965 } else if (strcmp("_GetFromCache", *name->ToCString()) == 0) {
1966 EmitGetFromCache(expr->arguments());
1967 } else {
1968 UNREACHABLE();
1969 }
1970 }
1971
1972
1973 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1974 ASSERT(args->length() == 1);
1975
1976 VisitForValue(args->at(0), kAccumulator);
1977
1978 Label materialize_true, materialize_false;
1979 Label* if_true = NULL;
1980 Label* if_false = NULL;
1981 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1982
1983 __ JumpIfSmi(rax, if_true);
1984 __ jmp(if_false);
1985
1986 Apply(context_, if_true, if_false);
1987 }
1988
1989
1990 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1991 ASSERT(args->length() == 1);
1992
1993 VisitForValue(args->at(0), kAccumulator);
1994
1995 Label materialize_true, materialize_false;
1996 Label* if_true = NULL;
1997 Label* if_false = NULL;
1998 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1999
2000 Condition positive_smi = __ CheckPositiveSmi(rax);
2001 __ j(positive_smi, if_true);
2002 __ jmp(if_false);
2003
2004 Apply(context_, if_true, if_false);
2005 }
2006
2007
2008 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2009 ASSERT(args->length() == 1);
2010
2011 VisitForValue(args->at(0), kAccumulator);
2012
2013 Label materialize_true, materialize_false;
2014 Label* if_true = NULL;
2015 Label* if_false = NULL;
2016 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2017
2018 __ JumpIfSmi(rax, if_false);
2019 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2020 __ j(equal, if_true);
2021 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2022 // Undetectable objects behave like undefined when tested with typeof.
2023 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2024 Immediate(1 << Map::kIsUndetectable));
2025 __ j(not_zero, if_false);
2026 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
2027 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
2028 __ j(below, if_false);
2029 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
2030 __ j(below_equal, if_true);
2031 __ jmp(if_false);
2032
2033 Apply(context_, if_true, if_false);
2034 }
2035
2036
2037 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2038 ASSERT(args->length() == 1);
2039
2040 VisitForValue(args->at(0), kAccumulator);
2041
2042 Label materialize_true, materialize_false;
2043 Label* if_true = NULL;
2044 Label* if_false = NULL;
2045 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2046
2047 __ JumpIfSmi(rax, if_false);
2048 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2049 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2050 Immediate(1 << Map::kIsUndetectable));
2051 __ j(not_zero, if_true);
2052 __ jmp(if_false);
2053
2054 Apply(context_, if_true, if_false);
2055 }
2056
2057
2058 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2059 ASSERT(args->length() == 1);
2060
2061 VisitForValue(args->at(0), kAccumulator);
2062
2063 Label materialize_true, materialize_false;
2064 Label* if_true = NULL;
2065 Label* if_false = NULL;
2066 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2067
2068 __ JumpIfSmi(rax, if_false);
2069 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2070 __ j(equal, if_true);
2071 __ jmp(if_false);
2072
2073 Apply(context_, if_true, if_false);
2074 }
2075
2076
2077 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2078 ASSERT(args->length() == 1);
2079
2080 VisitForValue(args->at(0), kAccumulator);
2081
2082 Label materialize_true, materialize_false;
2083 Label* if_true = NULL;
2084 Label* if_false = NULL;
2085 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2086
2087 __ JumpIfSmi(rax, if_false);
2088 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2089 __ j(equal, if_true);
2090 __ jmp(if_false);
2091
2092 Apply(context_, if_true, if_false);
2093 }
2094
2095
2096 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2097 ASSERT(args->length() == 1);
2098
2099 VisitForValue(args->at(0), kAccumulator);
2100
2101 Label materialize_true, materialize_false;
2102 Label* if_true = NULL;
2103 Label* if_false = NULL;
2104 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2105
2106 __ JumpIfSmi(rax, if_false);
2107 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
2108 __ j(equal, if_true);
2109 __ jmp(if_false);
2110
2111 Apply(context_, if_true, if_false);
2112 }
2113
2114
2115
2116 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2117 ASSERT(args->length() == 0);
2118
2119 Label materialize_true, materialize_false;
2120 Label* if_true = NULL;
2121 Label* if_false = NULL;
2122 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2123
2124 // Get the frame pointer for the calling frame.
2125 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2126
2127 // Skip the arguments adaptor frame if it exists.
2128 Label check_frame_marker;
2129 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset),
2130 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2131 __ j(not_equal, &check_frame_marker);
2132 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2133
2134 // Check the marker in the calling frame.
2135 __ bind(&check_frame_marker);
2136 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
2137 Smi::FromInt(StackFrame::CONSTRUCT));
2138 __ j(equal, if_true);
2139 __ jmp(if_false);
2140
2141 Apply(context_, if_true, if_false);
2142 }
2143
2144
2145 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2146 ASSERT(args->length() == 2);
2147
2148 // Load the two objects into registers and perform the comparison.
2149 VisitForValue(args->at(0), kStack);
2150 VisitForValue(args->at(1), kAccumulator);
2151
2152 Label materialize_true, materialize_false;
2153 Label* if_true = NULL;
2154 Label* if_false = NULL;
2155 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2156
2157 __ pop(rbx);
2158 __ cmpq(rax, rbx);
2159 __ j(equal, if_true);
2160 __ jmp(if_false);
2161
2162 Apply(context_, if_true, if_false);
2163 }
2164
2165
2166 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2167 ASSERT(args->length() == 1);
2168
2169 // ArgumentsAccessStub expects the key in edx and the formal
2170 // parameter count in eax.
2171 VisitForValue(args->at(0), kAccumulator);
2172 __ movq(rdx, rax);
2173 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2174 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2175 __ CallStub(&stub);
2176 Apply(context_, rax);
2177 }
2178
2179
2180 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2181 ASSERT(args->length() == 0);
2182
2183 Label exit;
2184 // Get the number of formal parameters.
2185 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2186
2187 // Check if the calling frame is an arguments adaptor frame.
2188 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2189 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
2190 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2191 __ j(not_equal, &exit);
2192
2193 // Arguments adaptor case: Read the arguments length from the
2194 // adaptor frame.
2195 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2196
2197 __ bind(&exit);
2198 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
2199 Apply(context_, rax);
2200 }
2201
2202
2203 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2204 ASSERT(args->length() == 1);
2205 Label done, null, function, non_function_constructor;
2206
2207 VisitForValue(args->at(0), kAccumulator);
2208
2209 // If the object is a smi, we return null.
2210 __ JumpIfSmi(rax, &null);
2211
2212 // Check that the object is a JS object but take special care of JS
2213 // functions to make sure they have 'Function' as their class.
2214 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
2215 __ j(below, &null);
2216
2217 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2218 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2219 // LAST_JS_OBJECT_TYPE.
2220 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2221 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
2222 __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
2223 __ j(equal, &function);
2224
2225 // Check if the constructor in the map is a function.
2226 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2227 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2228 __ j(not_equal, &non_function_constructor);
2229
2230 // rax now contains the constructor function. Grab the
2231 // instance class name from there.
2232 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2233 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2234 __ jmp(&done);
2235
2236 // Functions have class 'Function'.
2237 __ bind(&function);
2238 __ Move(rax, Factory::function_class_symbol());
2239 __ jmp(&done);
2240
2241 // Objects with a non-function constructor have class 'Object'.
2242 __ bind(&non_function_constructor);
2243 __ Move(rax, Factory::Object_symbol());
2244 __ jmp(&done);
2245
2246 // Non-JS objects have class null.
2247 __ bind(&null);
2248 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2249
2250 // All done.
2251 __ bind(&done);
2252
2253 Apply(context_, rax);
2254 }
2255
2256
2257 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2258 // Conditionally generate a log call.
2259 // Args:
2260 // 0 (literal string): The type of logging (corresponds to the flags).
2261 // This is used to determine whether or not to generate the log call.
2262 // 1 (string): Format string. Access the string at argument index 2
2263 // with '%2s' (see Logger::LogRuntime for all the formats).
2264 // 2 (array): Arguments to the format string.
2265 ASSERT_EQ(args->length(), 3);
2266 #ifdef ENABLE_LOGGING_AND_PROFILING
2267 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2268 VisitForValue(args->at(1), kStack);
2269 VisitForValue(args->at(2), kStack);
2270 __ CallRuntime(Runtime::kLog, 2);
2271 }
2272 #endif
2273 // Finally, we're expected to leave a value on the top of the stack.
2274 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2275 Apply(context_, rax);
2276 }
2277
2278
2279 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2280 ASSERT(args->length() == 0);
2281
2282 Label slow_allocate_heapnumber;
2283 Label heapnumber_allocated;
2284
2285 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2286 __ jmp(&heapnumber_allocated);
2287
2288 __ bind(&slow_allocate_heapnumber);
2289 // To allocate a heap number, and ensure that it is not a smi, we
2290 // call the runtime function FUnaryMinus on 0, returning the double
2291 // -0.0. A new, distinct heap number is returned each time.
2292 __ Push(Smi::FromInt(0));
2293 __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
2294 __ movq(rbx, rax);
2295
2296 __ bind(&heapnumber_allocated);
2297
2298 // Return a random uint32 number in rax.
2299 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
2300 __ PrepareCallCFunction(0);
2301 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2302
2303 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2304 // by computing:
2305 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2306 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2307 __ movd(xmm1, rcx);
2308 __ movd(xmm0, rax);
2309 __ cvtss2sd(xmm1, xmm1);
2310 __ xorpd(xmm0, xmm1);
2311 __ subsd(xmm0, xmm1);
2312 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2313
2314 __ movq(rax, rbx);
2315 Apply(context_, rax);
2316 }
2317
2318
2319 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2320 // Load the arguments on the stack and call the stub.
2321 SubStringStub stub;
2322 ASSERT(args->length() == 3);
2323 VisitForValue(args->at(0), kStack);
2324 VisitForValue(args->at(1), kStack);
2325 VisitForValue(args->at(2), kStack);
2326 __ CallStub(&stub);
2327 Apply(context_, rax);
2328 }
2329
2330
2331 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2332 // Load the arguments on the stack and call the stub.
2333 RegExpExecStub stub;
2334 ASSERT(args->length() == 4);
2335 VisitForValue(args->at(0), kStack);
2336 VisitForValue(args->at(1), kStack);
2337 VisitForValue(args->at(2), kStack);
2338 VisitForValue(args->at(3), kStack);
2339 __ CallStub(&stub);
2340 Apply(context_, rax);
2341 }
2342
2343
2344 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2345 ASSERT(args->length() == 1);
2346
2347 VisitForValue(args->at(0), kAccumulator); // Load the object.
2348
2349 Label done;
2350 // If the object is a smi return the object.
2351 __ JumpIfSmi(rax, &done);
2352 // If the object is not a value type, return the object.
2353 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2354 __ j(not_equal, &done);
2355 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2356
2357 __ bind(&done);
2358 Apply(context_, rax);
2359 }
2360
2361
2362 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2363 // Load the arguments on the stack and call the runtime function.
2364 ASSERT(args->length() == 2);
2365 VisitForValue(args->at(0), kStack);
2366 VisitForValue(args->at(1), kStack);
2367 __ CallRuntime(Runtime::kMath_pow, 2);
2368 Apply(context_, rax);
2369 }
2370
2371
2372 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2373 ASSERT(args->length() == 2);
2374
2375 VisitForValue(args->at(0), kStack); // Load the object.
2376 VisitForValue(args->at(1), kAccumulator); // Load the value.
2377 __ pop(rbx); // rax = value. ebx = object.
2378
2379 Label done;
2380 // If the object is a smi, return the value.
2381 __ JumpIfSmi(rbx, &done);
2382
2383 // If the object is not a value type, return the value.
2384 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2385 __ j(not_equal, &done);
2386
2387 // Store the value.
2388 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2389 // Update the write barrier. Save the value as it will be
2390 // overwritten by the write barrier code and is needed afterward.
2391 __ movq(rdx, rax);
2392 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
2393
2394 __ bind(&done);
2395 Apply(context_, rax);
2396 }
2397
2398
2399 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2400 ASSERT_EQ(args->length(), 1);
2401
2402 // Load the argument on the stack and call the stub.
2403 VisitForValue(args->at(0), kStack);
2404
2405 NumberToStringStub stub;
2406 __ CallStub(&stub);
2407 Apply(context_, rax);
2408 }
2409
2410
2411 void FullCodeGenerator::EmitCharFromCode(ZoneList<Expression*>* args) {
2412 ASSERT(args->length() == 1);
2413
2414 VisitForValue(args->at(0), kAccumulator);
2415
2416 Label slow_case, done;
2417 // Fast case of Heap::LookupSingleCharacterStringFromCode.
2418 __ JumpIfNotSmi(rax, &slow_case);
2419 __ SmiToInteger32(rcx, rax);
2420 __ cmpl(rcx, Immediate(String::kMaxAsciiCharCode));
2421 __ j(above, &slow_case);
2422
2423 __ Move(rbx, Factory::single_character_string_cache());
2424 __ movq(rbx, FieldOperand(rbx,
2425 rcx,
2426 times_pointer_size,
2427 FixedArray::kHeaderSize));
2428
2429 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
2430 __ j(equal, &slow_case);
2431 __ movq(rax, rbx);
2432 __ jmp(&done);
2433
2434 __ bind(&slow_case);
2435 __ push(rax);
2436 __ CallRuntime(Runtime::kCharFromCode, 1);
2437
2438 __ bind(&done);
2439 Apply(context_, rax);
2440 }
2441
2442
2443 void FullCodeGenerator::EmitFastCharCodeAt(ZoneList<Expression*>* args) {
2444 // TODO(fsc): Port the complete implementation from the classic back-end.
2445 // Move the undefined value into the result register, which will
2446 // trigger the slow case.
2447 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2448 Apply(context_, rax);
2449 }
2450
2451 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2452 ASSERT_EQ(2, args->length());
2453
2454 VisitForValue(args->at(0), kStack);
2455 VisitForValue(args->at(1), kStack);
2456
2457 StringAddStub stub(NO_STRING_ADD_FLAGS);
2458 __ CallStub(&stub);
2459 Apply(context_, rax);
2460 }
2461
2462
2463 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2464 ASSERT_EQ(2, args->length());
2465
2466 VisitForValue(args->at(0), kStack);
2467 VisitForValue(args->at(1), kStack);
2468
2469 StringCompareStub stub;
2470 __ CallStub(&stub);
2471 Apply(context_, rax);
2472 }
2473
2474
2475 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2476 // Load the argument on the stack and call the stub.
2477 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2478 ASSERT(args->length() == 1);
2479 VisitForValue(args->at(0), kStack);
2480 __ CallStub(&stub);
2481 Apply(context_, rax);
2482 }
2483
2484
2485 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2486 // Load the argument on the stack and call the stub.
2487 TranscendentalCacheStub stub(TranscendentalCache::COS);
2488 ASSERT(args->length() == 1);
2489 VisitForValue(args->at(0), kStack);
2490 __ CallStub(&stub);
2491 Apply(context_, rax);
2492 }
2493
2494
2495 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2496 // Load the argument on the stack and call the runtime function.
2497 ASSERT(args->length() == 1);
2498 VisitForValue(args->at(0), kStack);
2499 __ CallRuntime(Runtime::kMath_sqrt, 1);
2500 Apply(context_, rax);
2501 }
2502
2503
2504 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2505 ASSERT(args->length() >= 2);
2506
2507 int arg_count = args->length() - 2; // For receiver and function.
2508 VisitForValue(args->at(0), kStack); // Receiver.
2509 for (int i = 0; i < arg_count; i++) {
2510 VisitForValue(args->at(i + 1), kStack);
2511 }
2512 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2513
2514 // InvokeFunction requires function in rdi. Move it in there.
2515 if (!result_register().is(rdi)) __ movq(rdi, result_register());
2516 ParameterCount count(arg_count);
2517 __ InvokeFunction(rdi, count, CALL_FUNCTION);
2518 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2519 Apply(context_, rax);
2520 }
2521
2522
2523 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2524 ASSERT(args->length() == 3);
2525 VisitForValue(args->at(0), kStack);
2526 VisitForValue(args->at(1), kStack);
2527 VisitForValue(args->at(2), kStack);
2528 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2529 Apply(context_, rax);
2530 }
2531
2532
2533 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2534 ASSERT(args->length() == 3);
2535 VisitForValue(args->at(0), kStack);
2536 VisitForValue(args->at(1), kStack);
2537 VisitForValue(args->at(2), kStack);
2538 __ CallRuntime(Runtime::kSwapElements, 3);
2539 Apply(context_, rax);
2540 }
2541
2542
2543 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2544 ASSERT_EQ(2, args->length());
2545
2546 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2547 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2548
2549 Handle<FixedArray> jsfunction_result_caches(
2550 Top::global_context()->jsfunction_result_caches());
2551 if (jsfunction_result_caches->length() <= cache_id) {
2552 __ Abort("Attempt to use undefined cache.");
2553 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2554 Apply(context_, rax);
2555 return;
2556 }
2557
2558 VisitForValue(args->at(1), kAccumulator);
2559
2560 Register key = rax;
2561 Register cache = rbx;
2562 Register tmp = rcx;
2563 __ movq(cache, CodeGenerator::ContextOperand(rsi, Context::GLOBAL_INDEX));
2564 __ movq(cache,
2565 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
2566 __ movq(cache,
2567 CodeGenerator::ContextOperand(
2568 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2569 __ movq(cache,
2570 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2571
2572 Label done, not_found;
2573 // tmp now holds finger offset as a smi.
2574 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2575 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
2576 SmiIndex index =
2577 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
2578 __ cmpq(key, FieldOperand(cache,
2579 index.reg,
2580 index.scale,
2581 FixedArray::kHeaderSize));
2582 __ j(not_equal, &not_found);
2583 __ movq(rax, FieldOperand(cache,
2584 index.reg,
2585 index.scale,
2586 FixedArray::kHeaderSize + kPointerSize));
2587 __ jmp(&done);
2588
2589 __ bind(&not_found);
2590 // Call runtime to perform the lookup.
2591 __ push(cache);
2592 __ push(key);
2593 __ CallRuntime(Runtime::kGetFromCache, 2);
2594
2595 __ bind(&done);
2596 Apply(context_, rax);
2597 }
2598
2599
2600 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 1481 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2601 Handle<String> name = expr->name();
2602 if (name->length() > 0 && name->Get(0) == '_') {
2603 Comment cmnt(masm_, "[ InlineRuntimeCall");
2604 EmitInlineRuntimeCall(expr);
2605 return;
2606 }
2607
2608 Comment cmnt(masm_, "[ CallRuntime"); 1482 Comment cmnt(masm_, "[ CallRuntime");
2609 ZoneList<Expression*>* args = expr->arguments(); 1483 ZoneList<Expression*>* args = expr->arguments();
2610 1484
2611 if (expr->is_jsruntime()) { 1485 if (expr->is_jsruntime()) {
2612 // Prepare for calling JS runtime function. 1486 // Prepare for calling JS runtime function.
2613 __ movq(rax, CodeGenerator::GlobalObject()); 1487 __ movq(rax, CodeGenerator::GlobalObject());
2614 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); 1488 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
2615 } 1489 }
2616 1490
2617 // Push the arguments ("left-to-right"). 1491 // Push the arguments ("left-to-right").
(...skipping 12 matching lines...) Expand all
2630 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1504 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2631 } else { 1505 } else {
2632 __ CallRuntime(expr->function(), arg_count); 1506 __ CallRuntime(expr->function(), arg_count);
2633 } 1507 }
2634 Apply(context_, rax); 1508 Apply(context_, rax);
2635 } 1509 }
2636 1510
2637 1511
2638 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 1512 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2639 switch (expr->op()) { 1513 switch (expr->op()) {
2640 case Token::DELETE: {
2641 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2642 Property* prop = expr->expression()->AsProperty();
2643 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2644 if (prop == NULL && var == NULL) {
2645 // Result of deleting non-property, non-variable reference is true.
2646 // The subexpression may have side effects.
2647 VisitForEffect(expr->expression());
2648 Apply(context_, true);
2649 } else if (var != NULL &&
2650 !var->is_global() &&
2651 var->slot() != NULL &&
2652 var->slot()->type() != Slot::LOOKUP) {
2653 // Result of deleting non-global, non-dynamic variables is false.
2654 // The subexpression does not have side effects.
2655 Apply(context_, false);
2656 } else {
2657 // Property or variable reference. Call the delete builtin with
2658 // object and property name as arguments.
2659 if (prop != NULL) {
2660 VisitForValue(prop->obj(), kStack);
2661 VisitForValue(prop->key(), kStack);
2662 } else if (var->is_global()) {
2663 __ push(CodeGenerator::GlobalObject());
2664 __ Push(var->name());
2665 } else {
2666 // Non-global variable. Call the runtime to look up the context
2667 // where the variable was introduced.
2668 __ push(context_register());
2669 __ Push(var->name());
2670 __ CallRuntime(Runtime::kLookupContext, 2);
2671 __ push(rax);
2672 __ Push(var->name());
2673 }
2674 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
2675 Apply(context_, rax);
2676 }
2677 break;
2678 }
2679
2680 case Token::VOID: { 1514 case Token::VOID: {
2681 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 1515 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2682 VisitForEffect(expr->expression()); 1516 VisitForEffect(expr->expression());
2683 switch (context_) { 1517 switch (context_) {
2684 case Expression::kUninitialized: 1518 case Expression::kUninitialized:
2685 UNREACHABLE(); 1519 UNREACHABLE();
2686 break; 1520 break;
2687 case Expression::kEffect: 1521 case Expression::kEffect:
2688 break; 1522 break;
2689 case Expression::kValue: 1523 case Expression::kValue:
(...skipping 20 matching lines...) Expand all
2710 case Expression::kTest: 1544 case Expression::kTest:
2711 case Expression::kValueTest: 1545 case Expression::kValueTest:
2712 __ jmp(false_label_); 1546 __ jmp(false_label_);
2713 break; 1547 break;
2714 } 1548 }
2715 break; 1549 break;
2716 } 1550 }
2717 1551
2718 case Token::NOT: { 1552 case Token::NOT: {
2719 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 1553 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
2720 Label materialize_true, materialize_false; 1554 Label materialize_true, materialize_false, done;
2721 Label* if_true = NULL; 1555 // Initially assume a pure test context. Notice that the labels are
2722 Label* if_false = NULL; 1556 // swapped.
2723 1557 Label* if_true = false_label_;
2724 // Notice that the labels are swapped. 1558 Label* if_false = true_label_;
2725 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true); 1559 switch (context_) {
2726 1560 case Expression::kUninitialized:
1561 UNREACHABLE();
1562 break;
1563 case Expression::kEffect:
1564 if_true = &done;
1565 if_false = &done;
1566 break;
1567 case Expression::kValue:
1568 if_true = &materialize_false;
1569 if_false = &materialize_true;
1570 break;
1571 case Expression::kTest:
1572 break;
1573 case Expression::kValueTest:
1574 if_false = &materialize_true;
1575 break;
1576 case Expression::kTestValue:
1577 if_true = &materialize_false;
1578 break;
1579 }
2727 VisitForControl(expr->expression(), if_true, if_false); 1580 VisitForControl(expr->expression(), if_true, if_false);
2728
2729 Apply(context_, if_false, if_true); // Labels swapped. 1581 Apply(context_, if_false, if_true); // Labels swapped.
2730 break; 1582 break;
2731 } 1583 }
2732 1584
2733 case Token::TYPEOF: { 1585 case Token::TYPEOF: {
2734 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 1586 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
2735 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 1587 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2736 if (proxy != NULL && 1588 if (proxy != NULL &&
2737 !proxy->var()->is_this() && 1589 !proxy->var()->is_this() &&
2738 proxy->var()->is_global()) { 1590 proxy->var()->is_global()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2814 1666
2815 default: 1667 default:
2816 UNREACHABLE(); 1668 UNREACHABLE();
2817 } 1669 }
2818 } 1670 }
2819 1671
2820 1672
2821 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 1673 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
2822 Comment cmnt(masm_, "[ CountOperation"); 1674 Comment cmnt(masm_, "[ CountOperation");
2823 1675
2824 // Invalid left-hand-sides are rewritten to have a 'throw
2825 // ReferenceError' as the left-hand side.
2826 if (!expr->expression()->IsValidLeftHandSide()) {
2827 VisitForEffect(expr->expression());
2828 return;
2829 }
2830
2831 // Expression can only be a property, a global or a (parameter or local) 1676 // Expression can only be a property, a global or a (parameter or local)
2832 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1677 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
2833 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1678 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2834 LhsKind assign_type = VARIABLE; 1679 LhsKind assign_type = VARIABLE;
2835 Property* prop = expr->expression()->AsProperty(); 1680 Property* prop = expr->expression()->AsProperty();
2836 // In case of a property we use the uninitialized expression context 1681 // In case of a property we use the uninitialized expression context
2837 // of the key to detect a named property. 1682 // of the key to detect a named property.
2838 if (prop != NULL) { 1683 if (prop != NULL) {
2839 assign_type = 1684 assign_type =
2840 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1685 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
2841 } 1686 }
2842 1687
2843 // Evaluate expression and get value. 1688 // Evaluate expression and get value.
2844 if (assign_type == VARIABLE) { 1689 if (assign_type == VARIABLE) {
2845 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 1690 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
2846 Location saved_location = location_; 1691 Location saved_location = location_;
2847 location_ = kAccumulator; 1692 location_ = kAccumulator;
2848 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 1693 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
2849 Expression::kValue); 1694 Expression::kValue);
2850 location_ = saved_location; 1695 location_ = saved_location;
2851 } else { 1696 } else {
2852 // Reserve space for result of postfix operation. 1697 // Reserve space for result of postfix operation.
2853 if (expr->is_postfix() && context_ != Expression::kEffect) { 1698 if (expr->is_postfix() && context_ != Expression::kEffect) {
2854 __ Push(Smi::FromInt(0)); 1699 __ Push(Smi::FromInt(0));
2855 } 1700 }
2856 VisitForValue(prop->obj(), kStack); 1701 VisitForValue(prop->obj(), kStack);
2857 if (assign_type == NAMED_PROPERTY) { 1702 if (assign_type == NAMED_PROPERTY) {
2858 EmitNamedPropertyLoad(prop); 1703 EmitNamedPropertyLoad(prop);
2859 } else { 1704 } else {
2860 VisitForValue(prop->key(), kStack); 1705 VisitForValue(prop->key(), kStack);
2861 EmitKeyedPropertyLoad(prop); 1706 EmitKeyedPropertyLoad(prop);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
3013 VisitForValue(expr->right(), kAccumulator); 1858 VisitForValue(expr->right(), kAccumulator);
3014 EmitBinaryOp(expr->op(), context_); 1859 EmitBinaryOp(expr->op(), context_);
3015 break; 1860 break;
3016 1861
3017 default: 1862 default:
3018 UNREACHABLE(); 1863 UNREACHABLE();
3019 } 1864 }
3020 } 1865 }
3021 1866
3022 1867
3023 void FullCodeGenerator::EmitNullCompare(bool strict,
3024 Register obj,
3025 Register null_const,
3026 Label* if_true,
3027 Label* if_false,
3028 Register scratch) {
3029 __ cmpq(obj, null_const);
3030 if (strict) {
3031 __ j(equal, if_true);
3032 } else {
3033 __ j(equal, if_true);
3034 __ CompareRoot(obj, Heap::kUndefinedValueRootIndex);
3035 __ j(equal, if_true);
3036 __ JumpIfSmi(obj, if_false);
3037 // It can be an undetectable object.
3038 __ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset));
3039 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
3040 Immediate(1 << Map::kIsUndetectable));
3041 __ j(not_zero, if_true);
3042 }
3043 __ jmp(if_false);
3044 }
3045
3046
3047
3048 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 1868 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3049 Comment cmnt(masm_, "[ CompareOperation"); 1869 Comment cmnt(masm_, "[ CompareOperation");
3050 1870
3051 // Always perform the comparison for its control flow. Pack the result 1871 // Always perform the comparison for its control flow. Pack the result
3052 // into the expression's context after the comparison is performed. 1872 // into the expression's context after the comparison is performed.
3053 Label materialize_true, materialize_false; 1873 Label materialize_true, materialize_false, done;
3054 Label* if_true = NULL; 1874 // Initially assume we are in a test context.
3055 Label* if_false = NULL; 1875 Label* if_true = true_label_;
3056 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false); 1876 Label* if_false = false_label_;
1877 switch (context_) {
1878 case Expression::kUninitialized:
1879 UNREACHABLE();
1880 break;
1881 case Expression::kEffect:
1882 if_true = &done;
1883 if_false = &done;
1884 break;
1885 case Expression::kValue:
1886 if_true = &materialize_true;
1887 if_false = &materialize_false;
1888 break;
1889 case Expression::kTest:
1890 break;
1891 case Expression::kValueTest:
1892 if_true = &materialize_true;
1893 break;
1894 case Expression::kTestValue:
1895 if_false = &materialize_false;
1896 break;
1897 }
3057 1898
3058 VisitForValue(expr->left(), kStack); 1899 VisitForValue(expr->left(), kStack);
3059 switch (expr->op()) { 1900 switch (expr->op()) {
3060 case Token::IN: 1901 case Token::IN:
3061 VisitForValue(expr->right(), kStack); 1902 VisitForValue(expr->right(), kStack);
3062 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 1903 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
3063 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 1904 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
3064 __ j(equal, if_true); 1905 __ j(equal, if_true);
3065 __ jmp(if_false); 1906 __ jmp(if_false);
3066 break; 1907 break;
3067 1908
3068 case Token::INSTANCEOF: { 1909 case Token::INSTANCEOF: {
3069 VisitForValue(expr->right(), kStack); 1910 VisitForValue(expr->right(), kStack);
3070 InstanceofStub stub; 1911 InstanceofStub stub;
3071 __ CallStub(&stub); 1912 __ CallStub(&stub);
3072 __ testq(rax, rax); 1913 __ testq(rax, rax);
3073 __ j(zero, if_true); // The stub returns 0 for true. 1914 __ j(zero, if_true); // The stub returns 0 for true.
3074 __ jmp(if_false); 1915 __ jmp(if_false);
3075 break; 1916 break;
3076 } 1917 }
3077 1918
3078 default: { 1919 default: {
3079 VisitForValue(expr->right(), kAccumulator); 1920 VisitForValue(expr->right(), kAccumulator);
3080 Condition cc = no_condition; 1921 Condition cc = no_condition;
3081 bool strict = false; 1922 bool strict = false;
3082 switch (expr->op()) { 1923 switch (expr->op()) {
3083 case Token::EQ_STRICT: 1924 case Token::EQ_STRICT:
3084 strict = true; 1925 strict = true;
3085 // Fall through. 1926 // Fall through.
3086 case Token::EQ: { 1927 case Token::EQ:
3087 cc = equal; 1928 cc = equal;
3088 __ pop(rdx); 1929 __ pop(rdx);
3089 // If either operand is constant null we do a fast compare
3090 // against null.
3091 Literal* right_literal = expr->right()->AsLiteral();
3092 Literal* left_literal = expr->left()->AsLiteral();
3093 if (right_literal != NULL && right_literal->handle()->IsNull()) {
3094 EmitNullCompare(strict, rdx, rax, if_true, if_false, rcx);
3095 Apply(context_, if_true, if_false);
3096 return;
3097 } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3098 EmitNullCompare(strict, rax, rdx, if_true, if_false, rcx);
3099 Apply(context_, if_true, if_false);
3100 return;
3101 }
3102 break; 1930 break;
3103 }
3104 case Token::LT: 1931 case Token::LT:
3105 cc = less; 1932 cc = less;
3106 __ pop(rdx); 1933 __ pop(rdx);
3107 break; 1934 break;
3108 case Token::GT: 1935 case Token::GT:
3109 // Reverse left and right sizes to obtain ECMA-262 conversion order. 1936 // Reverse left and right sizes to obtain ECMA-262 conversion order.
3110 cc = less; 1937 cc = less;
3111 __ movq(rdx, result_register()); 1938 __ movq(rdx, result_register());
3112 __ pop(rax); 1939 __ pop(rax);
3113 break; 1940 break;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
3206 __ ret(0); 2033 __ ret(0);
3207 } 2034 }
3208 2035
3209 2036
3210 #undef __ 2037 #undef __
3211 2038
3212 2039
3213 } } // namespace v8::internal 2040 } } // namespace v8::internal
3214 2041
3215 #endif // V8_TARGET_ARCH_X64 2042 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.cc ('k') | src/x64/ic-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698