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

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

Issue 2137008: Reapply r4686: Complete version of full codegen for 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 __ Integer32ToSmi(rax, rax);
1015 __ push(rax); // Enumeration cache length (as smi).
1016 __ Push(Smi::FromInt(0)); // Initial index.
1017 __ jmp(&loop);
1018
1019 // We got a fixed array in register rax. Iterate through that.
1020 __ bind(&fixed_array);
1021 __ Push(Smi::FromInt(0)); // Map (0) - force slow check.
1022 __ push(rax);
1023 __ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
1024 __ Integer32ToSmi(rax, rax);
1025 __ push(rax); // Fixed array length (as smi).
1026 __ Push(Smi::FromInt(0)); // Initial index.
1027
1028 // Generate code for doing the condition check.
1029 __ bind(&loop);
1030 __ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
1031 __ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
1032 __ j(above_equal, loop_statement.break_target());
1033
1034 // Get the current entry of the array into register rbx.
1035 __ movq(rbx, Operand(rsp, 2 * kPointerSize));
1036 SmiIndex index = __ SmiToIndex(rax, rax, kPointerSizeLog2);
1037 __ movq(rbx, FieldOperand(rbx,
1038 index.reg,
1039 index.scale,
1040 FixedArray::kHeaderSize));
1041
1042 // Get the expected map from the stack or a zero map in the
1043 // permanent slow case into register rdx.
1044 __ movq(rdx, Operand(rsp, 3 * kPointerSize));
1045
1046 // Check if the expected map still matches that of the enumerable.
1047 // If not, we have to filter the key.
1048 Label update_each;
1049 __ movq(rcx, Operand(rsp, 4 * kPointerSize));
1050 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
1051 __ j(equal, &update_each);
1052
1053 // Convert the entry to a string or null if it isn't a property
1054 // anymore. If the property has been removed while iterating, we
1055 // just skip it.
1056 __ push(rcx); // Enumerable.
1057 __ push(rbx); // Current entry.
1058 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1059 __ CompareRoot(rax, Heap::kNullValueRootIndex);
1060 __ j(equal, loop_statement.continue_target());
1061 __ movq(rbx, rax);
1062
1063 // Update the 'each' property or variable from the possibly filtered
1064 // entry in register rbx.
1065 __ bind(&update_each);
1066 __ movq(result_register(), rbx);
1067 // Perform the assignment as if via '='.
1068 EmitAssignment(stmt->each());
1069
1070 // Generate code for the body of the loop.
1071 Label stack_limit_hit, stack_check_done;
1072 Visit(stmt->body());
1073
1074 __ StackLimitCheck(&stack_limit_hit);
1075 __ bind(&stack_check_done);
1076
1077 // Generate code for going to the next element by incrementing the
1078 // index (smi) stored on top of the stack.
1079 __ bind(loop_statement.continue_target());
1080 __ SmiAddConstant(Operand(rsp, 0 * kPointerSize), Smi::FromInt(1));
1081 __ jmp(&loop);
1082
1083 // Slow case for the stack limit check.
1084 StackCheckStub stack_check_stub;
1085 __ bind(&stack_limit_hit);
1086 __ CallStub(&stack_check_stub);
1087 __ jmp(&stack_check_done);
1088
1089 // Remove the pointers stored on the stack.
1090 __ bind(loop_statement.break_target());
1091 __ addq(rsp, Immediate(5 * kPointerSize));
1092
1093 // Exit and decrement the loop depth.
1094 __ bind(&exit);
1095 decrement_loop_depth();
789 } 1096 }
790 1097
791 1098
792 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) { 1099 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
793 // Use the fast case closure allocation code that allocates in new 1100 // Use the fast case closure allocation code that allocates in new
794 // space for nested functions that don't need literals cloning. 1101 // space for nested functions that don't need literals cloning.
795 if (scope()->is_function_scope() && info->num_literals() == 0) { 1102 if (scope()->is_function_scope() && info->num_literals() == 0) {
796 FastNewClosureStub stub; 1103 FastNewClosureStub stub;
797 __ Push(info); 1104 __ Push(info);
798 __ CallStub(&stub); 1105 __ CallStub(&stub);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 Comment cmnt(masm_, "Lookup slot"); 1144 Comment cmnt(masm_, "Lookup slot");
838 __ push(rsi); // Context. 1145 __ push(rsi); // Context.
839 __ Push(var->name()); 1146 __ Push(var->name());
840 __ CallRuntime(Runtime::kLoadContextSlot, 2); 1147 __ CallRuntime(Runtime::kLoadContextSlot, 2);
841 Apply(context, rax); 1148 Apply(context, rax);
842 1149
843 } else if (slot != NULL) { 1150 } else if (slot != NULL) {
844 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 1151 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
845 ? "Context slot" 1152 ? "Context slot"
846 : "Stack slot"); 1153 : "Stack slot");
847 Apply(context, slot); 1154 if (var->mode() == Variable::CONST) {
1155 // Constants may be the hole value if they have not been initialized.
1156 // Unhole them.
1157 Label done;
1158 MemOperand slot_operand = EmitSlotSearch(slot, rax);
1159 __ movq(rax, slot_operand);
1160 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1161 __ j(not_equal, &done);
1162 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1163 __ bind(&done);
1164 Apply(context, rax);
1165 } else {
1166 Apply(context, slot);
1167 }
848 1168
849 } else { 1169 } else {
850 Comment cmnt(masm_, "Rewritten parameter"); 1170 Comment cmnt(masm_, "Rewritten parameter");
851 ASSERT_NOT_NULL(property); 1171 ASSERT_NOT_NULL(property);
852 // Rewritten parameter accesses are of the form "slot[literal]". 1172 // Rewritten parameter accesses are of the form "slot[literal]".
853 1173
854 // Assert that the object is in a slot. 1174 // Assert that the object is in a slot.
855 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 1175 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
856 ASSERT_NOT_NULL(object_var); 1176 ASSERT_NOT_NULL(object_var);
857 Slot* object_slot = object_var->slot(); 1177 Slot* object_slot = object_var->slot();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
973 if (result_saved) { 1293 if (result_saved) {
974 ApplyTOS(context_); 1294 ApplyTOS(context_);
975 } else { 1295 } else {
976 Apply(context_, rax); 1296 Apply(context_, rax);
977 } 1297 }
978 } 1298 }
979 1299
980 1300
981 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1301 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
982 Comment cmnt(masm_, "[ ArrayLiteral"); 1302 Comment cmnt(masm_, "[ ArrayLiteral");
1303
1304 ZoneList<Expression*>* subexprs = expr->values();
1305 int length = subexprs->length();
1306
983 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 1307 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
984 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); 1308 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
985 __ Push(Smi::FromInt(expr->literal_index())); 1309 __ Push(Smi::FromInt(expr->literal_index()));
986 __ Push(expr->constant_elements()); 1310 __ Push(expr->constant_elements());
987 if (expr->depth() > 1) { 1311 if (expr->depth() > 1) {
988 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 1312 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1313 } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
1314 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
989 } else { 1315 } else {
990 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 1316 FastCloneShallowArrayStub stub(length);
1317 __ CallStub(&stub);
991 } 1318 }
992 1319
993 bool result_saved = false; // Is the result saved to the stack? 1320 bool result_saved = false; // Is the result saved to the stack?
994 1321
995 // Emit code to evaluate all the non-constant subexpressions and to store 1322 // Emit code to evaluate all the non-constant subexpressions and to store
996 // them into the newly cloned array. 1323 // them into the newly cloned array.
997 ZoneList<Expression*>* subexprs = expr->values(); 1324 for (int i = 0; i < length; i++) {
998 for (int i = 0, len = subexprs->length(); i < len; i++) {
999 Expression* subexpr = subexprs->at(i); 1325 Expression* subexpr = subexprs->at(i);
1000 // If the subexpression is a literal or a simple materialized literal it 1326 // If the subexpression is a literal or a simple materialized literal it
1001 // is already set in the cloned array. 1327 // is already set in the cloned array.
1002 if (subexpr->AsLiteral() != NULL || 1328 if (subexpr->AsLiteral() != NULL ||
1003 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1329 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1004 continue; 1330 continue;
1005 } 1331 }
1006 1332
1007 if (!result_saved) { 1333 if (!result_saved) {
1008 __ push(rax); 1334 __ push(rax);
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1150 Expression::Context context) { 1476 Expression::Context context) {
1151 __ push(result_register()); 1477 __ push(result_register());
1152 GenericBinaryOpStub stub(op, 1478 GenericBinaryOpStub stub(op,
1153 NO_OVERWRITE, 1479 NO_OVERWRITE,
1154 NO_GENERIC_BINARY_FLAGS); 1480 NO_GENERIC_BINARY_FLAGS);
1155 __ CallStub(&stub); 1481 __ CallStub(&stub);
1156 Apply(context, rax); 1482 Apply(context, rax);
1157 } 1483 }
1158 1484
1159 1485
1486 void FullCodeGenerator::EmitAssignment(Expression* expr) {
1487 // Invalid left-hand sides are rewritten to have a 'throw
1488 // ReferenceError' on the left-hand side.
1489 if (!expr->IsValidLeftHandSide()) {
1490 VisitForEffect(expr);
1491 return;
1492 }
1493
1494 // Left-hand side can only be a property, a global or a (parameter or local)
1495 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1496 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1497 LhsKind assign_type = VARIABLE;
1498 Property* prop = expr->AsProperty();
1499 if (prop != NULL) {
1500 assign_type = (prop->key()->IsPropertyName())
1501 ? NAMED_PROPERTY
1502 : KEYED_PROPERTY;
1503 }
1504
1505 switch (assign_type) {
1506 case VARIABLE: {
1507 Variable* var = expr->AsVariableProxy()->var();
1508 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1509 break;
1510 }
1511 case NAMED_PROPERTY: {
1512 __ push(rax); // Preserve value.
1513 VisitForValue(prop->obj(), kAccumulator);
1514 __ movq(rdx, rax);
1515 __ pop(rax); // Restore value.
1516 __ Move(rcx, prop->key()->AsLiteral()->handle());
1517 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1518 __ call(ic, RelocInfo::CODE_TARGET);
1519 __ nop(); // Signal no inlined code.
1520 break;
1521 }
1522 case KEYED_PROPERTY: {
1523 __ push(rax); // Preserve value.
1524 VisitForValue(prop->obj(), kStack);
1525 VisitForValue(prop->key(), kStack);
1526 __ movq(rax, Operand(rsp, 2 * kPointerSize));
1527 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1528 __ call(ic, RelocInfo::CODE_TARGET);
1529 __ nop(); // Signal no inlined code.
1530 __ Drop(3); // Receiver, key, and extra copy of value.
1531 break;
1532 }
1533 }
1534 }
1535
1536
1160 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1537 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1161 Token::Value op, 1538 Token::Value op,
1162 Expression::Context context) { 1539 Expression::Context context) {
1163 // Left-hand sides that rewrite to explicit property accesses do not reach 1540 // Left-hand sides that rewrite to explicit property accesses do not reach
1164 // here. 1541 // here.
1165 ASSERT(var != NULL); 1542 ASSERT(var != NULL);
1166 ASSERT(var->is_global() || var->slot() != NULL); 1543 ASSERT(var->is_global() || var->slot() != NULL);
1167 1544
1168 if (var->is_global()) { 1545 if (var->is_global()) {
1169 ASSERT(!var->is_this()); 1546 ASSERT(!var->is_this());
(...skipping 10 matching lines...) Expand all
1180 // Perform the assignment for non-const variables and for initialization 1557 // Perform the assignment for non-const variables and for initialization
1181 // of const variables. Const assignments are simply skipped. 1558 // of const variables. Const assignments are simply skipped.
1182 Label done; 1559 Label done;
1183 Slot* slot = var->slot(); 1560 Slot* slot = var->slot();
1184 switch (slot->type()) { 1561 switch (slot->type()) {
1185 case Slot::PARAMETER: 1562 case Slot::PARAMETER:
1186 case Slot::LOCAL: 1563 case Slot::LOCAL:
1187 if (op == Token::INIT_CONST) { 1564 if (op == Token::INIT_CONST) {
1188 // Detect const reinitialization by checking for the hole value. 1565 // Detect const reinitialization by checking for the hole value.
1189 __ movq(rdx, Operand(rbp, SlotOffset(slot))); 1566 __ movq(rdx, Operand(rbp, SlotOffset(slot)));
1190 __ Cmp(rdx, Factory::the_hole_value()); 1567 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1191 __ j(not_equal, &done); 1568 __ j(not_equal, &done);
1192 } 1569 }
1193 // Perform the assignment. 1570 // Perform the assignment.
1194 __ movq(Operand(rbp, SlotOffset(slot)), rax); 1571 __ movq(Operand(rbp, SlotOffset(slot)), rax);
1195 break; 1572 break;
1196 1573
1197 case Slot::CONTEXT: { 1574 case Slot::CONTEXT: {
1198 MemOperand target = EmitSlotSearch(slot, rcx); 1575 MemOperand target = EmitSlotSearch(slot, rcx);
1199 if (op == Token::INIT_CONST) { 1576 if (op == Token::INIT_CONST) {
1200 // Detect const reinitialization by checking for the hole value. 1577 // Detect const reinitialization by checking for the hole value.
1201 __ movq(rdx, target); 1578 __ movq(rdx, target);
1202 __ Cmp(rdx, Factory::the_hole_value()); 1579 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1203 __ j(not_equal, &done); 1580 __ j(not_equal, &done);
1204 } 1581 }
1205 // Perform the assignment and issue the write barrier. 1582 // Perform the assignment and issue the write barrier.
1206 __ movq(target, rax); 1583 __ movq(target, rax);
1207 // The value of the assignment is in rax. RecordWrite clobbers its 1584 // The value of the assignment is in rax. RecordWrite clobbers its
1208 // register arguments. 1585 // register arguments.
1209 __ movq(rdx, rax); 1586 __ movq(rdx, rax);
1210 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1587 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1211 __ RecordWrite(rcx, offset, rdx, rbx); 1588 __ RecordWrite(rcx, offset, rdx, rbx);
1212 break; 1589 break;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1355 1732
1356 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1733 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1357 // Code common for calls using the call stub. 1734 // Code common for calls using the call stub.
1358 ZoneList<Expression*>* args = expr->arguments(); 1735 ZoneList<Expression*>* args = expr->arguments();
1359 int arg_count = args->length(); 1736 int arg_count = args->length();
1360 for (int i = 0; i < arg_count; i++) { 1737 for (int i = 0; i < arg_count; i++) {
1361 VisitForValue(args->at(i), kStack); 1738 VisitForValue(args->at(i), kStack);
1362 } 1739 }
1363 // Record source position for debugger. 1740 // Record source position for debugger.
1364 SetSourcePosition(expr->position()); 1741 SetSourcePosition(expr->position());
1365 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1742 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1743 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1366 __ CallStub(&stub); 1744 __ CallStub(&stub);
1367 // Restore context register. 1745 // Restore context register.
1368 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1746 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1369 // Discard the function left on TOS. 1747 // Discard the function left on TOS.
1370 DropAndApply(1, context_, rax); 1748 DropAndApply(1, context_, rax);
1371 } 1749 }
1372 1750
1373 1751
1374 void FullCodeGenerator::VisitCall(Call* expr) { 1752 void FullCodeGenerator::VisitCall(Call* expr) {
1375 Comment cmnt(masm_, "[ Call"); 1753 Comment cmnt(masm_, "[ Call");
1376 Expression* fun = expr->expression(); 1754 Expression* fun = expr->expression();
1377 Variable* var = fun->AsVariableProxy()->AsVariable(); 1755 Variable* var = fun->AsVariableProxy()->AsVariable();
1378 1756
1379 if (var != NULL && var->is_possibly_eval()) { 1757 if (var != NULL && var->is_possibly_eval()) {
1380 // Call to the identifier 'eval'. 1758 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1381 UNREACHABLE(); 1759 // resolve the function we need to call and the receiver of the
1760 // call. The we call the resolved function using the given
1761 // arguments.
1762 VisitForValue(fun, kStack);
1763 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
1764
1765 // Push the arguments.
1766 ZoneList<Expression*>* args = expr->arguments();
1767 int arg_count = args->length();
1768 for (int i = 0; i < arg_count; i++) {
1769 VisitForValue(args->at(i), kStack);
1770 }
1771
1772 // Push copy of the function - found below the arguments.
1773 __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
1774
1775 // Push copy of the first argument or undefined if it doesn't exist.
1776 if (arg_count > 0) {
1777 __ push(Operand(rsp, arg_count * kPointerSize));
1778 } else {
1779 __ PushRoot(Heap::kUndefinedValueRootIndex);
1780 }
1781
1782 // Push the receiver of the enclosing function and do runtime call.
1783 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
1784 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1785
1786 // The runtime call returns a pair of values in rax (function) and
1787 // rdx (receiver). Touch up the stack with the right values.
1788 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
1789 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
1790
1791 // Record source position for debugger.
1792 SetSourcePosition(expr->position());
1793 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1794 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1795 __ CallStub(&stub);
1796 // Restore context register.
1797 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1798 DropAndApply(1, context_, rax);
1382 } else if (var != NULL && !var->is_this() && var->is_global()) { 1799 } else if (var != NULL && !var->is_this() && var->is_global()) {
1383 // Call to a global variable. 1800 // Call to a global variable.
1384 // Push global object as receiver for the call IC lookup. 1801 // Push global object as receiver for the call IC lookup.
1385 __ push(CodeGenerator::GlobalObject()); 1802 __ push(CodeGenerator::GlobalObject());
1386 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1803 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1387 } else if (var != NULL && var->slot() != NULL && 1804 } else if (var != NULL && var->slot() != NULL &&
1388 var->slot()->type() == Slot::LOOKUP) { 1805 var->slot()->type() == Slot::LOOKUP) {
1389 // Call to a lookup slot. 1806 // Call to a lookup slot (dynamically introduced variable). Call
1390 UNREACHABLE(); 1807 // the runtime to find the function to call (returned in rax) and
1808 // the object holding it (returned in rdx).
1809 __ push(context_register());
1810 __ Push(var->name());
1811 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1812 __ push(rax); // Function.
1813 __ push(rdx); // Receiver.
1814 EmitCallWithStub(expr);
1391 } else if (fun->AsProperty() != NULL) { 1815 } else if (fun->AsProperty() != NULL) {
1392 // Call to an object property. 1816 // Call to an object property.
1393 Property* prop = fun->AsProperty(); 1817 Property* prop = fun->AsProperty();
1394 Literal* key = prop->key()->AsLiteral(); 1818 Literal* key = prop->key()->AsLiteral();
1395 if (key != NULL && key->handle()->IsSymbol()) { 1819 if (key != NULL && key->handle()->IsSymbol()) {
1396 // Call to a named property, use call IC. 1820 // Call to a named property, use call IC.
1397 VisitForValue(prop->obj(), kStack); 1821 VisitForValue(prop->obj(), kStack);
1398 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1822 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1399 } else { 1823 } else {
1400 // Call to a keyed property, use keyed load IC followed by function 1824 // 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)); 1895 __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
1472 1896
1473 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1897 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1474 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1898 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1475 1899
1476 // Replace function on TOS with result in rax, or pop it. 1900 // Replace function on TOS with result in rax, or pop it.
1477 DropAndApply(1, context_, rax); 1901 DropAndApply(1, context_, rax);
1478 } 1902 }
1479 1903
1480 1904
1905 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
1906 Handle<String> name = expr->name();
1907 if (strcmp("_IsSmi", *name->ToCString()) == 0) {
1908 EmitIsSmi(expr->arguments());
1909 } else if (strcmp("_IsNonNegativeSmi", *name->ToCString()) == 0) {
1910 EmitIsNonNegativeSmi(expr->arguments());
1911 } else if (strcmp("_IsObject", *name->ToCString()) == 0) {
1912 EmitIsObject(expr->arguments());
1913 } else if (strcmp("_IsUndetectableObject", *name->ToCString()) == 0) {
1914 EmitIsUndetectableObject(expr->arguments());
1915 } else if (strcmp("_IsFunction", *name->ToCString()) == 0) {
1916 EmitIsFunction(expr->arguments());
1917 } else if (strcmp("_IsArray", *name->ToCString()) == 0) {
1918 EmitIsArray(expr->arguments());
1919 } else if (strcmp("_IsRegExp", *name->ToCString()) == 0) {
1920 EmitIsRegExp(expr->arguments());
1921 } else if (strcmp("_IsConstructCall", *name->ToCString()) == 0) {
1922 EmitIsConstructCall(expr->arguments());
1923 } else if (strcmp("_ObjectEquals", *name->ToCString()) == 0) {
1924 EmitObjectEquals(expr->arguments());
1925 } else if (strcmp("_Arguments", *name->ToCString()) == 0) {
1926 EmitArguments(expr->arguments());
1927 } else if (strcmp("_ArgumentsLength", *name->ToCString()) == 0) {
1928 EmitArgumentsLength(expr->arguments());
1929 } else if (strcmp("_ClassOf", *name->ToCString()) == 0) {
1930 EmitClassOf(expr->arguments());
1931 } else if (strcmp("_Log", *name->ToCString()) == 0) {
1932 EmitLog(expr->arguments());
1933 } else if (strcmp("_RandomHeapNumber", *name->ToCString()) == 0) {
1934 EmitRandomHeapNumber(expr->arguments());
1935 } else if (strcmp("_SubString", *name->ToCString()) == 0) {
1936 EmitSubString(expr->arguments());
1937 } else if (strcmp("_RegExpExec", *name->ToCString()) == 0) {
1938 EmitRegExpExec(expr->arguments());
1939 } else if (strcmp("_ValueOf", *name->ToCString()) == 0) {
1940 EmitValueOf(expr->arguments());
1941 } else if (strcmp("_SetValueOf", *name->ToCString()) == 0) {
1942 EmitSetValueOf(expr->arguments());
1943 } else if (strcmp("_NumberToString", *name->ToCString()) == 0) {
1944 EmitNumberToString(expr->arguments());
1945 } else if (strcmp("_CharFromCode", *name->ToCString()) == 0) {
1946 EmitCharFromCode(expr->arguments());
1947 } else if (strcmp("_FastCharCodeAt", *name->ToCString()) == 0) {
1948 EmitFastCharCodeAt(expr->arguments());
1949 } else if (strcmp("_StringAdd", *name->ToCString()) == 0) {
1950 EmitStringAdd(expr->arguments());
1951 } else if (strcmp("_StringCompare", *name->ToCString()) == 0) {
1952 EmitStringCompare(expr->arguments());
1953 } else if (strcmp("_MathPow", *name->ToCString()) == 0) {
1954 EmitMathPow(expr->arguments());
1955 } else if (strcmp("_MathSin", *name->ToCString()) == 0) {
1956 EmitMathSin(expr->arguments());
1957 } else if (strcmp("_MathCos", *name->ToCString()) == 0) {
1958 EmitMathCos(expr->arguments());
1959 } else if (strcmp("_MathSqrt", *name->ToCString()) == 0) {
1960 EmitMathSqrt(expr->arguments());
1961 } else if (strcmp("_CallFunction", *name->ToCString()) == 0) {
1962 EmitCallFunction(expr->arguments());
1963 } else if (strcmp("_RegExpConstructResult", *name->ToCString()) == 0) {
1964 EmitRegExpConstructResult(expr->arguments());
1965 } else if (strcmp("_SwapElements", *name->ToCString()) == 0) {
1966 EmitSwapElements(expr->arguments());
1967 } else if (strcmp("_GetFromCache", *name->ToCString()) == 0) {
1968 EmitGetFromCache(expr->arguments());
1969 } else {
1970 UNREACHABLE();
1971 }
1972 }
1973
1974
1975 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1976 ASSERT(args->length() == 1);
1977
1978 VisitForValue(args->at(0), kAccumulator);
1979
1980 Label materialize_true, materialize_false;
1981 Label* if_true = NULL;
1982 Label* if_false = NULL;
1983 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1984
1985 __ JumpIfSmi(rax, if_true);
1986 __ jmp(if_false);
1987
1988 Apply(context_, if_true, if_false);
1989 }
1990
1991
1992 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1993 ASSERT(args->length() == 1);
1994
1995 VisitForValue(args->at(0), kAccumulator);
1996
1997 Label materialize_true, materialize_false;
1998 Label* if_true = NULL;
1999 Label* if_false = NULL;
2000 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2001
2002 Condition positive_smi = __ CheckPositiveSmi(rax);
2003 __ j(positive_smi, if_true);
2004 __ jmp(if_false);
2005
2006 Apply(context_, if_true, if_false);
2007 }
2008
2009
2010 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2011 ASSERT(args->length() == 1);
2012
2013 VisitForValue(args->at(0), kAccumulator);
2014
2015 Label materialize_true, materialize_false;
2016 Label* if_true = NULL;
2017 Label* if_false = NULL;
2018 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2019
2020 __ JumpIfSmi(rax, if_false);
2021 __ CompareRoot(rax, Heap::kNullValueRootIndex);
2022 __ j(equal, if_true);
2023 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2024 // Undetectable objects behave like undefined when tested with typeof.
2025 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2026 Immediate(1 << Map::kIsUndetectable));
2027 __ j(not_zero, if_false);
2028 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset));
2029 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
2030 __ j(below, if_false);
2031 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
2032 __ j(below_equal, if_true);
2033 __ jmp(if_false);
2034
2035 Apply(context_, if_true, if_false);
2036 }
2037
2038
2039 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2040 ASSERT(args->length() == 1);
2041
2042 VisitForValue(args->at(0), kAccumulator);
2043
2044 Label materialize_true, materialize_false;
2045 Label* if_true = NULL;
2046 Label* if_false = NULL;
2047 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2048
2049 __ JumpIfSmi(rax, if_false);
2050 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2051 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
2052 Immediate(1 << Map::kIsUndetectable));
2053 __ j(not_zero, if_true);
2054 __ jmp(if_false);
2055
2056 Apply(context_, if_true, if_false);
2057 }
2058
2059
2060 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2061 ASSERT(args->length() == 1);
2062
2063 VisitForValue(args->at(0), kAccumulator);
2064
2065 Label materialize_true, materialize_false;
2066 Label* if_true = NULL;
2067 Label* if_false = NULL;
2068 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2069
2070 __ JumpIfSmi(rax, if_false);
2071 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2072 __ j(equal, if_true);
2073 __ jmp(if_false);
2074
2075 Apply(context_, if_true, if_false);
2076 }
2077
2078
2079 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2080 ASSERT(args->length() == 1);
2081
2082 VisitForValue(args->at(0), kAccumulator);
2083
2084 Label materialize_true, materialize_false;
2085 Label* if_true = NULL;
2086 Label* if_false = NULL;
2087 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2088
2089 __ JumpIfSmi(rax, if_false);
2090 __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2091 __ j(equal, if_true);
2092 __ jmp(if_false);
2093
2094 Apply(context_, if_true, if_false);
2095 }
2096
2097
2098 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2099 ASSERT(args->length() == 1);
2100
2101 VisitForValue(args->at(0), kAccumulator);
2102
2103 Label materialize_true, materialize_false;
2104 Label* if_true = NULL;
2105 Label* if_false = NULL;
2106 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2107
2108 __ JumpIfSmi(rax, if_false);
2109 __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
2110 __ j(equal, if_true);
2111 __ jmp(if_false);
2112
2113 Apply(context_, if_true, if_false);
2114 }
2115
2116
2117
2118 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2119 ASSERT(args->length() == 0);
2120
2121 Label materialize_true, materialize_false;
2122 Label* if_true = NULL;
2123 Label* if_false = NULL;
2124 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2125
2126 // Get the frame pointer for the calling frame.
2127 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2128
2129 // Skip the arguments adaptor frame if it exists.
2130 Label check_frame_marker;
2131 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset),
2132 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2133 __ j(not_equal, &check_frame_marker);
2134 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset));
2135
2136 // Check the marker in the calling frame.
2137 __ bind(&check_frame_marker);
2138 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
2139 Smi::FromInt(StackFrame::CONSTRUCT));
2140 __ j(equal, if_true);
2141 __ jmp(if_false);
2142
2143 Apply(context_, if_true, if_false);
2144 }
2145
2146
2147 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2148 ASSERT(args->length() == 2);
2149
2150 // Load the two objects into registers and perform the comparison.
2151 VisitForValue(args->at(0), kStack);
2152 VisitForValue(args->at(1), kAccumulator);
2153
2154 Label materialize_true, materialize_false;
2155 Label* if_true = NULL;
2156 Label* if_false = NULL;
2157 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2158
2159 __ pop(rbx);
2160 __ cmpq(rax, rbx);
2161 __ j(equal, if_true);
2162 __ jmp(if_false);
2163
2164 Apply(context_, if_true, if_false);
2165 }
2166
2167
2168 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2169 ASSERT(args->length() == 1);
2170
2171 // ArgumentsAccessStub expects the key in edx and the formal
2172 // parameter count in eax.
2173 VisitForValue(args->at(0), kAccumulator);
2174 __ movq(rdx, rax);
2175 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2176 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2177 __ CallStub(&stub);
2178 Apply(context_, rax);
2179 }
2180
2181
2182 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2183 ASSERT(args->length() == 0);
2184
2185 Label exit;
2186 // Get the number of formal parameters.
2187 __ Move(rax, Smi::FromInt(scope()->num_parameters()));
2188
2189 // Check if the calling frame is an arguments adaptor frame.
2190 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2191 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset),
2192 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2193 __ j(not_equal, &exit);
2194
2195 // Arguments adaptor case: Read the arguments length from the
2196 // adaptor frame.
2197 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2198
2199 __ bind(&exit);
2200 if (FLAG_debug_code) __ AbortIfNotSmi(rax);
2201 Apply(context_, rax);
2202 }
2203
2204
2205 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2206 ASSERT(args->length() == 1);
2207 Label done, null, function, non_function_constructor;
2208
2209 VisitForValue(args->at(0), kAccumulator);
2210
2211 // If the object is a smi, we return null.
2212 __ JumpIfSmi(rax, &null);
2213
2214 // Check that the object is a JS object but take special care of JS
2215 // functions to make sure they have 'Function' as their class.
2216 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax);
2217 __ j(below, &null);
2218
2219 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2220 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2221 // LAST_JS_OBJECT_TYPE.
2222 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2223 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
2224 __ CmpInstanceType(rax, JS_FUNCTION_TYPE);
2225 __ j(equal, &function);
2226
2227 // Check if the constructor in the map is a function.
2228 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2229 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2230 __ j(not_equal, &non_function_constructor);
2231
2232 // rax now contains the constructor function. Grab the
2233 // instance class name from there.
2234 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset));
2235 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset));
2236 __ jmp(&done);
2237
2238 // Functions have class 'Function'.
2239 __ bind(&function);
2240 __ Move(rax, Factory::function_class_symbol());
2241 __ jmp(&done);
2242
2243 // Objects with a non-function constructor have class 'Object'.
2244 __ bind(&non_function_constructor);
2245 __ Move(rax, Factory::Object_symbol());
2246 __ jmp(&done);
2247
2248 // Non-JS objects have class null.
2249 __ bind(&null);
2250 __ LoadRoot(rax, Heap::kNullValueRootIndex);
2251
2252 // All done.
2253 __ bind(&done);
2254
2255 Apply(context_, rax);
2256 }
2257
2258
2259 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2260 // Conditionally generate a log call.
2261 // Args:
2262 // 0 (literal string): The type of logging (corresponds to the flags).
2263 // This is used to determine whether or not to generate the log call.
2264 // 1 (string): Format string. Access the string at argument index 2
2265 // with '%2s' (see Logger::LogRuntime for all the formats).
2266 // 2 (array): Arguments to the format string.
2267 ASSERT_EQ(args->length(), 3);
2268 #ifdef ENABLE_LOGGING_AND_PROFILING
2269 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2270 VisitForValue(args->at(1), kStack);
2271 VisitForValue(args->at(2), kStack);
2272 __ CallRuntime(Runtime::kLog, 2);
2273 }
2274 #endif
2275 // Finally, we're expected to leave a value on the top of the stack.
2276 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2277 Apply(context_, rax);
2278 }
2279
2280
2281 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2282 ASSERT(args->length() == 0);
2283
2284 Label slow_allocate_heapnumber;
2285 Label heapnumber_allocated;
2286
2287 __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
2288 __ jmp(&heapnumber_allocated);
2289
2290 __ bind(&slow_allocate_heapnumber);
2291 // To allocate a heap number, and ensure that it is not a smi, we
2292 // call the runtime function FUnaryMinus on 0, returning the double
2293 // -0.0. A new, distinct heap number is returned each time.
2294 __ Push(Smi::FromInt(0));
2295 __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
2296 __ movq(rbx, rax);
2297
2298 __ bind(&heapnumber_allocated);
2299
2300 // Return a random uint32 number in rax.
2301 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
2302 __ PrepareCallCFunction(0);
2303 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2304
2305 // Convert 32 random bits in rax to 0.(32 random bits) in a double
2306 // by computing:
2307 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2308 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2309 __ movd(xmm1, rcx);
2310 __ movd(xmm0, rax);
2311 __ cvtss2sd(xmm1, xmm1);
2312 __ xorpd(xmm0, xmm1);
2313 __ subsd(xmm0, xmm1);
2314 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
2315
2316 __ movq(rax, rbx);
2317 Apply(context_, rax);
2318 }
2319
2320
2321 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2322 // Load the arguments on the stack and call the stub.
2323 SubStringStub stub;
2324 ASSERT(args->length() == 3);
2325 VisitForValue(args->at(0), kStack);
2326 VisitForValue(args->at(1), kStack);
2327 VisitForValue(args->at(2), kStack);
2328 __ CallStub(&stub);
2329 Apply(context_, rax);
2330 }
2331
2332
2333 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2334 // Load the arguments on the stack and call the stub.
2335 RegExpExecStub stub;
2336 ASSERT(args->length() == 4);
2337 VisitForValue(args->at(0), kStack);
2338 VisitForValue(args->at(1), kStack);
2339 VisitForValue(args->at(2), kStack);
2340 VisitForValue(args->at(3), kStack);
2341 __ CallStub(&stub);
2342 Apply(context_, rax);
2343 }
2344
2345
2346 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2347 ASSERT(args->length() == 1);
2348
2349 VisitForValue(args->at(0), kAccumulator); // Load the object.
2350
2351 Label done;
2352 // If the object is a smi return the object.
2353 __ JumpIfSmi(rax, &done);
2354 // If the object is not a value type, return the object.
2355 __ CmpObjectType(rax, JS_VALUE_TYPE, rbx);
2356 __ j(not_equal, &done);
2357 __ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
2358
2359 __ bind(&done);
2360 Apply(context_, rax);
2361 }
2362
2363
2364 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2365 // Load the arguments on the stack and call the runtime function.
2366 ASSERT(args->length() == 2);
2367 VisitForValue(args->at(0), kStack);
2368 VisitForValue(args->at(1), kStack);
2369 __ CallRuntime(Runtime::kMath_pow, 2);
2370 Apply(context_, rax);
2371 }
2372
2373
2374 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2375 ASSERT(args->length() == 2);
2376
2377 VisitForValue(args->at(0), kStack); // Load the object.
2378 VisitForValue(args->at(1), kAccumulator); // Load the value.
2379 __ pop(rbx); // rax = value. ebx = object.
2380
2381 Label done;
2382 // If the object is a smi, return the value.
2383 __ JumpIfSmi(rbx, &done);
2384
2385 // If the object is not a value type, return the value.
2386 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx);
2387 __ j(not_equal, &done);
2388
2389 // Store the value.
2390 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax);
2391 // Update the write barrier. Save the value as it will be
2392 // overwritten by the write barrier code and is needed afterward.
2393 __ movq(rdx, rax);
2394 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
2395
2396 __ bind(&done);
2397 Apply(context_, rax);
2398 }
2399
2400
2401 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2402 ASSERT_EQ(args->length(), 1);
2403
2404 // Load the argument on the stack and call the stub.
2405 VisitForValue(args->at(0), kStack);
2406
2407 NumberToStringStub stub;
2408 __ CallStub(&stub);
2409 Apply(context_, rax);
2410 }
2411
2412
2413 void FullCodeGenerator::EmitCharFromCode(ZoneList<Expression*>* args) {
2414 ASSERT(args->length() == 1);
2415
2416 VisitForValue(args->at(0), kAccumulator);
2417
2418 Label slow_case, done;
2419 // Fast case of Heap::LookupSingleCharacterStringFromCode.
2420 __ JumpIfNotSmi(rax, &slow_case);
2421 __ SmiToInteger32(rcx, rax);
2422 __ cmpl(rcx, Immediate(String::kMaxAsciiCharCode));
2423 __ j(above, &slow_case);
2424
2425 __ Move(rbx, Factory::single_character_string_cache());
2426 __ movq(rbx, FieldOperand(rbx,
2427 rcx,
2428 times_pointer_size,
2429 FixedArray::kHeaderSize));
2430
2431 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
2432 __ j(equal, &slow_case);
2433 __ movq(rax, rbx);
2434 __ jmp(&done);
2435
2436 __ bind(&slow_case);
2437 __ push(rax);
2438 __ CallRuntime(Runtime::kCharFromCode, 1);
2439
2440 __ bind(&done);
2441 Apply(context_, rax);
2442 }
2443
2444
2445 void FullCodeGenerator::EmitFastCharCodeAt(ZoneList<Expression*>* args) {
2446 // TODO(fsc): Port the complete implementation from the classic back-end.
2447 // Move the undefined value into the result register, which will
2448 // trigger the slow case.
2449 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2450 Apply(context_, rax);
2451 }
2452
2453 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2454 ASSERT_EQ(2, args->length());
2455
2456 VisitForValue(args->at(0), kStack);
2457 VisitForValue(args->at(1), kStack);
2458
2459 StringAddStub stub(NO_STRING_ADD_FLAGS);
2460 __ CallStub(&stub);
2461 Apply(context_, rax);
2462 }
2463
2464
2465 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2466 ASSERT_EQ(2, args->length());
2467
2468 VisitForValue(args->at(0), kStack);
2469 VisitForValue(args->at(1), kStack);
2470
2471 StringCompareStub stub;
2472 __ CallStub(&stub);
2473 Apply(context_, rax);
2474 }
2475
2476
2477 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2478 // Load the argument on the stack and call the stub.
2479 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2480 ASSERT(args->length() == 1);
2481 VisitForValue(args->at(0), kStack);
2482 __ CallStub(&stub);
2483 Apply(context_, rax);
2484 }
2485
2486
2487 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2488 // Load the argument on the stack and call the stub.
2489 TranscendentalCacheStub stub(TranscendentalCache::COS);
2490 ASSERT(args->length() == 1);
2491 VisitForValue(args->at(0), kStack);
2492 __ CallStub(&stub);
2493 Apply(context_, rax);
2494 }
2495
2496
2497 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2498 // Load the argument on the stack and call the runtime function.
2499 ASSERT(args->length() == 1);
2500 VisitForValue(args->at(0), kStack);
2501 __ CallRuntime(Runtime::kMath_sqrt, 1);
2502 Apply(context_, rax);
2503 }
2504
2505
2506 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2507 ASSERT(args->length() >= 2);
2508
2509 int arg_count = args->length() - 2; // For receiver and function.
2510 VisitForValue(args->at(0), kStack); // Receiver.
2511 for (int i = 0; i < arg_count; i++) {
2512 VisitForValue(args->at(i + 1), kStack);
2513 }
2514 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2515
2516 // InvokeFunction requires function in rdi. Move it in there.
2517 if (!result_register().is(rdi)) __ movq(rdi, result_register());
2518 ParameterCount count(arg_count);
2519 __ InvokeFunction(rdi, count, CALL_FUNCTION);
2520 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2521 Apply(context_, rax);
2522 }
2523
2524
2525 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2526 ASSERT(args->length() == 3);
2527 VisitForValue(args->at(0), kStack);
2528 VisitForValue(args->at(1), kStack);
2529 VisitForValue(args->at(2), kStack);
2530 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2531 Apply(context_, rax);
2532 }
2533
2534
2535 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2536 ASSERT(args->length() == 3);
2537 VisitForValue(args->at(0), kStack);
2538 VisitForValue(args->at(1), kStack);
2539 VisitForValue(args->at(2), kStack);
2540 __ CallRuntime(Runtime::kSwapElements, 3);
2541 Apply(context_, rax);
2542 }
2543
2544
2545 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2546 ASSERT_EQ(2, args->length());
2547
2548 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2549 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2550
2551 Handle<FixedArray> jsfunction_result_caches(
2552 Top::global_context()->jsfunction_result_caches());
2553 if (jsfunction_result_caches->length() <= cache_id) {
2554 __ Abort("Attempt to use undefined cache.");
2555 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
2556 Apply(context_, rax);
2557 return;
2558 }
2559
2560 VisitForValue(args->at(1), kAccumulator);
2561
2562 Register key = rax;
2563 Register cache = rbx;
2564 Register tmp = rcx;
2565 __ movq(cache, CodeGenerator::ContextOperand(rsi, Context::GLOBAL_INDEX));
2566 __ movq(cache,
2567 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
2568 __ movq(cache,
2569 CodeGenerator::ContextOperand(
2570 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2571 __ movq(cache,
2572 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2573
2574 Label done, not_found;
2575 // tmp now holds finger offset as a smi.
2576 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2577 __ movq(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
2578 SmiIndex index =
2579 __ SmiToIndex(kScratchRegister, tmp, kPointerSizeLog2);
2580 __ cmpq(key, FieldOperand(cache,
2581 index.reg,
2582 index.scale,
2583 FixedArray::kHeaderSize));
2584 __ j(not_equal, &not_found);
2585 __ movq(rax, FieldOperand(cache,
2586 index.reg,
2587 index.scale,
2588 FixedArray::kHeaderSize + kPointerSize));
2589 __ jmp(&done);
2590
2591 __ bind(&not_found);
2592 // Call runtime to perform the lookup.
2593 __ push(cache);
2594 __ push(key);
2595 __ CallRuntime(Runtime::kGetFromCache, 2);
2596
2597 __ bind(&done);
2598 Apply(context_, rax);
2599 }
2600
2601
1481 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2602 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2603 Handle<String> name = expr->name();
2604 if (name->length() > 0 && name->Get(0) == '_') {
2605 Comment cmnt(masm_, "[ InlineRuntimeCall");
2606 EmitInlineRuntimeCall(expr);
2607 return;
2608 }
2609
1482 Comment cmnt(masm_, "[ CallRuntime"); 2610 Comment cmnt(masm_, "[ CallRuntime");
1483 ZoneList<Expression*>* args = expr->arguments(); 2611 ZoneList<Expression*>* args = expr->arguments();
1484 2612
1485 if (expr->is_jsruntime()) { 2613 if (expr->is_jsruntime()) {
1486 // Prepare for calling JS runtime function. 2614 // Prepare for calling JS runtime function.
1487 __ movq(rax, CodeGenerator::GlobalObject()); 2615 __ movq(rax, CodeGenerator::GlobalObject());
1488 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset)); 2616 __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
1489 } 2617 }
1490 2618
1491 // Push the arguments ("left-to-right"). 2619 // Push the arguments ("left-to-right").
(...skipping 12 matching lines...) Expand all
1504 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2632 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1505 } else { 2633 } else {
1506 __ CallRuntime(expr->function(), arg_count); 2634 __ CallRuntime(expr->function(), arg_count);
1507 } 2635 }
1508 Apply(context_, rax); 2636 Apply(context_, rax);
1509 } 2637 }
1510 2638
1511 2639
1512 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 2640 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1513 switch (expr->op()) { 2641 switch (expr->op()) {
2642 case Token::DELETE: {
2643 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2644 Property* prop = expr->expression()->AsProperty();
2645 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2646 if (prop == NULL && var == NULL) {
2647 // Result of deleting non-property, non-variable reference is true.
2648 // The subexpression may have side effects.
2649 VisitForEffect(expr->expression());
2650 Apply(context_, true);
2651 } else if (var != NULL &&
2652 !var->is_global() &&
2653 var->slot() != NULL &&
2654 var->slot()->type() != Slot::LOOKUP) {
2655 // Result of deleting non-global, non-dynamic variables is false.
2656 // The subexpression does not have side effects.
2657 Apply(context_, false);
2658 } else {
2659 // Property or variable reference. Call the delete builtin with
2660 // object and property name as arguments.
2661 if (prop != NULL) {
2662 VisitForValue(prop->obj(), kStack);
2663 VisitForValue(prop->key(), kStack);
2664 } else if (var->is_global()) {
2665 __ push(CodeGenerator::GlobalObject());
2666 __ Push(var->name());
2667 } else {
2668 // Non-global variable. Call the runtime to look up the context
2669 // where the variable was introduced.
2670 __ push(context_register());
2671 __ Push(var->name());
2672 __ CallRuntime(Runtime::kLookupContext, 2);
2673 __ push(rax);
2674 __ Push(var->name());
2675 }
2676 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
2677 Apply(context_, rax);
2678 }
2679 break;
2680 }
2681
1514 case Token::VOID: { 2682 case Token::VOID: {
1515 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 2683 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1516 VisitForEffect(expr->expression()); 2684 VisitForEffect(expr->expression());
1517 switch (context_) { 2685 switch (context_) {
1518 case Expression::kUninitialized: 2686 case Expression::kUninitialized:
1519 UNREACHABLE(); 2687 UNREACHABLE();
1520 break; 2688 break;
1521 case Expression::kEffect: 2689 case Expression::kEffect:
1522 break; 2690 break;
1523 case Expression::kValue: 2691 case Expression::kValue:
(...skipping 20 matching lines...) Expand all
1544 case Expression::kTest: 2712 case Expression::kTest:
1545 case Expression::kValueTest: 2713 case Expression::kValueTest:
1546 __ jmp(false_label_); 2714 __ jmp(false_label_);
1547 break; 2715 break;
1548 } 2716 }
1549 break; 2717 break;
1550 } 2718 }
1551 2719
1552 case Token::NOT: { 2720 case Token::NOT: {
1553 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 2721 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1554 Label materialize_true, materialize_false, done; 2722 Label materialize_true, materialize_false;
1555 // Initially assume a pure test context. Notice that the labels are 2723 Label* if_true = NULL;
1556 // swapped. 2724 Label* if_false = NULL;
1557 Label* if_true = false_label_; 2725
1558 Label* if_false = true_label_; 2726 // Notice that the labels are swapped.
1559 switch (context_) { 2727 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
1560 case Expression::kUninitialized: 2728
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); 2729 VisitForControl(expr->expression(), if_true, if_false);
2730
1581 Apply(context_, if_false, if_true); // Labels swapped. 2731 Apply(context_, if_false, if_true); // Labels swapped.
1582 break; 2732 break;
1583 } 2733 }
1584 2734
1585 case Token::TYPEOF: { 2735 case Token::TYPEOF: {
1586 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 2736 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1587 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2737 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1588 if (proxy != NULL && 2738 if (proxy != NULL &&
1589 !proxy->var()->is_this() && 2739 !proxy->var()->is_this() &&
1590 proxy->var()->is_global()) { 2740 proxy->var()->is_global()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1666 2816
1667 default: 2817 default:
1668 UNREACHABLE(); 2818 UNREACHABLE();
1669 } 2819 }
1670 } 2820 }
1671 2821
1672 2822
1673 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 2823 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
1674 Comment cmnt(masm_, "[ CountOperation"); 2824 Comment cmnt(masm_, "[ CountOperation");
1675 2825
2826 // Invalid left-hand-sides are rewritten to have a 'throw
2827 // ReferenceError' as the left-hand side.
2828 if (!expr->expression()->IsValidLeftHandSide()) {
2829 VisitForEffect(expr->expression());
2830 return;
2831 }
2832
1676 // Expression can only be a property, a global or a (parameter or local) 2833 // 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. 2834 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1678 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 2835 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1679 LhsKind assign_type = VARIABLE; 2836 LhsKind assign_type = VARIABLE;
1680 Property* prop = expr->expression()->AsProperty(); 2837 Property* prop = expr->expression()->AsProperty();
1681 // In case of a property we use the uninitialized expression context 2838 // In case of a property we use the uninitialized expression context
1682 // of the key to detect a named property. 2839 // of the key to detect a named property.
1683 if (prop != NULL) { 2840 if (prop != NULL) {
1684 assign_type = 2841 assign_type =
1685 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 2842 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1686 } 2843 }
1687 2844
1688 // Evaluate expression and get value. 2845 // Evaluate expression and get value.
1689 if (assign_type == VARIABLE) { 2846 if (assign_type == VARIABLE) {
1690 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 2847 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1691 Location saved_location = location_; 2848 Location saved_location = location_;
1692 location_ = kAccumulator; 2849 location_ = kAccumulator;
1693 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 2850 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1694 Expression::kValue); 2851 Expression::kValue);
1695 location_ = saved_location; 2852 location_ = saved_location;
1696 } else { 2853 } else {
1697 // Reserve space for result of postfix operation. 2854 // Reserve space for result of postfix operation.
1698 if (expr->is_postfix() && context_ != Expression::kEffect) { 2855 if (expr->is_postfix() && context_ != Expression::kEffect) {
1699 __ Push(Smi::FromInt(0)); 2856 __ Push(Smi::FromInt(0));
1700 } 2857 }
1701 VisitForValue(prop->obj(), kStack); 2858 VisitForValue(prop->obj(), kStack);
1702 if (assign_type == NAMED_PROPERTY) { 2859 if (assign_type == NAMED_PROPERTY) {
1703 EmitNamedPropertyLoad(prop); 2860 EmitNamedPropertyLoad(prop);
1704 } else { 2861 } else {
1705 VisitForValue(prop->key(), kStack); 2862 VisitForValue(prop->key(), kStack);
1706 EmitKeyedPropertyLoad(prop); 2863 EmitKeyedPropertyLoad(prop);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
1858 VisitForValue(expr->right(), kAccumulator); 3015 VisitForValue(expr->right(), kAccumulator);
1859 EmitBinaryOp(expr->op(), context_); 3016 EmitBinaryOp(expr->op(), context_);
1860 break; 3017 break;
1861 3018
1862 default: 3019 default:
1863 UNREACHABLE(); 3020 UNREACHABLE();
1864 } 3021 }
1865 } 3022 }
1866 3023
1867 3024
3025 void FullCodeGenerator::EmitNullCompare(bool strict,
3026 Register obj,
3027 Register null_const,
3028 Label* if_true,
3029 Label* if_false,
3030 Register scratch) {
3031 __ cmpq(obj, null_const);
3032 if (strict) {
3033 __ j(equal, if_true);
3034 } else {
3035 __ j(equal, if_true);
3036 __ CompareRoot(obj, Heap::kUndefinedValueRootIndex);
3037 __ j(equal, if_true);
3038 __ JumpIfSmi(obj, if_false);
3039 // It can be an undetectable object.
3040 __ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset));
3041 __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
3042 Immediate(1 << Map::kIsUndetectable));
3043 __ j(not_zero, if_true);
3044 }
3045 __ jmp(if_false);
3046 }
3047
3048
3049
1868 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 3050 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1869 Comment cmnt(masm_, "[ CompareOperation"); 3051 Comment cmnt(masm_, "[ CompareOperation");
1870 3052
1871 // Always perform the comparison for its control flow. Pack the result 3053 // Always perform the comparison for its control flow. Pack the result
1872 // into the expression's context after the comparison is performed. 3054 // into the expression's context after the comparison is performed.
1873 Label materialize_true, materialize_false, done; 3055 Label materialize_true, materialize_false;
1874 // Initially assume we are in a test context. 3056 Label* if_true = NULL;
1875 Label* if_true = true_label_; 3057 Label* if_false = NULL;
1876 Label* if_false = false_label_; 3058 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 3059
1899 VisitForValue(expr->left(), kStack); 3060 VisitForValue(expr->left(), kStack);
1900 switch (expr->op()) { 3061 switch (expr->op()) {
1901 case Token::IN: 3062 case Token::IN:
1902 VisitForValue(expr->right(), kStack); 3063 VisitForValue(expr->right(), kStack);
1903 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 3064 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1904 __ CompareRoot(rax, Heap::kTrueValueRootIndex); 3065 __ CompareRoot(rax, Heap::kTrueValueRootIndex);
1905 __ j(equal, if_true); 3066 __ j(equal, if_true);
1906 __ jmp(if_false); 3067 __ jmp(if_false);
1907 break; 3068 break;
1908 3069
1909 case Token::INSTANCEOF: { 3070 case Token::INSTANCEOF: {
1910 VisitForValue(expr->right(), kStack); 3071 VisitForValue(expr->right(), kStack);
1911 InstanceofStub stub; 3072 InstanceofStub stub;
1912 __ CallStub(&stub); 3073 __ CallStub(&stub);
1913 __ testq(rax, rax); 3074 __ testq(rax, rax);
1914 __ j(zero, if_true); // The stub returns 0 for true. 3075 __ j(zero, if_true); // The stub returns 0 for true.
1915 __ jmp(if_false); 3076 __ jmp(if_false);
1916 break; 3077 break;
1917 } 3078 }
1918 3079
1919 default: { 3080 default: {
1920 VisitForValue(expr->right(), kAccumulator); 3081 VisitForValue(expr->right(), kAccumulator);
1921 Condition cc = no_condition; 3082 Condition cc = no_condition;
1922 bool strict = false; 3083 bool strict = false;
1923 switch (expr->op()) { 3084 switch (expr->op()) {
1924 case Token::EQ_STRICT: 3085 case Token::EQ_STRICT:
1925 strict = true; 3086 strict = true;
1926 // Fall through. 3087 // Fall through.
1927 case Token::EQ: 3088 case Token::EQ: {
1928 cc = equal; 3089 cc = equal;
1929 __ pop(rdx); 3090 __ pop(rdx);
3091 // If either operand is constant null we do a fast compare
3092 // against null.
3093 Literal* right_literal = expr->right()->AsLiteral();
3094 Literal* left_literal = expr->left()->AsLiteral();
3095 if (right_literal != NULL && right_literal->handle()->IsNull()) {
3096 EmitNullCompare(strict, rdx, rax, if_true, if_false, rcx);
3097 Apply(context_, if_true, if_false);
3098 return;
3099 } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3100 EmitNullCompare(strict, rax, rdx, if_true, if_false, rcx);
3101 Apply(context_, if_true, if_false);
3102 return;
3103 }
1930 break; 3104 break;
3105 }
1931 case Token::LT: 3106 case Token::LT:
1932 cc = less; 3107 cc = less;
1933 __ pop(rdx); 3108 __ pop(rdx);
1934 break; 3109 break;
1935 case Token::GT: 3110 case Token::GT:
1936 // Reverse left and right sizes to obtain ECMA-262 conversion order. 3111 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1937 cc = less; 3112 cc = less;
1938 __ movq(rdx, result_register()); 3113 __ movq(rdx, result_register());
1939 __ pop(rax); 3114 __ pop(rax);
1940 break; 3115 break;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
2033 __ ret(0); 3208 __ ret(0);
2034 } 3209 }
2035 3210
2036 3211
2037 #undef __ 3212 #undef __
2038 3213
2039 3214
2040 } } // namespace v8::internal 3215 } } // namespace v8::internal
2041 3216
2042 #endif // V8_TARGET_ARCH_X64 3217 #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