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

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

Issue 2078022: Complete the full codegenerator on x64. (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/macro-assembler-x64.h » ('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 if (scope()->num_heap_slots() > 0) { 84 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
85 if (heap_slots > 0) {
85 Comment cmnt(masm_, "[ Allocate local context"); 86 Comment cmnt(masm_, "[ Allocate local context");
86 // Argument to NewContext is the function, which is still in rdi. 87 // Argument to NewContext is the function, which is still in rdi.
87 __ push(rdi); 88 __ push(rdi);
88 __ 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 }
89 function_in_register = false; 95 function_in_register = false;
90 // 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
91 // 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.
92 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); 98 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
93 99
94 // Copy any necessary parameters into the context. 100 // Copy any necessary parameters into the context.
95 int num_parameters = scope()->num_parameters(); 101 int num_parameters = scope()->num_parameters();
96 for (int i = 0; i < num_parameters; i++) { 102 for (int i = 0; i < num_parameters; i++) {
97 Slot* slot = scope()->parameter(i)->slot(); 103 Slot* slot = scope()->parameter(i)->slot();
98 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
138 // Store new arguments object in both "arguments" and ".arguments" slots. 144 // Store new arguments object in both "arguments" and ".arguments" slots.
139 __ movq(rcx, rax); 145 __ movq(rcx, rax);
140 Move(arguments->slot(), rax, rbx, rdx); 146 Move(arguments->slot(), rax, rbx, rdx);
141 Slot* dot_arguments_slot = 147 Slot* dot_arguments_slot =
142 scope()->arguments_shadow()->AsVariable()->slot(); 148 scope()->arguments_shadow()->AsVariable()->slot();
143 Move(dot_arguments_slot, rcx, rbx, rdx); 149 Move(dot_arguments_slot, rcx, rbx, rdx);
144 } 150 }
145 } 151 }
146 152
147 { Comment cmnt(masm_, "[ Declarations"); 153 { Comment cmnt(masm_, "[ Declarations");
148 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 }
149 } 166 }
150 167
151 { Comment cmnt(masm_, "[ Stack check"); 168 { Comment cmnt(masm_, "[ Stack check");
152 Label ok; 169 Label ok;
153 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 170 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
154 __ j(above_equal, &ok); 171 __ j(above_equal, &ok);
155 StackCheckStub stub; 172 StackCheckStub stub;
156 __ CallStub(&stub); 173 __ CallStub(&stub);
157 __ bind(&ok); 174 __ bind(&ok);
158 } 175 }
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 __ movq(result_register(), reg); 439 __ movq(result_register(), reg);
423 __ movq(Operand(rsp, 0), result_register()); 440 __ movq(Operand(rsp, 0), result_register());
424 break; 441 break;
425 } 442 }
426 DoTest(context); 443 DoTest(context);
427 break; 444 break;
428 } 445 }
429 } 446 }
430 447
431 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
432 void FullCodeGenerator::Apply(Expression::Context context, 482 void FullCodeGenerator::Apply(Expression::Context context,
433 Label* materialize_true, 483 Label* materialize_true,
434 Label* materialize_false) { 484 Label* materialize_false) {
435 switch (context) { 485 switch (context) {
436 case Expression::kUninitialized: 486 case Expression::kUninitialized:
437 487
438 case Expression::kEffect: 488 case Expression::kEffect:
439 ASSERT_EQ(materialize_true, materialize_false); 489 ASSERT_EQ(materialize_true, materialize_false);
440 __ bind(materialize_true); 490 __ bind(materialize_true);
441 break; 491 break;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 case kStack: 537 case kStack:
488 __ Push(Factory::false_value()); 538 __ Push(Factory::false_value());
489 break; 539 break;
490 } 540 }
491 __ jmp(false_label_); 541 __ jmp(false_label_);
492 break; 542 break;
493 } 543 }
494 } 544 }
495 545
496 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
497 void FullCodeGenerator::DoTest(Expression::Context context) { 602 void FullCodeGenerator::DoTest(Expression::Context context) {
498 // 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
499 // 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
500 // desired), then the value is already duplicated on the stack. 605 // desired), then the value is already duplicated on the stack.
501 ASSERT_NE(NULL, true_label_); 606 ASSERT_NE(NULL, true_label_);
502 ASSERT_NE(NULL, false_label_); 607 ASSERT_NE(NULL, false_label_);
503 608
504 // 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
505 // 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
506 // 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
662 MemOperand location = EmitSlotSearch(dst, scratch1); 767 MemOperand location = EmitSlotSearch(dst, scratch1);
663 __ movq(location, src); 768 __ movq(location, src);
664 // 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.
665 if (dst->type() == Slot::CONTEXT) { 770 if (dst->type() == Slot::CONTEXT) {
666 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 771 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
667 __ RecordWrite(scratch1, offset, src, scratch2); 772 __ RecordWrite(scratch1, offset, src, scratch2);
668 } 773 }
669 } 774 }
670 775
671 776
672 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 777 void FullCodeGenerator::EmitDeclaration(Variable* variable,
778 Variable::Mode mode,
779 FunctionLiteral* function) {
673 Comment cmnt(masm_, "[ Declaration"); 780 Comment cmnt(masm_, "[ Declaration");
674 Variable* var = decl->proxy()->var(); 781 ASSERT(variable != NULL); // Must have been resolved.
675 ASSERT(var != NULL); // Must have been resolved. 782 Slot* slot = variable->slot();
676 Slot* slot = var->slot(); 783 Property* prop = variable->AsProperty();
677 Property* prop = var->AsProperty();
678 784
679 if (slot != NULL) { 785 if (slot != NULL) {
680 switch (slot->type()) { 786 switch (slot->type()) {
681 case Slot::PARAMETER: 787 case Slot::PARAMETER:
682 case Slot::LOCAL: 788 case Slot::LOCAL:
683 if (decl->mode() == Variable::CONST) { 789 if (mode == Variable::CONST) {
684 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 790 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
685 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister); 791 __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
686 } else if (decl->fun() != NULL) { 792 } else if (function != NULL) {
687 VisitForValue(decl->fun(), kAccumulator); 793 VisitForValue(function, kAccumulator);
688 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); 794 __ movq(Operand(rbp, SlotOffset(slot)), result_register());
689 } 795 }
690 break; 796 break;
691 797
692 case Slot::CONTEXT: 798 case Slot::CONTEXT:
693 // We bypass the general EmitSlotSearch because we know more about 799 // We bypass the general EmitSlotSearch because we know more about
694 // this specific context. 800 // this specific context.
695 801
696 // The variable in the decl always resides in the current context. 802 // The variable in the decl always resides in the current context.
697 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); 803 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
698 if (FLAG_debug_code) { 804 if (FLAG_debug_code) {
699 // Check if we have the correct context pointer. 805 // Check if we have the correct context pointer.
700 __ movq(rbx, 806 __ movq(rbx,
701 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); 807 CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX));
702 __ cmpq(rbx, rsi); 808 __ cmpq(rbx, rsi);
703 __ Check(equal, "Unexpected declaration in current context."); 809 __ Check(equal, "Unexpected declaration in current context.");
704 } 810 }
705 if (decl->mode() == Variable::CONST) { 811 if (mode == Variable::CONST) {
706 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); 812 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
707 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 813 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
708 kScratchRegister); 814 kScratchRegister);
709 // No write barrier since the hole value is in old space. 815 // No write barrier since the hole value is in old space.
710 } else if (decl->fun() != NULL) { 816 } else if (function != NULL) {
711 VisitForValue(decl->fun(), kAccumulator); 817 VisitForValue(function, kAccumulator);
712 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), 818 __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
713 result_register()); 819 result_register());
714 int offset = Context::SlotOffset(slot->index()); 820 int offset = Context::SlotOffset(slot->index());
715 __ movq(rbx, rsi); 821 __ movq(rbx, rsi);
716 __ RecordWrite(rbx, offset, result_register(), rcx); 822 __ RecordWrite(rbx, offset, result_register(), rcx);
717 } 823 }
718 break; 824 break;
719 825
720 case Slot::LOOKUP: { 826 case Slot::LOOKUP: {
721 __ push(rsi); 827 __ push(rsi);
722 __ Push(var->name()); 828 __ Push(variable->name());
723 // Declaration nodes are always introduced in one of two modes. 829 // Declaration nodes are always introduced in one of two modes.
724 ASSERT(decl->mode() == Variable::VAR || 830 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
725 decl->mode() == Variable::CONST); 831 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
726 PropertyAttributes attr =
727 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
728 __ Push(Smi::FromInt(attr)); 832 __ Push(Smi::FromInt(attr));
729 // Push initial value, if any. 833 // Push initial value, if any.
730 // 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
731 // 'undefined') because we may have a (legal) redeclaration and we 835 // 'undefined') because we may have a (legal) redeclaration and we
732 // must not destroy the current value. 836 // must not destroy the current value.
733 if (decl->mode() == Variable::CONST) { 837 if (mode == Variable::CONST) {
734 __ PushRoot(Heap::kTheHoleValueRootIndex); 838 __ PushRoot(Heap::kTheHoleValueRootIndex);
735 } else if (decl->fun() != NULL) { 839 } else if (function != NULL) {
736 VisitForValue(decl->fun(), kStack); 840 VisitForValue(function, kStack);
737 } else { 841 } else {
738 __ Push(Smi::FromInt(0)); // no initial value! 842 __ Push(Smi::FromInt(0)); // no initial value!
739 } 843 }
740 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 844 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
741 break; 845 break;
742 } 846 }
743 } 847 }
744 848
745 } else if (prop != NULL) { 849 } else if (prop != NULL) {
746 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { 850 if (function != NULL || mode == Variable::CONST) {
747 // We are declaring a function or constant that rewrites to a 851 // We are declaring a function or constant that rewrites to a
748 // property. Use (keyed) IC to set the initial value. 852 // property. Use (keyed) IC to set the initial value.
749 VisitForValue(prop->obj(), kStack); 853 VisitForValue(prop->obj(), kStack);
750 VisitForValue(prop->key(), kStack); 854 VisitForValue(prop->key(), kStack);
751 855
752 if (decl->fun() != NULL) { 856 if (function != NULL) {
753 VisitForValue(decl->fun(), kAccumulator); 857 VisitForValue(function, kAccumulator);
754 } else { 858 } else {
755 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex); 859 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
756 } 860 }
757 861
758 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 862 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
759 __ call(ic, RelocInfo::CODE_TARGET); 863 __ call(ic, RelocInfo::CODE_TARGET);
760 // Absence of a test rax instruction following the call 864 // Absence of a test rax instruction following the call
761 // indicates that none of the load was inlined. 865 // indicates that none of the load was inlined.
762 __ nop(); 866 __ nop();
763 867
764 // Value in rax is ignored (declarations are statements). Receiver 868 // Value in rax is ignored (declarations are statements). Receiver
765 // and key on stack are discarded. 869 // and key on stack are discarded.
766 __ Drop(2); 870 __ Drop(2);
767 } 871 }
768 } 872 }
769 } 873 }
770 874
771 875
876 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
877 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
878 }
879
880
772 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 881 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
773 // Call the runtime to declare the globals. 882 // Call the runtime to declare the globals.
774 __ push(rsi); // The context is the first argument. 883 __ push(rsi); // The context is the first argument.
775 __ Push(pairs); 884 __ Push(pairs);
776 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); 885 __ Push(Smi::FromInt(is_eval() ? 1 : 0));
777 __ CallRuntime(Runtime::kDeclareGlobals, 3); 886 __ CallRuntime(Runtime::kDeclareGlobals, 3);
778 // Return value is ignored. 887 // Return value is ignored.
779 } 888 }
780 889
781 890
782 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 891 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
783 UNREACHABLE(); 892 Comment cmnt(masm_, "[ SwitchStatement");
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());
784 } 956 }
785 957
786 958
787 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 959 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
788 UNREACHABLE(); 960 Comment cmnt(masm_, "[ ForInStatement");
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();
789 } 1094 }
790 1095
791 1096
792 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { 1097 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
793 // Use the fast case closure allocation code that allocates in new 1098 // Use the fast case closure allocation code that allocates in new
794 // space for nested functions that don't need literals cloning. 1099 // space for nested functions that don't need literals cloning.
795 if (scope()->is_function_scope() && info->num_literals() == 0) { 1100 if (scope()->is_function_scope() && info->num_literals() == 0) {
796 FastNewClosureStub stub; 1101 FastNewClosureStub stub;
797 __ Push(info); 1102 __ Push(info);
798 __ CallStub(&stub); 1103 __ CallStub(&stub);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 Comment cmnt(masm_, "Lookup slot"); 1142 Comment cmnt(masm_, "Lookup slot");
838 __ push(rsi); // Context. 1143 __ push(rsi); // Context.
839 __ Push(var->name()); 1144 __ Push(var->name());
840 __ CallRuntime(Runtime::kLoadContextSlot, 2); 1145 __ CallRuntime(Runtime::kLoadContextSlot, 2);
841 Apply(context, rax); 1146 Apply(context, rax);
842 1147
843 } else if (slot != NULL) { 1148 } else if (slot != NULL) {
844 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 1149 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
845 ? "Context slot" 1150 ? "Context slot"
846 : "Stack slot"); 1151 : "Stack slot");
847 Apply(context, slot); 1152 if (var->mode() == Variable::CONST) {
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 }
848 1166
849 } else { 1167 } else {
850 Comment cmnt(masm_, "Rewritten parameter"); 1168 Comment cmnt(masm_, "Rewritten parameter");
851 ASSERT_NOT_NULL(property); 1169 ASSERT_NOT_NULL(property);
852 // Rewritten parameter accesses are of the form "slot[literal]". 1170 // Rewritten parameter accesses are of the form "slot[literal]".
853 1171
854 // Assert that the object is in a slot. 1172 // Assert that the object is in a slot.
855 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 1173 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
856 ASSERT_NOT_NULL(object_var); 1174 ASSERT_NOT_NULL(object_var);
857 Slot* object_slot = object_var->slot(); 1175 Slot* object_slot = object_var->slot();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 if (result_saved) { 1291 if (result_saved) {
974 ApplyTOS(context_); 1292 ApplyTOS(context_);
975 } else { 1293 } else {
976 Apply(context_, rax); 1294 Apply(context_, rax);
977 } 1295 }
978 } 1296 }
979 1297
980 1298
981 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1299 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
982 Comment cmnt(masm_, "[ ArrayLiteral"); 1300 Comment cmnt(masm_, "[ ArrayLiteral");
1301
1302 ZoneList<Expression*>* subexprs = expr->values();
1303 int length = subexprs->length();
1304
983 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 1305 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
984 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); 1306 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
985 __ Push(Smi::FromInt(expr->literal_index())); 1307 __ Push(Smi::FromInt(expr->literal_index()));
986 __ Push(expr->constant_elements()); 1308 __ Push(expr->constant_elements());
987 if (expr->depth() > 1) { 1309 if (expr->depth() > 1) {
988 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 1310 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1311 } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
1312 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
989 } else { 1313 } else {
990 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 1314 FastCloneShallowArrayStub stub(length);
1315 __ CallStub(&stub);
991 } 1316 }
992 1317
993 bool result_saved = false; // Is the result saved to the stack? 1318 bool result_saved = false; // Is the result saved to the stack?
994 1319
995 // Emit code to evaluate all the non-constant subexpressions and to store 1320 // Emit code to evaluate all the non-constant subexpressions and to store
996 // them into the newly cloned array. 1321 // them into the newly cloned array.
997 ZoneList<Expression*>* subexprs = expr->values(); 1322 for (int i = 0; i < length; i++) {
998 for (int i = 0, len = subexprs->length(); i < len; i++) {
999 Expression* subexpr = subexprs->at(i); 1323 Expression* subexpr = subexprs->at(i);
1000 // If the subexpression is a literal or a simple materialized literal it 1324 // If the subexpression is a literal or a simple materialized literal it
1001 // is already set in the cloned array. 1325 // is already set in the cloned array.
1002 if (subexpr->AsLiteral() != NULL || 1326 if (subexpr->AsLiteral() != NULL ||
1003 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1327 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1004 continue; 1328 continue;
1005 } 1329 }
1006 1330
1007 if (!result_saved) { 1331 if (!result_saved) {
1008 __ push(rax); 1332 __ push(rax);
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 Expression::Context context) { 1474 Expression::Context context) {
1151 __ push(result_register()); 1475 __ push(result_register());
1152 GenericBinaryOpStub stub(op, 1476 GenericBinaryOpStub stub(op,
1153 NO_OVERWRITE, 1477 NO_OVERWRITE,
1154 NO_GENERIC_BINARY_FLAGS); 1478 NO_GENERIC_BINARY_FLAGS);
1155 __ CallStub(&stub); 1479 __ CallStub(&stub);
1156 Apply(context, rax); 1480 Apply(context, rax);
1157 } 1481 }
1158 1482
1159 1483
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
1160 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1535 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1161 Token::Value op, 1536 Token::Value op,
1162 Expression::Context context) { 1537 Expression::Context context) {
1163 // Left-hand sides that rewrite to explicit property accesses do not reach 1538 // Left-hand sides that rewrite to explicit property accesses do not reach
1164 // here. 1539 // here.
1165 ASSERT(var != NULL); 1540 ASSERT(var != NULL);
1166 ASSERT(var->is_global() || var->slot() != NULL); 1541 ASSERT(var->is_global() || var->slot() != NULL);
1167 1542
1168 if (var->is_global()) { 1543 if (var->is_global()) {
1169 ASSERT(!var->is_this()); 1544 ASSERT(!var->is_this());
(...skipping 10 matching lines...) Expand all
1180 // Perform the assignment for non-const variables and for initialization 1555 // Perform the assignment for non-const variables and for initialization
1181 // of const variables. Const assignments are simply skipped. 1556 // of const variables. Const assignments are simply skipped.
1182 Label done; 1557 Label done;
1183 Slot* slot = var->slot(); 1558 Slot* slot = var->slot();
1184 switch (slot->type()) { 1559 switch (slot->type()) {
1185 case Slot::PARAMETER: 1560 case Slot::PARAMETER:
1186 case Slot::LOCAL: 1561 case Slot::LOCAL:
1187 if (op == Token::INIT_CONST) { 1562 if (op == Token::INIT_CONST) {
1188 // Detect const reinitialization by checking for the hole value. 1563 // Detect const reinitialization by checking for the hole value.
1189 __ movq(rdx, Operand(rbp, SlotOffset(slot))); 1564 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1190 __ Cmp(rdx, Factory::the_hole_value()); 1565 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1191 __ j(not_equal, &done); 1566 __ j(not_equal, &done);
1192 } 1567 }
1193 // Perform the assignment. 1568 // Perform the assignment.
1194 __ movq(Operand(rbp, SlotOffset(slot)), rax); 1569 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1195 break; 1570 break;
1196 1571
1197 case Slot::CONTEXT: { 1572 case Slot::CONTEXT: {
1198 MemOperand target = EmitSlotSearch(slot, rcx); 1573 MemOperand target = EmitSlotSearch(slot, rcx);
1199 if (op == Token::INIT_CONST) { 1574 if (op == Token::INIT_CONST) {
1200 // Detect const reinitialization by checking for the hole value. 1575 // Detect const reinitialization by checking for the hole value.
1201 __ movq(rdx, target); 1576 __ movq(rdx, target);
1202 __ Cmp(rdx, Factory::the_hole_value()); 1577 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1203 __ j(not_equal, &done); 1578 __ j(not_equal, &done);
1204 } 1579 }
1205 // Perform the assignment and issue the write barrier. 1580 // Perform the assignment and issue the write barrier.
1206 __ movq(target, rax); 1581 __ movq(target, rax);
1207 // The value of the assignment is in rax. RecordWrite clobbers its 1582 // The value of the assignment is in rax. RecordWrite clobbers its
1208 // register arguments. 1583 // register arguments.
1209 __ movq(rdx, rax); 1584 __ movq(rdx, rax);
1210 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1585 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1211 __ RecordWrite(rcx, offset, rdx, rbx); 1586 __ RecordWrite(rcx, offset, rdx, rbx);
1212 break; 1587 break;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1355 1730
1356 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1731 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1357 // Code common for calls using the call stub. 1732 // Code common for calls using the call stub.
1358 ZoneList<Expression*>* args = expr->arguments(); 1733 ZoneList<Expression*>* args = expr->arguments();
1359 int arg_count = args->length(); 1734 int arg_count = args->length();
1360 for (int i = 0; i < arg_count; i++) { 1735 for (int i = 0; i < arg_count; i++) {
1361 VisitForValue(args->at(i), kStack); 1736 VisitForValue(args->at(i), kStack);
1362 } 1737 }
1363 // Record source position for debugger. 1738 // Record source position for debugger.
1364 SetSourcePosition(expr->position()); 1739 SetSourcePosition(expr->position());
1365 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1740 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1741 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1366 __ CallStub(&stub); 1742 __ CallStub(&stub);
1367 // Restore context register. 1743 // Restore context register.
1368 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1744 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1369 // Discard the function left on TOS. 1745 // Discard the function left on TOS.
1370 DropAndApply(1, context_, rax); 1746 DropAndApply(1, context_, rax);
1371 } 1747 }
1372 1748
1373 1749
1374 void FullCodeGenerator::VisitCall(Call* expr) { 1750 void FullCodeGenerator::VisitCall(Call* expr) {
1375 Comment cmnt(masm_, "[ Call"); 1751 Comment cmnt(masm_, "[ Call");
1376 Expression* fun = expr->expression(); 1752 Expression* fun = expr->expression();
1377 Variable* var = fun->AsVariableProxy()->AsVariable(); 1753 Variable* var = fun->AsVariableProxy()->AsVariable();
1378 1754
1379 if (var != NULL && var->is_possibly_eval()) { 1755 if (var != NULL && var->is_possibly_eval()) {
1380 // Call to the identifier 'eval'. 1756 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1381 UNREACHABLE(); 1757 // resolve the function we need to call and the receiver of the
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);
1382 } else if (var != NULL && !var->is_this() && var->is_global()) { 1797 } else if (var != NULL && !var->is_this() && var->is_global()) {
1383 // Call to a global variable. 1798 // Call to a global variable.
1384 // Push global object as receiver for the call IC lookup. 1799 // Push global object as receiver for the call IC lookup.
1385 __ push(CodeGenerator::GlobalObject()); 1800 __ push(CodeGenerator::GlobalObject());
1386 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1801 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1387 } else if (var != NULL && var->slot() != NULL && 1802 } else if (var != NULL && var->slot() != NULL &&
1388 var->slot()->type() == Slot::LOOKUP) { 1803 var->slot()->type() == Slot::LOOKUP) {
1389 // Call to a lookup slot. 1804 // Call to a lookup slot (dynamically introduced variable). Call
1390 UNREACHABLE(); 1805 // the runtime to find the function to call (returned in rax) and
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);
1391 } else if (fun->AsProperty() != NULL) { 1813 } else if (fun->AsProperty() != NULL) {
1392 // Call to an object property. 1814 // Call to an object property.
1393 Property* prop = fun->AsProperty(); 1815 Property* prop = fun->AsProperty();
1394 Literal* key = prop->key()->AsLiteral(); 1816 Literal* key = prop->key()->AsLiteral();
1395 if (key != NULL && key->handle()->IsSymbol()) { 1817 if (key != NULL && key->handle()->IsSymbol()) {
1396 // Call to a named property, use call IC. 1818 // Call to a named property, use call IC.
1397 VisitForValue(prop->obj(), kStack); 1819 VisitForValue(prop->obj(), kStack);
1398 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1820 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1399 } else { 1821 } else {
1400 // Call to a keyed property, use keyed load IC followed by function 1822 // Call to a keyed property, use keyed load IC followed by function
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1471 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize)); 1893 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
1472 1894
1473 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1895 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1474 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1896 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1475 1897
1476 // Replace function on TOS with result in rax, or pop it. 1898 // Replace function on TOS with result in rax, or pop it.
1477 DropAndApply(1, context_, rax); 1899 DropAndApply(1, context_, rax);
1478 } 1900 }
1479 1901
1480 1902
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
1481 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2600 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
1482 Comment cmnt(masm_, "[ CallRuntime"); 2608 Comment cmnt(masm_, "[ CallRuntime");
1483 ZoneList<Expression*>* args = expr->arguments(); 2609 ZoneList<Expression*>* args = expr->arguments();
1484 2610
1485 if (expr->is_jsruntime()) { 2611 if (expr->is_jsruntime()) {
1486 // Prepare for calling JS runtime function. 2612 // Prepare for calling JS runtime function.
1487 __ movq(rax, CodeGenerator::GlobalObject()); 2613 __ movq(rax, CodeGenerator::GlobalObject());
1488 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); 2614 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
1489 } 2615 }
1490 2616
1491 // Push the arguments ("left-to-right"). 2617 // Push the arguments ("left-to-right").
(...skipping 12 matching lines...) Expand all
1504 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2630 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1505 } else { 2631 } else {
1506 __ CallRuntime(expr->function(), arg_count); 2632 __ CallRuntime(expr->function(), arg_count);
1507 } 2633 }
1508 Apply(context_, rax); 2634 Apply(context_, rax);
1509 } 2635 }
1510 2636
1511 2637
1512 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 2638 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1513 switch (expr->op()) { 2639 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
1514 case Token::VOID: { 2680 case Token::VOID: {
1515 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 2681 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1516 VisitForEffect(expr->expression()); 2682 VisitForEffect(expr->expression());
1517 switch (context_) { 2683 switch (context_) {
1518 case Expression::kUninitialized: 2684 case Expression::kUninitialized:
1519 UNREACHABLE(); 2685 UNREACHABLE();
1520 break; 2686 break;
1521 case Expression::kEffect: 2687 case Expression::kEffect:
1522 break; 2688 break;
1523 case Expression::kValue: 2689 case Expression::kValue:
(...skipping 20 matching lines...) Expand all
1544 case Expression::kTest: 2710 case Expression::kTest:
1545 case Expression::kValueTest: 2711 case Expression::kValueTest:
1546 __ jmp(false_label_); 2712 __ jmp(false_label_);
1547 break; 2713 break;
1548 } 2714 }
1549 break; 2715 break;
1550 } 2716 }
1551 2717
1552 case Token::NOT: { 2718 case Token::NOT: {
1553 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 2719 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1554 Label materialize_true, materialize_false, done; 2720 Label materialize_true, materialize_false;
1555 // Initially assume a pure test context. Notice that the labels are 2721 Label* if_true = NULL;
1556 // swapped. 2722 Label* if_false = NULL;
1557 Label* if_true = false_label_; 2723
1558 Label* if_false = true_label_; 2724 // Notice that the labels are swapped.
1559 switch (context_) { 2725 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
1560 case Expression::kUninitialized: 2726
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 }
1580 VisitForControl(expr->expression(), if_true, if_false); 2727 VisitForControl(expr->expression(), if_true, if_false);
2728
1581 Apply(context_, if_false, if_true); // Labels swapped. 2729 Apply(context_, if_false, if_true); // Labels swapped.
1582 break; 2730 break;
1583 } 2731 }
1584 2732
1585 case Token::TYPEOF: { 2733 case Token::TYPEOF: {
1586 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 2734 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1587 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2735 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1588 if (proxy != NULL && 2736 if (proxy != NULL &&
1589 !proxy->var()->is_this() && 2737 !proxy->var()->is_this() &&
1590 proxy->var()->is_global()) { 2738 proxy->var()->is_global()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1666 2814
1667 default: 2815 default:
1668 UNREACHABLE(); 2816 UNREACHABLE();
1669 } 2817 }
1670 } 2818 }
1671 2819
1672 2820
1673 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 2821 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
1674 Comment cmnt(masm_, "[ CountOperation"); 2822 Comment cmnt(masm_, "[ CountOperation");
1675 2823
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
1676 // Expression can only be a property, a global or a (parameter or local) 2831 // Expression can only be a property, a global or a (parameter or local)
1677 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 2832 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1678 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 2833 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1679 LhsKind assign_type = VARIABLE; 2834 LhsKind assign_type = VARIABLE;
1680 Property* prop = expr->expression()->AsProperty(); 2835 Property* prop = expr->expression()->AsProperty();
1681 // In case of a property we use the uninitialized expression context 2836 // In case of a property we use the uninitialized expression context
1682 // of the key to detect a named property. 2837 // of the key to detect a named property.
1683 if (prop != NULL) { 2838 if (prop != NULL) {
1684 assign_type = 2839 assign_type =
1685 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 2840 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1686 } 2841 }
1687 2842
1688 // Evaluate expression and get value. 2843 // Evaluate expression and get value.
1689 if (assign_type == VARIABLE) { 2844 if (assign_type == VARIABLE) {
1690 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 2845 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1691 Location saved_location = location_; 2846 Location saved_location = location_;
1692 location_ = kAccumulator; 2847 location_ = kAccumulator;
1693 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 2848 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1694 Expression::kValue); 2849 Expression::kValue);
1695 location_ = saved_location; 2850 location_ = saved_location;
1696 } else { 2851 } else {
1697 // Reserve space for result of postfix operation. 2852 // Reserve space for result of postfix operation.
1698 if (expr->is_postfix() && context_ != Expression::kEffect) { 2853 if (expr->is_postfix() && context_ != Expression::kEffect) {
1699 __ Push(Smi::FromInt(0)); 2854 __ Push(Smi::FromInt(0));
1700 } 2855 }
1701 VisitForValue(prop->obj(), kStack); 2856 VisitForValue(prop->obj(), kStack);
1702 if (assign_type == NAMED_PROPERTY) { 2857 if (assign_type == NAMED_PROPERTY) {
1703 EmitNamedPropertyLoad(prop); 2858 EmitNamedPropertyLoad(prop);
1704 } else { 2859 } else {
1705 VisitForValue(prop->key(), kStack); 2860 VisitForValue(prop->key(), kStack);
1706 EmitKeyedPropertyLoad(prop); 2861 EmitKeyedPropertyLoad(prop);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
1858 VisitForValue(expr->right(), kAccumulator); 3013 VisitForValue(expr->right(), kAccumulator);
1859 EmitBinaryOp(expr->op(), context_); 3014 EmitBinaryOp(expr->op(), context_);
1860 break; 3015 break;
1861 3016
1862 default: 3017 default:
1863 UNREACHABLE(); 3018 UNREACHABLE();
1864 } 3019 }
1865 } 3020 }
1866 3021
1867 3022
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
1868 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 3048 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1869 Comment cmnt(masm_, "[ CompareOperation"); 3049 Comment cmnt(masm_, "[ CompareOperation");
1870 3050
1871 // Always perform the comparison for its control flow. Pack the result 3051 // Always perform the comparison for its control flow. Pack the result
1872 // into the expression's context after the comparison is performed. 3052 // into the expression's context after the comparison is performed.
1873 Label materialize_true, materialize_false, done; 3053 Label materialize_true, materialize_false;
1874 // Initially assume we are in a test context. 3054 Label* if_true = NULL;
1875 Label* if_true = true_label_; 3055 Label* if_false = NULL;
1876 Label* if_false = false_label_; 3056 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
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 }
1898 3057
1899 VisitForValue(expr->left(), kStack); 3058 VisitForValue(expr->left(), kStack);
1900 switch (expr->op()) { 3059 switch (expr->op()) {
1901 case Token::IN: 3060 case Token::IN:
1902 VisitForValue(expr->right(), kStack); 3061 VisitForValue(expr->right(), kStack);
1903 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 3062 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1904 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 3063 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
1905 __ j(equal, if_true); 3064 __ j(equal, if_true);
1906 __ jmp(if_false); 3065 __ jmp(if_false);
1907 break; 3066 break;
1908 3067
1909 case Token::INSTANCEOF: { 3068 case Token::INSTANCEOF: {
1910 VisitForValue(expr->right(), kStack); 3069 VisitForValue(expr->right(), kStack);
1911 InstanceofStub stub; 3070 InstanceofStub stub;
1912 __ CallStub(&stub); 3071 __ CallStub(&stub);
1913 __ testq(rax, rax); 3072 __ testq(rax, rax);
1914 __ j(zero, if_true); // The stub returns 0 for true. 3073 __ j(zero, if_true); // The stub returns 0 for true.
1915 __ jmp(if_false); 3074 __ jmp(if_false);
1916 break; 3075 break;
1917 } 3076 }
1918 3077
1919 default: { 3078 default: {
1920 VisitForValue(expr->right(), kAccumulator); 3079 VisitForValue(expr->right(), kAccumulator);
1921 Condition cc = no_condition; 3080 Condition cc = no_condition;
1922 bool strict = false; 3081 bool strict = false;
1923 switch (expr->op()) { 3082 switch (expr->op()) {
1924 case Token::EQ_STRICT: 3083 case Token::EQ_STRICT:
1925 strict = true; 3084 strict = true;
1926 // Fall through. 3085 // Fall through.
1927 case Token::EQ: 3086 case Token::EQ: {
1928 cc = equal; 3087 cc = equal;
1929 __ pop(rdx); 3088 __ 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 }
1930 break; 3102 break;
3103 }
1931 case Token::LT: 3104 case Token::LT:
1932 cc = less; 3105 cc = less;
1933 __ pop(rdx); 3106 __ pop(rdx);
1934 break; 3107 break;
1935 case Token::GT: 3108 case Token::GT:
1936 // Reverse left and right sizes to obtain ECMA-262 conversion order. 3109 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1937 cc = less; 3110 cc = less;
1938 __ movq(rdx, result_register()); 3111 __ movq(rdx, result_register());
1939 __ pop(rax); 3112 __ pop(rax);
1940 break; 3113 break;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
2033 __ ret(0); 3206 __ ret(0);
2034 } 3207 }
2035 3208
2036 3209
2037 #undef __ 3210 #undef __
2038 3211
2039 3212
2040 } } // namespace v8::internal 3213 } } // namespace v8::internal
2041 3214
2042 #endif // V8_TARGET_ARCH_X64 3215 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.cc ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698