OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_IA32 | 5 #if V8_TARGET_ARCH_IA32 |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/codegen.h" | 8 #include "src/codegen.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
(...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
950 __ j(not_sign, &loop); // While non-negative (to copy return address). | 950 __ j(not_sign, &loop); // While non-negative (to copy return address). |
951 __ pop(ebx); // Discard copy of return address. | 951 __ pop(ebx); // Discard copy of return address. |
952 __ dec(eax); // One fewer argument (first argument is new receiver). | 952 __ dec(eax); // One fewer argument (first argument is new receiver). |
953 } | 953 } |
954 | 954 |
955 // 4. Call the callable. | 955 // 4. Call the callable. |
956 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 956 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
957 } | 957 } |
958 | 958 |
959 | 959 |
| 960 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 961 const int vectorOffset, |
| 962 const int argumentsOffset, |
| 963 const int indexOffset, |
| 964 const int limitOffset) { |
| 965 // Copy all arguments from the array to the stack. |
| 966 Label entry, loop; |
| 967 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 968 Register key = LoadDescriptor::NameRegister(); |
| 969 Register slot = LoadDescriptor::SlotRegister(); |
| 970 Register vector = LoadWithVectorDescriptor::VectorRegister(); |
| 971 __ mov(key, Operand(ebp, indexOffset)); |
| 972 __ jmp(&entry); |
| 973 __ bind(&loop); |
| 974 __ mov(receiver, Operand(ebp, argumentsOffset)); // load arguments |
| 975 |
| 976 // Use inline caching to speed up access to arguments. |
| 977 int slot_index = TypeFeedbackVector::PushAppliedArgumentsIndex(); |
| 978 __ mov(slot, Immediate(Smi::FromInt(slot_index))); |
| 979 __ mov(vector, Operand(ebp, vectorOffset)); |
| 980 Handle<Code> ic = |
| 981 KeyedLoadICStub(masm->isolate(), LoadICState(kNoExtraICState)).GetCode(); |
| 982 __ call(ic, RelocInfo::CODE_TARGET); |
| 983 // It is important that we do not have a test instruction after the |
| 984 // call. A test instruction after the call is used to indicate that |
| 985 // we have generated an inline version of the keyed load. In this |
| 986 // case, we know that we are not generating a test instruction next. |
| 987 |
| 988 // Push the nth argument. |
| 989 __ push(eax); |
| 990 |
| 991 // Update the index on the stack and in register key. |
| 992 __ mov(key, Operand(ebp, indexOffset)); |
| 993 __ add(key, Immediate(1 << kSmiTagSize)); |
| 994 __ mov(Operand(ebp, indexOffset), key); |
| 995 |
| 996 __ bind(&entry); |
| 997 __ cmp(key, Operand(ebp, limitOffset)); |
| 998 __ j(not_equal, &loop); |
| 999 |
| 1000 // On exit, the pushed arguments count is in eax, untagged |
| 1001 __ Move(eax, key); |
| 1002 __ SmiUntag(eax); |
| 1003 } |
| 1004 |
| 1005 |
| 1006 // Used by FunctionApply and ReflectApply |
| 1007 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) { |
| 1008 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1009 const int kStackSize = kFormalParameters + 1; |
| 1010 |
| 1011 // Stack at entry: |
| 1012 // esp : return address |
| 1013 // esp[4] : arguments |
| 1014 // esp[8] : receiver ("this") |
| 1015 // esp[12] : function |
| 1016 { |
| 1017 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1018 // Stack frame: |
| 1019 // ebp : Old base pointer |
| 1020 // ebp[4] : return address |
| 1021 // ebp[8] : function arguments |
| 1022 // ebp[12] : receiver |
| 1023 // ebp[16] : function |
| 1024 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
| 1025 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
| 1026 static const int kFunctionOffset = kReceiverOffset + kPointerSize; |
| 1027 static const int kVectorOffset = |
| 1028 InternalFrameConstants::kCodeOffset - 1 * kPointerSize; |
| 1029 |
| 1030 // Push the vector. |
| 1031 __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 1032 __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFeedbackVectorOffset)); |
| 1033 __ push(edi); |
| 1034 |
| 1035 __ push(Operand(ebp, kFunctionOffset)); // push this |
| 1036 __ push(Operand(ebp, kArgumentsOffset)); // push arguments |
| 1037 if (targetIsArgument) { |
| 1038 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, |
| 1039 CALL_FUNCTION); |
| 1040 } else { |
| 1041 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); |
| 1042 } |
| 1043 |
| 1044 Generate_CheckStackOverflow(masm, kEaxIsSmiTagged); |
| 1045 |
| 1046 // Push current index and limit. |
| 1047 const int kLimitOffset = kVectorOffset - 1 * kPointerSize; |
| 1048 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
| 1049 __ Push(eax); // limit |
| 1050 __ Push(Immediate(0)); // index |
| 1051 __ Push(Operand(ebp, kReceiverOffset)); // receiver |
| 1052 |
| 1053 // Loop over the arguments array, pushing each value to the stack |
| 1054 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset, |
| 1055 kIndexOffset, kLimitOffset); |
| 1056 |
| 1057 // Call the callable. |
| 1058 // TODO(bmeurer): This should be a tail call according to ES6. |
| 1059 __ mov(edi, Operand(ebp, kFunctionOffset)); |
| 1060 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
| 1061 |
| 1062 // Leave internal frame. |
| 1063 } |
| 1064 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
| 1065 } |
| 1066 |
| 1067 |
| 1068 // Used by ReflectConstruct |
| 1069 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1070 const int kFormalParameters = 3; |
| 1071 const int kStackSize = kFormalParameters + 1; |
| 1072 |
| 1073 // Stack at entry: |
| 1074 // esp : return address |
| 1075 // esp[4] : new target |
| 1076 // esp[8] : arguments |
| 1077 // esp[16] : constructor |
| 1078 { |
| 1079 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1080 // Stack frame: |
| 1081 // ebp : Old base pointer |
| 1082 // ebp[4] : return address |
| 1083 // ebp[8] : new target |
| 1084 // ebp[12] : arguments |
| 1085 // ebp[16] : constructor |
| 1086 static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize; |
| 1087 static const int kArgumentsOffset = kNewTargetOffset + kPointerSize; |
| 1088 static const int kFunctionOffset = kArgumentsOffset + kPointerSize; |
| 1089 static const int kVectorOffset = |
| 1090 InternalFrameConstants::kCodeOffset - 1 * kPointerSize; |
| 1091 |
| 1092 // Push the vector. |
| 1093 __ mov(edi, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 1094 __ mov(edi, FieldOperand(edi, SharedFunctionInfo::kFeedbackVectorOffset)); |
| 1095 __ push(edi); |
| 1096 |
| 1097 // If newTarget is not supplied, set it to constructor |
| 1098 Label validate_arguments; |
| 1099 __ mov(eax, Operand(ebp, kNewTargetOffset)); |
| 1100 __ CompareRoot(eax, Heap::kUndefinedValueRootIndex); |
| 1101 __ j(not_equal, &validate_arguments, Label::kNear); |
| 1102 __ mov(eax, Operand(ebp, kFunctionOffset)); |
| 1103 __ mov(Operand(ebp, kNewTargetOffset), eax); |
| 1104 |
| 1105 // Validate arguments |
| 1106 __ bind(&validate_arguments); |
| 1107 __ push(Operand(ebp, kFunctionOffset)); |
| 1108 __ push(Operand(ebp, kArgumentsOffset)); |
| 1109 __ push(Operand(ebp, kNewTargetOffset)); |
| 1110 __ InvokeBuiltin(Context::REFLECT_CONSTRUCT_PREPARE_BUILTIN_INDEX, |
| 1111 CALL_FUNCTION); |
| 1112 |
| 1113 Generate_CheckStackOverflow(masm, kEaxIsSmiTagged); |
| 1114 |
| 1115 // Push current index and limit. |
| 1116 const int kLimitOffset = kVectorOffset - 1 * kPointerSize; |
| 1117 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
| 1118 __ Push(eax); // limit |
| 1119 __ push(Immediate(0)); // index |
| 1120 // Push the constructor function as callee. |
| 1121 __ push(Operand(ebp, kFunctionOffset)); |
| 1122 |
| 1123 // Loop over the arguments array, pushing each value to the stack |
| 1124 Generate_PushAppliedArguments(masm, kVectorOffset, kArgumentsOffset, |
| 1125 kIndexOffset, kLimitOffset); |
| 1126 |
| 1127 // Use undefined feedback vector |
| 1128 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); |
| 1129 __ mov(edi, Operand(ebp, kFunctionOffset)); |
| 1130 __ mov(edx, Operand(ebp, kNewTargetOffset)); |
| 1131 |
| 1132 // Call the function. |
| 1133 __ Call(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
| 1134 |
| 1135 // Leave internal frame. |
| 1136 } |
| 1137 // remove this, target, arguments, and newTarget |
| 1138 __ ret(kStackSize * kPointerSize); |
| 1139 } |
| 1140 |
| 1141 |
960 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 1142 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
961 // ----------- S t a t e ------------- | 1143 Generate_ApplyHelper(masm, false); |
962 // -- eax : argc | |
963 // -- esp[0] : return address | |
964 // -- esp[4] : argArray | |
965 // -- esp[8] : thisArg | |
966 // -- esp[12] : receiver | |
967 // ----------------------------------- | |
968 | |
969 // 1. Load receiver into edi, argArray into eax (if present), remove all | |
970 // arguments from the stack (including the receiver), and push thisArg (if | |
971 // present) instead. | |
972 { | |
973 Label no_arg_array, no_this_arg; | |
974 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); | |
975 __ mov(ebx, edx); | |
976 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | |
977 __ test(eax, eax); | |
978 __ j(zero, &no_this_arg, Label::kNear); | |
979 { | |
980 __ mov(edx, Operand(esp, eax, times_pointer_size, 0)); | |
981 __ cmp(eax, Immediate(1)); | |
982 __ j(equal, &no_arg_array, Label::kNear); | |
983 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize)); | |
984 __ bind(&no_arg_array); | |
985 } | |
986 __ bind(&no_this_arg); | |
987 __ PopReturnAddressTo(ecx); | |
988 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); | |
989 __ Push(edx); | |
990 __ PushReturnAddressFrom(ecx); | |
991 __ Move(eax, ebx); | |
992 } | |
993 | |
994 // ----------- S t a t e ------------- | |
995 // -- eax : argArray | |
996 // -- edi : receiver | |
997 // -- esp[0] : return address | |
998 // -- esp[4] : thisArg | |
999 // ----------------------------------- | |
1000 | |
1001 // 2. Make sure the receiver is actually callable. | |
1002 Label receiver_not_callable; | |
1003 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear); | |
1004 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); | |
1005 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); | |
1006 __ j(zero, &receiver_not_callable, Label::kNear); | |
1007 | |
1008 // 3. Tail call with no arguments if argArray is null or undefined. | |
1009 Label no_arguments; | |
1010 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); | |
1011 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments, | |
1012 Label::kNear); | |
1013 | |
1014 // 4a. Apply the receiver to the given argArray (passing undefined for | |
1015 // new.target). | |
1016 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); | |
1017 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); | |
1018 | |
1019 // 4b. The argArray is either null or undefined, so we tail call without any | |
1020 // arguments to the receiver. | |
1021 __ bind(&no_arguments); | |
1022 { | |
1023 __ Set(eax, 0); | |
1024 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | |
1025 } | |
1026 | |
1027 // 4c. The receiver is not callable, throw an appropriate TypeError. | |
1028 __ bind(&receiver_not_callable); | |
1029 { | |
1030 __ mov(Operand(esp, kPointerSize), edi); | |
1031 __ TailCallRuntime(Runtime::kThrowApplyNonFunction, 1, 1); | |
1032 } | |
1033 } | 1144 } |
1034 | 1145 |
1035 | 1146 |
1036 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { | 1147 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { |
1037 // ----------- S t a t e ------------- | 1148 Generate_ApplyHelper(masm, true); |
1038 // -- eax : argc | |
1039 // -- esp[0] : return address | |
1040 // -- esp[4] : argumentsList | |
1041 // -- esp[8] : thisArgument | |
1042 // -- esp[12] : target | |
1043 // -- esp[16] : receiver | |
1044 // ----------------------------------- | |
1045 | |
1046 // 1. Load target into edi (if present), argumentsList into eax (if present), | |
1047 // remove all arguments from the stack (including the receiver), and push | |
1048 // thisArgument (if present) instead. | |
1049 { | |
1050 Label done; | |
1051 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); | |
1052 __ mov(edx, edi); | |
1053 __ mov(ebx, edi); | |
1054 __ cmp(eax, Immediate(1)); | |
1055 __ j(below, &done, Label::kNear); | |
1056 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); | |
1057 __ j(equal, &done, Label::kNear); | |
1058 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); | |
1059 __ cmp(eax, Immediate(3)); | |
1060 __ j(below, &done, Label::kNear); | |
1061 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); | |
1062 __ bind(&done); | |
1063 __ PopReturnAddressTo(ecx); | |
1064 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); | |
1065 __ Push(edx); | |
1066 __ PushReturnAddressFrom(ecx); | |
1067 __ Move(eax, ebx); | |
1068 } | |
1069 | |
1070 // ----------- S t a t e ------------- | |
1071 // -- eax : argumentsList | |
1072 // -- edi : target | |
1073 // -- esp[0] : return address | |
1074 // -- esp[4] : thisArgument | |
1075 // ----------------------------------- | |
1076 | |
1077 // 2. Make sure the target is actually callable. | |
1078 Label target_not_callable; | |
1079 __ JumpIfSmi(edi, &target_not_callable, Label::kNear); | |
1080 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); | |
1081 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); | |
1082 __ j(zero, &target_not_callable, Label::kNear); | |
1083 | |
1084 // 3a. Apply the target to the given argumentsList (passing undefined for | |
1085 // new.target). | |
1086 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); | |
1087 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); | |
1088 | |
1089 // 3b. The target is not callable, throw an appropriate TypeError. | |
1090 __ bind(&target_not_callable); | |
1091 { | |
1092 __ mov(Operand(esp, kPointerSize), edi); | |
1093 __ TailCallRuntime(Runtime::kThrowApplyNonFunction, 1, 1); | |
1094 } | |
1095 } | 1149 } |
1096 | 1150 |
1097 | 1151 |
1098 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { | 1152 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { |
1099 // ----------- S t a t e ------------- | 1153 Generate_ConstructHelper(masm); |
1100 // -- eax : argc | 1154 } |
1101 // -- esp[0] : return address | 1155 |
1102 // -- esp[4] : new.target (optional) | 1156 |
1103 // -- esp[8] : argumentsList | |
1104 // -- esp[12] : target | |
1105 // -- esp[16] : receiver | |
1106 // ----------------------------------- | |
1107 | |
1108 // 1. Load target into edi (if present), argumentsList into eax (if present), | |
1109 // new.target into edx (if present, otherwise use target), remove all | |
1110 // arguments from the stack (including the receiver), and push thisArgument | |
1111 // (if present) instead. | |
1112 { | |
1113 Label done; | |
1114 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); | |
1115 __ mov(edx, edi); | |
1116 __ mov(ebx, edi); | |
1117 __ cmp(eax, Immediate(1)); | |
1118 __ j(below, &done, Label::kNear); | |
1119 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); | |
1120 __ mov(edx, edi); | |
1121 __ j(equal, &done, Label::kNear); | |
1122 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); | |
1123 __ cmp(eax, Immediate(3)); | |
1124 __ j(below, &done, Label::kNear); | |
1125 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); | |
1126 __ bind(&done); | |
1127 __ PopReturnAddressTo(ecx); | |
1128 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); | |
1129 __ PushRoot(Heap::kUndefinedValueRootIndex); | |
1130 __ PushReturnAddressFrom(ecx); | |
1131 __ Move(eax, ebx); | |
1132 } | |
1133 | |
1134 // ----------- S t a t e ------------- | |
1135 // -- eax : argumentsList | |
1136 // -- edx : new.target | |
1137 // -- edi : target | |
1138 // -- esp[0] : return address | |
1139 // -- esp[4] : receiver (undefined) | |
1140 // ----------------------------------- | |
1141 | |
1142 // 2. Make sure the target is actually a constructor. | |
1143 Label target_not_constructor; | |
1144 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear); | |
1145 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); | |
1146 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); | |
1147 __ j(zero, &target_not_constructor, Label::kNear); | |
1148 | |
1149 // 3. Make sure the target is actually a constructor. | |
1150 Label new_target_not_constructor; | |
1151 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear); | |
1152 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
1153 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); | |
1154 __ j(zero, &new_target_not_constructor, Label::kNear); | |
1155 | |
1156 // 4a. Construct the target with the given new.target and argumentsList. | |
1157 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); | |
1158 | |
1159 // 4b. The target is not a constructor, throw an appropriate TypeError. | |
1160 __ bind(&target_not_constructor); | |
1161 { | |
1162 __ mov(Operand(esp, kPointerSize), edi); | |
1163 __ TailCallRuntime(Runtime::kThrowCalledNonCallable, 1, 1); | |
1164 } | |
1165 | |
1166 // 4c. The new.target is not a constructor, throw an appropriate TypeError. | |
1167 __ bind(&new_target_not_constructor); | |
1168 { | |
1169 __ mov(Operand(esp, kPointerSize), edx); | |
1170 __ TailCallRuntime(Runtime::kThrowCalledNonCallable, 1, 1); | |
1171 } | |
1172 } | |
1173 | |
1174 | |
1175 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { | 1157 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
1176 // ----------- S t a t e ------------- | 1158 // ----------- S t a t e ------------- |
1177 // -- eax : argc | 1159 // -- eax : argc |
1178 // -- esp[0] : return address | 1160 // -- esp[0] : return address |
1179 // -- esp[4] : last argument | 1161 // -- esp[4] : last argument |
1180 // ----------------------------------- | 1162 // ----------------------------------- |
1181 Label generic_array_code; | 1163 Label generic_array_code; |
1182 | 1164 |
1183 // Get the InternalArray function. | 1165 // Get the InternalArray function. |
1184 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); | 1166 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1433 __ leave(); | 1415 __ leave(); |
1434 | 1416 |
1435 // Remove caller arguments from the stack. | 1417 // Remove caller arguments from the stack. |
1436 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1418 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
1437 __ pop(ecx); | 1419 __ pop(ecx); |
1438 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 1420 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
1439 __ push(ecx); | 1421 __ push(ecx); |
1440 } | 1422 } |
1441 | 1423 |
1442 | 1424 |
1443 // static | |
1444 void Builtins::Generate_Apply(MacroAssembler* masm) { | |
1445 // ----------- S t a t e ------------- | |
1446 // -- eax : argumentsList | |
1447 // -- edi : target | |
1448 // -- edx : new.target (checked to be constructor or undefined) | |
1449 // -- esp[0] : return address. | |
1450 // -- esp[4] : thisArgument | |
1451 // ----------------------------------- | |
1452 | |
1453 // Create the list of arguments from the array-like argumentsList. | |
1454 { | |
1455 Label create_arguments, create_array, create_runtime, done_create; | |
1456 __ JumpIfSmi(eax, &create_runtime); | |
1457 | |
1458 // Load the map of argumentsList into ecx. | |
1459 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
1460 | |
1461 // Load native context into ebx. | |
1462 __ mov(ebx, NativeContextOperand()); | |
1463 | |
1464 // Check if argumentsList is an (unmodified) arguments object. | |
1465 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX)); | |
1466 __ j(equal, &create_arguments); | |
1467 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX)); | |
1468 __ j(equal, &create_arguments); | |
1469 | |
1470 // Check if argumentsList is a fast JSArray. | |
1471 __ CmpInstanceType(ecx, JS_ARRAY_TYPE); | |
1472 __ j(equal, &create_array); | |
1473 | |
1474 // Ask the runtime to create the list (actually a FixedArray). | |
1475 __ bind(&create_runtime); | |
1476 { | |
1477 FrameScope scope(masm, StackFrame::INTERNAL); | |
1478 __ Push(edi); | |
1479 __ Push(edx); | |
1480 __ Push(eax); | |
1481 __ CallRuntime(Runtime::kCreateListFromArrayLike, 1); | |
1482 __ Pop(edx); | |
1483 __ Pop(edi); | |
1484 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset)); | |
1485 __ SmiUntag(ebx); | |
1486 } | |
1487 __ jmp(&done_create); | |
1488 | |
1489 // Try to create the list from an arguments object. | |
1490 __ bind(&create_arguments); | |
1491 __ mov(ebx, | |
1492 FieldOperand(eax, JSObject::kHeaderSize + | |
1493 Heap::kArgumentsLengthIndex * kPointerSize)); | |
1494 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset)); | |
1495 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); | |
1496 __ j(not_equal, &create_runtime); | |
1497 __ SmiUntag(ebx); | |
1498 __ mov(eax, ecx); | |
1499 __ jmp(&done_create); | |
1500 | |
1501 // Try to create the list from a JSArray object. | |
1502 __ bind(&create_array); | |
1503 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); | |
1504 __ DecodeField<Map::ElementsKindBits>(ecx); | |
1505 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); | |
1506 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | |
1507 STATIC_ASSERT(FAST_ELEMENTS == 2); | |
1508 __ cmp(ecx, Immediate(FAST_ELEMENTS)); | |
1509 __ j(above, &create_runtime); | |
1510 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS)); | |
1511 __ j(equal, &create_runtime); | |
1512 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset)); | |
1513 __ SmiUntag(ebx); | |
1514 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset)); | |
1515 | |
1516 __ bind(&done_create); | |
1517 } | |
1518 | |
1519 // Check for stack overflow. | |
1520 { | |
1521 // Check the stack for overflow. We are not trying to catch interruptions | |
1522 // (i.e. debug break and preemption) here, so check the "real stack limit". | |
1523 Label done; | |
1524 ExternalReference real_stack_limit = | |
1525 ExternalReference::address_of_real_stack_limit(masm->isolate()); | |
1526 __ mov(ecx, Operand::StaticVariable(real_stack_limit)); | |
1527 // Make ecx the space we have left. The stack might already be overflowed | |
1528 // here which will cause ecx to become negative. | |
1529 __ neg(ecx); | |
1530 __ add(ecx, esp); | |
1531 __ sar(ecx, kPointerSizeLog2); | |
1532 // Check if the arguments will overflow the stack. | |
1533 __ cmp(ecx, ebx); | |
1534 __ j(greater, &done, Label::kNear); // Signed comparison. | |
1535 __ TailCallRuntime(Runtime::kThrowStackOverflow, 1, 1); | |
1536 __ bind(&done); | |
1537 } | |
1538 | |
1539 // ----------- S t a t e ------------- | |
1540 // -- edi : target | |
1541 // -- eax : args (a FixedArray built from argumentsList) | |
1542 // -- ebx : len (number of elements to push from args) | |
1543 // -- edx : new.target (checked to be constructor or undefined) | |
1544 // -- esp[0] : return address. | |
1545 // -- esp[4] : thisArgument | |
1546 // ----------------------------------- | |
1547 | |
1548 // Push arguments onto the stack (thisArgument is already on the stack). | |
1549 { | |
1550 __ movd(xmm0, edx); | |
1551 __ PopReturnAddressTo(edx); | |
1552 __ Move(ecx, Immediate(0)); | |
1553 Label done, loop; | |
1554 __ bind(&loop); | |
1555 __ cmp(ecx, ebx); | |
1556 __ j(equal, &done, Label::kNear); | |
1557 __ Push( | |
1558 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize)); | |
1559 __ inc(ecx); | |
1560 __ jmp(&loop); | |
1561 __ bind(&done); | |
1562 __ PushReturnAddressFrom(edx); | |
1563 __ movd(edx, xmm0); | |
1564 __ Move(eax, ebx); | |
1565 } | |
1566 | |
1567 // Dispatch to Call or Construct depending on whether new.target is undefined. | |
1568 { | |
1569 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex); | |
1570 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | |
1571 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | |
1572 } | |
1573 } | |
1574 | |
1575 | |
1576 // static | 1425 // static |
1577 void Builtins::Generate_CallFunction(MacroAssembler* masm, | 1426 void Builtins::Generate_CallFunction(MacroAssembler* masm, |
1578 ConvertReceiverMode mode) { | 1427 ConvertReceiverMode mode) { |
1579 // ----------- S t a t e ------------- | 1428 // ----------- S t a t e ------------- |
1580 // -- eax : the number of arguments (not including the receiver) | 1429 // -- eax : the number of arguments (not including the receiver) |
1581 // -- edi : the function to call (checked to be a JSFunction) | 1430 // -- edi : the function to call (checked to be a JSFunction) |
1582 // ----------------------------------- | 1431 // ----------------------------------- |
1583 __ AssertFunction(edi); | 1432 __ AssertFunction(edi); |
1584 | 1433 |
1585 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) | 1434 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2131 | 1980 |
2132 __ bind(&ok); | 1981 __ bind(&ok); |
2133 __ ret(0); | 1982 __ ret(0); |
2134 } | 1983 } |
2135 | 1984 |
2136 #undef __ | 1985 #undef __ |
2137 } // namespace internal | 1986 } // namespace internal |
2138 } // namespace v8 | 1987 } // namespace v8 |
2139 | 1988 |
2140 #endif // V8_TARGET_ARCH_IA32 | 1989 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |