OLD | NEW |
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 Loading... |
74 } | 74 } |
75 } | 75 } |
76 | 76 |
77 bool function_in_register = true; | 77 bool function_in_register = true; |
78 | 78 |
79 // Possibly allocate a local context. | 79 // Possibly allocate a local context. |
80 if (scope()->num_heap_slots() > 0) { | 80 if (scope()->num_heap_slots() > 0) { |
81 Comment cmnt(masm_, "[ Allocate local context"); | 81 Comment cmnt(masm_, "[ Allocate local context"); |
82 // Argument to NewContext is the function, which is still in rdi. | 82 // Argument to NewContext is the function, which is still in rdi. |
83 __ push(rdi); | 83 __ push(rdi); |
84 __ CallRuntime(Runtime::kNewContext, 1); | 84 EmitCallRuntime(Runtime::kNewContext, 1); |
85 function_in_register = false; | 85 function_in_register = false; |
86 // Context is returned in both rax and rsi. It replaces the context | 86 // Context is returned in both rax and rsi. It replaces the context |
87 // passed to us. It's saved in the stack and kept live in rsi. | 87 // passed to us. It's saved in the stack and kept live in rsi. |
88 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 88 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
89 | 89 |
90 // Copy any necessary parameters into the context. | 90 // Copy any necessary parameters into the context. |
91 int num_parameters = scope()->num_parameters(); | 91 int num_parameters = scope()->num_parameters(); |
92 for (int i = 0; i < num_parameters; i++) { | 92 for (int i = 0; i < num_parameters; i++) { |
93 Slot* slot = scope()->parameter(i)->slot(); | 93 Slot* slot = scope()->parameter(i)->slot(); |
94 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 94 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 { Comment cmnt(masm_, "[ Stack check"); | 147 { Comment cmnt(masm_, "[ Stack check"); |
148 Label ok; | 148 Label ok; |
149 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 149 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
150 __ j(above_equal, &ok); | 150 __ j(above_equal, &ok); |
151 StackCheckStub stub; | 151 StackCheckStub stub; |
152 __ CallStub(&stub); | 152 __ CallStub(&stub); |
153 __ bind(&ok); | 153 __ bind(&ok); |
154 } | 154 } |
155 | 155 |
156 if (FLAG_trace) { | 156 if (FLAG_trace) { |
157 __ CallRuntime(Runtime::kTraceEnter, 0); | 157 EmitCallRuntime(Runtime::kTraceEnter, 0); |
158 } | 158 } |
159 | 159 |
160 { Comment cmnt(masm_, "[ Body"); | 160 { Comment cmnt(masm_, "[ Body"); |
161 ASSERT(loop_depth() == 0); | 161 ASSERT(loop_depth() == 0); |
162 VisitStatements(function()->body()); | 162 VisitStatements(function()->body()); |
163 ASSERT(loop_depth() == 0); | 163 ASSERT(loop_depth() == 0); |
164 } | 164 } |
165 | 165 |
166 { Comment cmnt(masm_, "[ return <undefined>;"); | 166 { Comment cmnt(masm_, "[ return <undefined>;"); |
167 // Emit a 'return undefined' in case control fell off the end of the body. | 167 // Emit a 'return undefined' in case control fell off the end of the body. |
168 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 168 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
169 EmitReturnSequence(function()->end_position()); | 169 EmitReturnSequence(function()->end_position()); |
170 } | 170 } |
171 } | 171 } |
172 | 172 |
173 | 173 |
174 void FullCodeGenerator::EmitReturnSequence(int position) { | 174 void FullCodeGenerator::EmitReturnSequence(int position) { |
175 Comment cmnt(masm_, "[ Return sequence"); | 175 Comment cmnt(masm_, "[ Return sequence"); |
176 if (return_label_.is_bound()) { | 176 if (return_label_.is_bound()) { |
177 __ jmp(&return_label_); | 177 __ jmp(&return_label_); |
178 } else { | 178 } else { |
179 __ bind(&return_label_); | 179 __ bind(&return_label_); |
180 if (FLAG_trace) { | 180 if (FLAG_trace) { |
181 __ push(rax); | 181 __ push(rax); |
182 __ CallRuntime(Runtime::kTraceExit, 1); | 182 EmitCallRuntime(Runtime::kTraceExit, 1); |
183 } | 183 } |
184 #ifdef DEBUG | 184 #ifdef DEBUG |
185 // Add a label for checking the size of the code used for returning. | 185 // Add a label for checking the size of the code used for returning. |
186 Label check_exit_codesize; | 186 Label check_exit_codesize; |
187 masm_->bind(&check_exit_codesize); | 187 masm_->bind(&check_exit_codesize); |
188 #endif | 188 #endif |
189 CodeGenerator::RecordPositions(masm_, position); | 189 CodeGenerator::RecordPositions(masm_, position); |
190 __ RecordJSReturn(); | 190 __ RecordJSReturn(); |
191 // Do not use the leave instruction here because it is too short to | 191 // Do not use the leave instruction here because it is too short to |
192 // patch with the code required by the debugger. | 192 // patch with the code required by the debugger. |
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 // Note: For variables we must not push an initial value (such as | 726 // Note: For variables we must not push an initial value (such as |
727 // 'undefined') because we may have a (legal) redeclaration and we | 727 // 'undefined') because we may have a (legal) redeclaration and we |
728 // must not destroy the current value. | 728 // must not destroy the current value. |
729 if (decl->mode() == Variable::CONST) { | 729 if (decl->mode() == Variable::CONST) { |
730 __ PushRoot(Heap::kTheHoleValueRootIndex); | 730 __ PushRoot(Heap::kTheHoleValueRootIndex); |
731 } else if (decl->fun() != NULL) { | 731 } else if (decl->fun() != NULL) { |
732 VisitForValue(decl->fun(), kStack); | 732 VisitForValue(decl->fun(), kStack); |
733 } else { | 733 } else { |
734 __ Push(Smi::FromInt(0)); // no initial value! | 734 __ Push(Smi::FromInt(0)); // no initial value! |
735 } | 735 } |
736 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 736 EmitCallRuntime(Runtime::kDeclareContextSlot, 4); |
737 break; | 737 break; |
738 } | 738 } |
739 } | 739 } |
740 | 740 |
741 } else if (prop != NULL) { | 741 } else if (prop != NULL) { |
742 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { | 742 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { |
743 // We are declaring a function or constant that rewrites to a | 743 // We are declaring a function or constant that rewrites to a |
744 // property. Use (keyed) IC to set the initial value. | 744 // property. Use (keyed) IC to set the initial value. |
745 VisitForValue(prop->obj(), kStack); | 745 VisitForValue(prop->obj(), kStack); |
746 VisitForValue(prop->key(), kStack); | 746 VisitForValue(prop->key(), kStack); |
(...skipping 16 matching lines...) Expand all Loading... |
763 } | 763 } |
764 } | 764 } |
765 } | 765 } |
766 | 766 |
767 | 767 |
768 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 768 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
769 // Call the runtime to declare the globals. | 769 // Call the runtime to declare the globals. |
770 __ push(rsi); // The context is the first argument. | 770 __ push(rsi); // The context is the first argument. |
771 __ Push(pairs); | 771 __ Push(pairs); |
772 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 772 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
773 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 773 EmitCallRuntime(Runtime::kDeclareGlobals, 3); |
774 // Return value is ignored. | 774 // Return value is ignored. |
775 } | 775 } |
776 | 776 |
777 | 777 |
778 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 778 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
779 Comment cmnt(masm_, "[ FunctionLiteral"); | 779 Comment cmnt(masm_, "[ FunctionLiteral"); |
780 | 780 |
781 // Build the function boilerplate and instantiate it. | 781 // Build the function boilerplate and instantiate it. |
782 Handle<JSFunction> boilerplate = | 782 Handle<JSFunction> boilerplate = |
783 Compiler::BuildBoilerplate(expr, script(), this); | 783 Compiler::BuildBoilerplate(expr, script(), this); |
784 if (HasStackOverflow()) return; | 784 if (HasStackOverflow()) return; |
785 | 785 |
786 ASSERT(boilerplate->IsBoilerplate()); | 786 ASSERT(boilerplate->IsBoilerplate()); |
787 | 787 |
788 // Create a new closure. | 788 // Create a new closure. |
789 __ push(rsi); | 789 __ push(rsi); |
790 __ Push(boilerplate); | 790 __ Push(boilerplate); |
791 __ CallRuntime(Runtime::kNewClosure, 2); | 791 EmitCallRuntime(Runtime::kNewClosure, 2); |
792 Apply(context_, rax); | 792 Apply(context_, rax); |
793 } | 793 } |
794 | 794 |
795 | 795 |
796 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 796 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
797 Comment cmnt(masm_, "[ VariableProxy"); | 797 Comment cmnt(masm_, "[ VariableProxy"); |
798 EmitVariableLoad(expr->var(), context_); | 798 EmitVariableLoad(expr->var(), context_); |
799 } | 799 } |
800 | 800 |
801 | 801 |
(...skipping 16 matching lines...) Expand all Loading... |
818 // A test rax instruction following the call is used by the IC to | 818 // A test rax instruction following the call is used by the IC to |
819 // indicate that the inobject property case was inlined. Ensure there | 819 // indicate that the inobject property case was inlined. Ensure there |
820 // is no test rax instruction here. | 820 // is no test rax instruction here. |
821 __ nop(); | 821 __ nop(); |
822 DropAndApply(1, context, rax); | 822 DropAndApply(1, context, rax); |
823 | 823 |
824 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 824 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
825 Comment cmnt(masm_, "Lookup slot"); | 825 Comment cmnt(masm_, "Lookup slot"); |
826 __ push(rsi); // Context. | 826 __ push(rsi); // Context. |
827 __ Push(var->name()); | 827 __ Push(var->name()); |
828 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 828 EmitCallRuntime(Runtime::kLoadContextSlot, 2); |
829 Apply(context, rax); | 829 Apply(context, rax); |
830 | 830 |
831 } else if (slot != NULL) { | 831 } else if (slot != NULL) { |
832 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 832 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
833 ? "Context slot" | 833 ? "Context slot" |
834 : "Stack slot"); | 834 : "Stack slot"); |
835 Apply(context, slot); | 835 Apply(context, slot); |
836 | 836 |
837 } else { | 837 } else { |
838 Comment cmnt(masm_, "Rewritten parameter"); | 838 Comment cmnt(masm_, "Rewritten parameter"); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 882 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
883 __ movq(rax, FieldOperand(rbx, literal_offset)); | 883 __ movq(rax, FieldOperand(rbx, literal_offset)); |
884 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 884 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
885 __ j(not_equal, &done); | 885 __ j(not_equal, &done); |
886 // Create regexp literal using runtime function | 886 // Create regexp literal using runtime function |
887 // Result will be in rax. | 887 // Result will be in rax. |
888 __ push(rbx); | 888 __ push(rbx); |
889 __ Push(Smi::FromInt(expr->literal_index())); | 889 __ Push(Smi::FromInt(expr->literal_index())); |
890 __ Push(expr->pattern()); | 890 __ Push(expr->pattern()); |
891 __ Push(expr->flags()); | 891 __ Push(expr->flags()); |
892 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 892 EmitCallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
893 __ bind(&done); | 893 __ bind(&done); |
894 Apply(context_, rax); | 894 Apply(context_, rax); |
895 } | 895 } |
896 | 896 |
897 | 897 |
898 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 898 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
899 Comment cmnt(masm_, "[ ObjectLiteral"); | 899 Comment cmnt(masm_, "[ ObjectLiteral"); |
900 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 900 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
901 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 901 __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
902 __ Push(Smi::FromInt(expr->literal_index())); | 902 __ Push(Smi::FromInt(expr->literal_index())); |
903 __ Push(expr->constant_properties()); | 903 __ Push(expr->constant_properties()); |
904 if (expr->depth() > 1) { | 904 if (expr->depth() > 1) { |
905 __ CallRuntime(Runtime::kCreateObjectLiteral, 3); | 905 EmitCallRuntime(Runtime::kCreateObjectLiteral, 3); |
906 } else { | 906 } else { |
907 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 907 EmitCallRuntime(Runtime::kCreateObjectLiteralShallow, 3); |
908 } | 908 } |
909 | 909 |
910 // If result_saved is true the result is on top of the stack. If | 910 // If result_saved is true the result is on top of the stack. If |
911 // result_saved is false the result is in rax. | 911 // result_saved is false the result is in rax. |
912 bool result_saved = false; | 912 bool result_saved = false; |
913 | 913 |
914 for (int i = 0; i < expr->properties()->length(); i++) { | 914 for (int i = 0; i < expr->properties()->length(); i++) { |
915 ObjectLiteral::Property* property = expr->properties()->at(i); | 915 ObjectLiteral::Property* property = expr->properties()->at(i); |
916 if (property->IsCompileTimeValue()) continue; | 916 if (property->IsCompileTimeValue()) continue; |
917 | 917 |
(...skipping 17 matching lines...) Expand all Loading... |
935 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 935 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
936 __ call(ic, RelocInfo::CODE_TARGET); | 936 __ call(ic, RelocInfo::CODE_TARGET); |
937 __ nop(); | 937 __ nop(); |
938 break; | 938 break; |
939 } | 939 } |
940 // Fall through. | 940 // Fall through. |
941 case ObjectLiteral::Property::PROTOTYPE: | 941 case ObjectLiteral::Property::PROTOTYPE: |
942 __ push(Operand(rsp, 0)); // Duplicate receiver. | 942 __ push(Operand(rsp, 0)); // Duplicate receiver. |
943 VisitForValue(key, kStack); | 943 VisitForValue(key, kStack); |
944 VisitForValue(value, kStack); | 944 VisitForValue(value, kStack); |
945 __ CallRuntime(Runtime::kSetProperty, 3); | 945 EmitCallRuntime(Runtime::kSetProperty, 3); |
946 break; | 946 break; |
947 case ObjectLiteral::Property::SETTER: | 947 case ObjectLiteral::Property::SETTER: |
948 case ObjectLiteral::Property::GETTER: | 948 case ObjectLiteral::Property::GETTER: |
949 __ push(Operand(rsp, 0)); // Duplicate receiver. | 949 __ push(Operand(rsp, 0)); // Duplicate receiver. |
950 VisitForValue(key, kStack); | 950 VisitForValue(key, kStack); |
951 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 951 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
952 Smi::FromInt(1) : | 952 Smi::FromInt(1) : |
953 Smi::FromInt(0)); | 953 Smi::FromInt(0)); |
954 VisitForValue(value, kStack); | 954 VisitForValue(value, kStack); |
955 __ CallRuntime(Runtime::kDefineAccessor, 4); | 955 EmitCallRuntime(Runtime::kDefineAccessor, 4); |
956 break; | 956 break; |
957 } | 957 } |
958 } | 958 } |
959 | 959 |
960 if (result_saved) { | 960 if (result_saved) { |
961 ApplyTOS(context_); | 961 ApplyTOS(context_); |
962 } else { | 962 } else { |
963 Apply(context_, rax); | 963 Apply(context_, rax); |
964 } | 964 } |
965 } | 965 } |
966 | 966 |
967 | 967 |
968 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 968 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
969 Comment cmnt(masm_, "[ ArrayLiteral"); | 969 Comment cmnt(masm_, "[ ArrayLiteral"); |
970 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 970 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
971 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 971 __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
972 __ Push(Smi::FromInt(expr->literal_index())); | 972 __ Push(Smi::FromInt(expr->literal_index())); |
973 __ Push(expr->constant_elements()); | 973 __ Push(expr->constant_elements()); |
974 if (expr->depth() > 1) { | 974 if (expr->depth() > 1) { |
975 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); | 975 EmitCallRuntime(Runtime::kCreateArrayLiteral, 3); |
976 } else { | 976 } else { |
977 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 977 EmitCallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
978 } | 978 } |
979 | 979 |
980 bool result_saved = false; // Is the result saved to the stack? | 980 bool result_saved = false; // Is the result saved to the stack? |
981 | 981 |
982 // Emit code to evaluate all the non-constant subexpressions and to store | 982 // Emit code to evaluate all the non-constant subexpressions and to store |
983 // them into the newly cloned array. | 983 // them into the newly cloned array. |
984 ZoneList<Expression*>* subexprs = expr->values(); | 984 ZoneList<Expression*>* subexprs = expr->values(); |
985 for (int i = 0, len = subexprs->length(); i < len; i++) { | 985 for (int i = 0, len = subexprs->length(); i < len; i++) { |
986 Expression* subexpr = subexprs->at(i); | 986 Expression* subexpr = subexprs->at(i); |
987 // If the subexpression is a literal or a simple materialized literal it | 987 // If the subexpression is a literal or a simple materialized literal it |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 __ Move(rcx, var->name()); | 1146 __ Move(rcx, var->name()); |
1147 __ movq(rdx, CodeGenerator::GlobalObject()); | 1147 __ movq(rdx, CodeGenerator::GlobalObject()); |
1148 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1148 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1149 __ Call(ic, RelocInfo::CODE_TARGET); | 1149 __ Call(ic, RelocInfo::CODE_TARGET); |
1150 Apply(context, rax); | 1150 Apply(context, rax); |
1151 | 1151 |
1152 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1152 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1153 __ push(result_register()); // Value. | 1153 __ push(result_register()); // Value. |
1154 __ push(rsi); // Context. | 1154 __ push(rsi); // Context. |
1155 __ Push(var->name()); | 1155 __ Push(var->name()); |
1156 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 1156 EmitCallRuntime(Runtime::kStoreContextSlot, 3); |
1157 Apply(context, rax); | 1157 Apply(context, rax); |
1158 | 1158 |
1159 } else if (var->slot() != NULL) { | 1159 } else if (var->slot() != NULL) { |
1160 switch (slot->type()) { | 1160 switch (slot->type()) { |
1161 case Slot::LOCAL: | 1161 case Slot::LOCAL: |
1162 case Slot::PARAMETER: | 1162 case Slot::PARAMETER: |
1163 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); | 1163 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
1164 break; | 1164 break; |
1165 | 1165 |
1166 case Slot::CONTEXT: { | 1166 case Slot::CONTEXT: { |
(...skipping 26 matching lines...) Expand all Loading... |
1193 Property* prop = expr->target()->AsProperty(); | 1193 Property* prop = expr->target()->AsProperty(); |
1194 ASSERT(prop != NULL); | 1194 ASSERT(prop != NULL); |
1195 ASSERT(prop->key()->AsLiteral() != NULL); | 1195 ASSERT(prop->key()->AsLiteral() != NULL); |
1196 | 1196 |
1197 // If the assignment starts a block of assignments to the same object, | 1197 // If the assignment starts a block of assignments to the same object, |
1198 // change to slow case to avoid the quadratic behavior of repeatedly | 1198 // change to slow case to avoid the quadratic behavior of repeatedly |
1199 // adding fast properties. | 1199 // adding fast properties. |
1200 if (expr->starts_initialization_block()) { | 1200 if (expr->starts_initialization_block()) { |
1201 __ push(result_register()); | 1201 __ push(result_register()); |
1202 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. | 1202 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. |
1203 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1203 EmitCallRuntime(Runtime::kToSlowProperties, 1); |
1204 __ pop(result_register()); | 1204 __ pop(result_register()); |
1205 } | 1205 } |
1206 | 1206 |
1207 // Record source code position before IC call. | 1207 // Record source code position before IC call. |
1208 SetSourcePosition(expr->position()); | 1208 SetSourcePosition(expr->position()); |
1209 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1209 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
1210 if (expr->ends_initialization_block()) { | 1210 if (expr->ends_initialization_block()) { |
1211 __ movq(rdx, Operand(rsp, 0)); | 1211 __ movq(rdx, Operand(rsp, 0)); |
1212 } else { | 1212 } else { |
1213 __ pop(rdx); | 1213 __ pop(rdx); |
1214 } | 1214 } |
1215 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1215 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
1216 __ Call(ic, RelocInfo::CODE_TARGET); | 1216 __ Call(ic, RelocInfo::CODE_TARGET); |
1217 __ nop(); | 1217 __ nop(); |
1218 | 1218 |
1219 // If the assignment ends an initialization block, revert to fast case. | 1219 // If the assignment ends an initialization block, revert to fast case. |
1220 if (expr->ends_initialization_block()) { | 1220 if (expr->ends_initialization_block()) { |
1221 __ push(rax); // Result of assignment, saved even if not needed. | 1221 __ push(rax); // Result of assignment, saved even if not needed. |
1222 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1222 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
1223 __ CallRuntime(Runtime::kToFastProperties, 1); | 1223 EmitCallRuntime(Runtime::kToFastProperties, 1); |
1224 __ pop(rax); | 1224 __ pop(rax); |
1225 DropAndApply(1, context_, rax); | 1225 DropAndApply(1, context_, rax); |
1226 } else { | 1226 } else { |
1227 Apply(context_, rax); | 1227 Apply(context_, rax); |
1228 } | 1228 } |
1229 } | 1229 } |
1230 | 1230 |
1231 | 1231 |
1232 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 1232 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
1233 // Assignment to a property, using a keyed store IC. | 1233 // Assignment to a property, using a keyed store IC. |
1234 | 1234 |
1235 // If the assignment starts a block of assignments to the same object, | 1235 // If the assignment starts a block of assignments to the same object, |
1236 // change to slow case to avoid the quadratic behavior of repeatedly | 1236 // change to slow case to avoid the quadratic behavior of repeatedly |
1237 // adding fast properties. | 1237 // adding fast properties. |
1238 if (expr->starts_initialization_block()) { | 1238 if (expr->starts_initialization_block()) { |
1239 __ push(result_register()); | 1239 __ push(result_register()); |
1240 // Receiver is now under the key and value. | 1240 // Receiver is now under the key and value. |
1241 __ push(Operand(rsp, 2 * kPointerSize)); | 1241 __ push(Operand(rsp, 2 * kPointerSize)); |
1242 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1242 EmitCallRuntime(Runtime::kToSlowProperties, 1); |
1243 __ pop(result_register()); | 1243 __ pop(result_register()); |
1244 } | 1244 } |
1245 | 1245 |
1246 // Record source code position before IC call. | 1246 // Record source code position before IC call. |
1247 SetSourcePosition(expr->position()); | 1247 SetSourcePosition(expr->position()); |
1248 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1248 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
1249 __ Call(ic, RelocInfo::CODE_TARGET); | 1249 __ Call(ic, RelocInfo::CODE_TARGET); |
1250 // This nop signals to the IC that there is no inlined code at the call | 1250 // This nop signals to the IC that there is no inlined code at the call |
1251 // site for it to patch. | 1251 // site for it to patch. |
1252 __ nop(); | 1252 __ nop(); |
1253 | 1253 |
1254 // If the assignment ends an initialization block, revert to fast case. | 1254 // If the assignment ends an initialization block, revert to fast case. |
1255 if (expr->ends_initialization_block()) { | 1255 if (expr->ends_initialization_block()) { |
1256 __ push(rax); // Result of assignment, saved even if not needed. | 1256 __ push(rax); // Result of assignment, saved even if not needed. |
1257 // Receiver is under the key and value. | 1257 // Receiver is under the key and value. |
1258 __ push(Operand(rsp, 2 * kPointerSize)); | 1258 __ push(Operand(rsp, 2 * kPointerSize)); |
1259 __ CallRuntime(Runtime::kToFastProperties, 1); | 1259 EmitCallRuntime(Runtime::kToFastProperties, 1); |
1260 __ pop(rax); | 1260 __ pop(rax); |
1261 } | 1261 } |
1262 | 1262 |
1263 // Receiver and key are still on stack. | 1263 // Receiver and key are still on stack. |
1264 DropAndApply(2, context_, rax); | 1264 DropAndApply(2, context_, rax); |
1265 } | 1265 } |
1266 | 1266 |
1267 | 1267 |
1268 void FullCodeGenerator::VisitProperty(Property* expr) { | 1268 void FullCodeGenerator::VisitProperty(Property* expr) { |
1269 Comment cmnt(masm_, "[ Property"); | 1269 Comment cmnt(masm_, "[ Property"); |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1451 | 1451 |
1452 if (expr->is_jsruntime()) { | 1452 if (expr->is_jsruntime()) { |
1453 // Call the JS runtime function using a call IC. | 1453 // Call the JS runtime function using a call IC. |
1454 __ Move(rcx, expr->name()); | 1454 __ Move(rcx, expr->name()); |
1455 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1455 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
1456 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); | 1456 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); |
1457 __ call(ic, RelocInfo::CODE_TARGET); | 1457 __ call(ic, RelocInfo::CODE_TARGET); |
1458 // Restore context register. | 1458 // Restore context register. |
1459 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1459 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
1460 } else { | 1460 } else { |
1461 __ CallRuntime(expr->function(), arg_count); | 1461 EmitCallRuntime(expr->function(), arg_count); |
1462 } | 1462 } |
1463 Apply(context_, rax); | 1463 Apply(context_, rax); |
1464 } | 1464 } |
1465 | 1465 |
1466 | 1466 |
| 1467 void FullCodeGenerator::EmitCallRuntime(Runtime::FunctionId id, int arg_count) { |
| 1468 EmitCallRuntime(Runtime::FunctionForId(id), arg_count); |
| 1469 } |
| 1470 |
| 1471 |
| 1472 void FullCodeGenerator::EmitCallRuntime(Runtime::Function* f, int arg_count) { |
| 1473 if (Runtime::DIRECT_CALL_NOT_FAILS == f->calling_convention) { |
| 1474 if (arg_count > kCArgRegsCount) { |
| 1475 __ IllegalOperation(arg_count); |
| 1476 __ Drop(arg_count); |
| 1477 return; |
| 1478 } |
| 1479 for (int i = arg_count - 1; i >= 0; i--) { |
| 1480 __ pop(kCArgRegs[i]); |
| 1481 } |
| 1482 } |
| 1483 |
| 1484 __ CallRuntime(f, arg_count); |
| 1485 |
| 1486 if (Runtime::DIRECT_CALL_NOT_FAILS == f->calling_convention) { |
| 1487 // Restore context register. |
| 1488 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1489 } |
| 1490 } |
| 1491 |
| 1492 |
1467 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 1493 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
1468 switch (expr->op()) { | 1494 switch (expr->op()) { |
1469 case Token::VOID: { | 1495 case Token::VOID: { |
1470 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 1496 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
1471 VisitForEffect(expr->expression()); | 1497 VisitForEffect(expr->expression()); |
1472 switch (context_) { | 1498 switch (context_) { |
1473 case Expression::kUninitialized: | 1499 case Expression::kUninitialized: |
1474 UNREACHABLE(); | 1500 UNREACHABLE(); |
1475 break; | 1501 break; |
1476 case Expression::kEffect: | 1502 case Expression::kEffect: |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1549 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1575 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1550 // Use a regular load, not a contextual load, to avoid a reference | 1576 // Use a regular load, not a contextual load, to avoid a reference |
1551 // error. | 1577 // error. |
1552 __ Call(ic, RelocInfo::CODE_TARGET); | 1578 __ Call(ic, RelocInfo::CODE_TARGET); |
1553 __ movq(Operand(rsp, 0), rax); | 1579 __ movq(Operand(rsp, 0), rax); |
1554 } else if (proxy != NULL && | 1580 } else if (proxy != NULL && |
1555 proxy->var()->slot() != NULL && | 1581 proxy->var()->slot() != NULL && |
1556 proxy->var()->slot()->type() == Slot::LOOKUP) { | 1582 proxy->var()->slot()->type() == Slot::LOOKUP) { |
1557 __ push(rsi); | 1583 __ push(rsi); |
1558 __ Push(proxy->name()); | 1584 __ Push(proxy->name()); |
1559 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1585 EmitCallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
1560 __ push(rax); | 1586 __ push(rax); |
1561 } else { | 1587 } else { |
1562 // This expression cannot throw a reference error at the top level. | 1588 // This expression cannot throw a reference error at the top level. |
1563 VisitForValue(expr->expression(), kStack); | 1589 VisitForValue(expr->expression(), kStack); |
1564 } | 1590 } |
1565 | 1591 |
1566 __ CallRuntime(Runtime::kTypeof, 1); | 1592 EmitCallRuntime(Runtime::kTypeof, 1); |
1567 Apply(context_, rax); | 1593 Apply(context_, rax); |
1568 break; | 1594 break; |
1569 } | 1595 } |
1570 | 1596 |
1571 case Token::ADD: { | 1597 case Token::ADD: { |
1572 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 1598 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
1573 VisitForValue(expr->expression(), kAccumulator); | 1599 VisitForValue(expr->expression(), kAccumulator); |
1574 Label no_conversion; | 1600 Label no_conversion; |
1575 Condition is_smi = masm_->CheckSmi(result_register()); | 1601 Condition is_smi = masm_->CheckSmi(result_register()); |
1576 __ j(is_smi, &no_conversion); | 1602 __ j(is_smi, &no_conversion); |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1982 __ movq(Operand(rsp, 0), rdx); | 2008 __ movq(Operand(rsp, 0), rdx); |
1983 // And return. | 2009 // And return. |
1984 __ ret(0); | 2010 __ ret(0); |
1985 } | 2011 } |
1986 | 2012 |
1987 | 2013 |
1988 #undef __ | 2014 #undef __ |
1989 | 2015 |
1990 | 2016 |
1991 } } // namespace v8::internal | 2017 } } // namespace v8::internal |
OLD | NEW |