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