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 938 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) { | 949 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) { |
950 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); | 950 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); |
951 } | 951 } |
952 | 952 |
953 | 953 |
954 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { | 954 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { |
955 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); | 955 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); |
956 } | 956 } |
957 | 957 |
958 | 958 |
959 // static | |
960 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | 959 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
961 // Stack Layout: | 960 Factory* factory = masm->isolate()->factory(); |
962 // esp[0] : Return address | 961 |
963 // esp[8] : Argument n | |
964 // esp[16] : Argument n-1 | |
965 // ... | |
966 // esp[8 * n] : Argument 1 | |
967 // esp[8 * (n + 1)] : Receiver (callable to call) | |
968 // | |
969 // eax contains the number of arguments, n, not counting the receiver. | |
970 // | |
971 // 1. Make sure we have at least one argument. | 962 // 1. Make sure we have at least one argument. |
972 { | 963 { Label done; |
973 Label done; | |
974 __ test(eax, eax); | 964 __ test(eax, eax); |
975 __ j(not_zero, &done, Label::kNear); | 965 __ j(not_zero, &done); |
976 __ PopReturnAddressTo(ebx); | 966 __ pop(ebx); |
977 __ PushRoot(Heap::kUndefinedValueRootIndex); | 967 __ push(Immediate(factory->undefined_value())); |
978 __ PushReturnAddressFrom(ebx); | 968 __ push(ebx); |
979 __ inc(eax); | 969 __ inc(eax); |
980 __ bind(&done); | 970 __ bind(&done); |
981 } | 971 } |
982 | 972 |
983 // 2. Get the callable to call (passed as receiver) from the stack. | 973 // 2. Get the function to call (passed as receiver) from the stack, check |
984 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | 974 // if it is a function. |
| 975 Label slow, non_function; |
| 976 // 1 ~ return address. |
| 977 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
| 978 __ JumpIfSmi(edi, &non_function); |
| 979 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 980 __ j(not_equal, &slow); |
985 | 981 |
986 // 3. Shift arguments and return address one slot down on the stack | 982 |
| 983 // 3a. Patch the first argument if necessary when calling a function. |
| 984 Label shift_arguments; |
| 985 __ Move(edx, Immediate(0)); // indicate regular JS_FUNCTION |
| 986 { Label convert_to_object, use_global_proxy, patch_receiver; |
| 987 // Change context eagerly in case we need the global receiver. |
| 988 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 989 |
| 990 // Do not transform the receiver for strict mode functions. |
| 991 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 992 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), |
| 993 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
| 994 __ j(not_equal, &shift_arguments); |
| 995 |
| 996 // Do not transform the receiver for natives (shared already in ebx). |
| 997 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset), |
| 998 1 << SharedFunctionInfo::kNativeBitWithinByte); |
| 999 __ j(not_equal, &shift_arguments); |
| 1000 |
| 1001 // Compute the receiver in sloppy mode. |
| 1002 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. |
| 1003 |
| 1004 // Call ToObject on the receiver if it is not an object, or use the |
| 1005 // global object if it is null or undefined. |
| 1006 __ JumpIfSmi(ebx, &convert_to_object); |
| 1007 __ cmp(ebx, factory->null_value()); |
| 1008 __ j(equal, &use_global_proxy); |
| 1009 __ cmp(ebx, factory->undefined_value()); |
| 1010 __ j(equal, &use_global_proxy); |
| 1011 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 1012 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 1013 __ j(above_equal, &shift_arguments); |
| 1014 |
| 1015 __ bind(&convert_to_object); |
| 1016 |
| 1017 { // In order to preserve argument count. |
| 1018 FrameScope scope(masm, StackFrame::INTERNAL); |
| 1019 __ SmiTag(eax); |
| 1020 __ push(eax); |
| 1021 |
| 1022 __ mov(eax, ebx); |
| 1023 ToObjectStub stub(masm->isolate()); |
| 1024 __ CallStub(&stub); |
| 1025 __ mov(ebx, eax); |
| 1026 __ Move(edx, Immediate(0)); // restore |
| 1027 |
| 1028 __ pop(eax); |
| 1029 __ SmiUntag(eax); |
| 1030 } |
| 1031 |
| 1032 // Restore the function to edi. |
| 1033 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); |
| 1034 __ jmp(&patch_receiver); |
| 1035 |
| 1036 __ bind(&use_global_proxy); |
| 1037 __ mov(ebx, |
| 1038 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 1039 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); |
| 1040 |
| 1041 __ bind(&patch_receiver); |
| 1042 __ mov(Operand(esp, eax, times_4, 0), ebx); |
| 1043 |
| 1044 __ jmp(&shift_arguments); |
| 1045 } |
| 1046 |
| 1047 // 3b. Check for function proxy. |
| 1048 __ bind(&slow); |
| 1049 __ Move(edx, Immediate(1)); // indicate function proxy |
| 1050 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); |
| 1051 __ j(equal, &shift_arguments); |
| 1052 __ bind(&non_function); |
| 1053 __ Move(edx, Immediate(2)); // indicate non-function |
| 1054 |
| 1055 // 3c. Patch the first argument when calling a non-function. The |
| 1056 // CALL_NON_FUNCTION builtin expects the non-function callee as |
| 1057 // receiver, so overwrite the first argument which will ultimately |
| 1058 // become the receiver. |
| 1059 __ mov(Operand(esp, eax, times_4, 0), edi); |
| 1060 |
| 1061 // 4. Shift arguments and return address one slot down on the stack |
987 // (overwriting the original receiver). Adjust argument count to make | 1062 // (overwriting the original receiver). Adjust argument count to make |
988 // the original first argument the new receiver. | 1063 // the original first argument the new receiver. |
989 { | 1064 __ bind(&shift_arguments); |
990 Label loop; | 1065 { Label loop; |
991 __ mov(ecx, eax); | 1066 __ mov(ecx, eax); |
992 __ bind(&loop); | 1067 __ bind(&loop); |
993 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0)); | 1068 __ mov(ebx, Operand(esp, ecx, times_4, 0)); |
994 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx); | 1069 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); |
995 __ dec(ecx); | 1070 __ dec(ecx); |
996 __ j(not_sign, &loop); // While non-negative (to copy return address). | 1071 __ j(not_sign, &loop); // While non-negative (to copy return address). |
997 __ pop(ebx); // Discard copy of return address. | 1072 __ pop(ebx); // Discard copy of return address. |
998 __ dec(eax); // One fewer argument (first argument is new receiver). | 1073 __ dec(eax); // One fewer argument (first argument is new receiver). |
999 } | 1074 } |
1000 | 1075 |
1001 // 4. Call the callable. | 1076 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, |
1002 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 1077 // or a function proxy via CALL_FUNCTION_PROXY. |
| 1078 { Label function, non_proxy; |
| 1079 __ test(edx, edx); |
| 1080 __ j(zero, &function); |
| 1081 __ Move(ebx, Immediate(0)); |
| 1082 __ cmp(edx, Immediate(1)); |
| 1083 __ j(not_equal, &non_proxy); |
| 1084 |
| 1085 __ pop(edx); // return address |
| 1086 __ push(edi); // re-add proxy object as additional argument |
| 1087 __ push(edx); |
| 1088 __ inc(eax); |
| 1089 __ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX); |
| 1090 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 1091 RelocInfo::CODE_TARGET); |
| 1092 |
| 1093 __ bind(&non_proxy); |
| 1094 __ GetBuiltinEntry(edx, Context::CALL_NON_FUNCTION_BUILTIN_INDEX); |
| 1095 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 1096 RelocInfo::CODE_TARGET); |
| 1097 __ bind(&function); |
| 1098 } |
| 1099 |
| 1100 // 5b. Get the code to call from the function and check that the number of |
| 1101 // expected arguments matches what we're providing. If so, jump |
| 1102 // (tail-call) to the code in register edx without checking arguments. |
| 1103 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 1104 __ mov(ebx, |
| 1105 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 1106 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); |
| 1107 __ SmiUntag(ebx); |
| 1108 __ cmp(eax, ebx); |
| 1109 __ j(not_equal, |
| 1110 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); |
| 1111 |
| 1112 ParameterCount expected(0); |
| 1113 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); |
1003 } | 1114 } |
1004 | 1115 |
1005 | 1116 |
1006 static void Generate_PushAppliedArguments(MacroAssembler* masm, | 1117 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
1007 const int argumentsOffset, | 1118 const int argumentsOffset, |
1008 const int indexOffset, | 1119 const int indexOffset, |
1009 const int limitOffset) { | 1120 const int limitOffset) { |
1010 // Copy all arguments from the array to the stack. | 1121 // Copy all arguments from the array to the stack. |
1011 Label entry, loop; | 1122 Label entry, loop; |
1012 Register receiver = LoadDescriptor::ReceiverRegister(); | 1123 Register receiver = LoadDescriptor::ReceiverRegister(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 // Stack frame: | 1178 // Stack frame: |
1068 // ebp : Old base pointer | 1179 // ebp : Old base pointer |
1069 // ebp[4] : return address | 1180 // ebp[4] : return address |
1070 // ebp[8] : function arguments | 1181 // ebp[8] : function arguments |
1071 // ebp[12] : receiver | 1182 // ebp[12] : receiver |
1072 // ebp[16] : function | 1183 // ebp[16] : function |
1073 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; | 1184 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
1074 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; | 1185 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
1075 static const int kFunctionOffset = kReceiverOffset + kPointerSize; | 1186 static const int kFunctionOffset = kReceiverOffset + kPointerSize; |
1076 | 1187 |
1077 __ push(Operand(ebp, kFunctionOffset)); // push this | 1188 __ push(Operand(ebp, kFunctionOffset)); // push this |
1078 __ push(Operand(ebp, kArgumentsOffset)); // push arguments | 1189 __ push(Operand(ebp, kArgumentsOffset)); // push arguments |
1079 if (targetIsArgument) { | 1190 if (targetIsArgument) { |
1080 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, | 1191 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, |
1081 CALL_FUNCTION); | 1192 CALL_FUNCTION); |
1082 } else { | 1193 } else { |
1083 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); | 1194 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); |
1084 } | 1195 } |
1085 | 1196 |
1086 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged); | 1197 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged); |
1087 | 1198 |
1088 // Push current index and limit. | 1199 // Push current index and limit. |
1089 const int kLimitOffset = | 1200 const int kLimitOffset = |
1090 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 1201 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
1091 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 1202 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
1092 __ Push(eax); // limit | 1203 __ push(eax); // limit |
1093 __ Push(Immediate(0)); // index | 1204 __ push(Immediate(0)); // index |
1094 __ Push(Operand(ebp, kReceiverOffset)); // receiver | 1205 |
| 1206 // Get the receiver. |
| 1207 __ mov(ebx, Operand(ebp, kReceiverOffset)); |
| 1208 |
| 1209 // Check that the function is a JS function (otherwise it must be a proxy). |
| 1210 Label push_receiver, use_global_proxy; |
| 1211 __ mov(edi, Operand(ebp, kFunctionOffset)); |
| 1212 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 1213 __ j(not_equal, &push_receiver); |
| 1214 |
| 1215 // Change context eagerly to get the right global object if necessary. |
| 1216 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 1217 |
| 1218 // Compute the receiver. |
| 1219 // Do not transform the receiver for strict mode functions. |
| 1220 Label call_to_object; |
| 1221 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 1222 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), |
| 1223 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
| 1224 __ j(not_equal, &push_receiver); |
| 1225 |
| 1226 Factory* factory = masm->isolate()->factory(); |
| 1227 |
| 1228 // Do not transform the receiver for natives (shared already in ecx). |
| 1229 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), |
| 1230 1 << SharedFunctionInfo::kNativeBitWithinByte); |
| 1231 __ j(not_equal, &push_receiver); |
| 1232 |
| 1233 // Compute the receiver in sloppy mode. |
| 1234 // Call ToObject on the receiver if it is not an object, or use the |
| 1235 // global object if it is null or undefined. |
| 1236 __ JumpIfSmi(ebx, &call_to_object); |
| 1237 __ cmp(ebx, factory->null_value()); |
| 1238 __ j(equal, &use_global_proxy); |
| 1239 __ cmp(ebx, factory->undefined_value()); |
| 1240 __ j(equal, &use_global_proxy); |
| 1241 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 1242 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 1243 __ j(above_equal, &push_receiver); |
| 1244 |
| 1245 __ bind(&call_to_object); |
| 1246 __ mov(eax, ebx); |
| 1247 ToObjectStub stub(masm->isolate()); |
| 1248 __ CallStub(&stub); |
| 1249 __ mov(ebx, eax); |
| 1250 __ jmp(&push_receiver); |
| 1251 |
| 1252 __ bind(&use_global_proxy); |
| 1253 __ mov(ebx, |
| 1254 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 1255 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); |
| 1256 |
| 1257 // Push the receiver. |
| 1258 __ bind(&push_receiver); |
| 1259 __ push(ebx); |
1095 | 1260 |
1096 // Loop over the arguments array, pushing each value to the stack | 1261 // Loop over the arguments array, pushing each value to the stack |
1097 Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset, | 1262 Generate_PushAppliedArguments( |
1098 kLimitOffset); | 1263 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
1099 | 1264 |
1100 // Call the callable. | 1265 // Call the function. |
1101 // TODO(bmeurer): This should be a tail call according to ES6. | 1266 Label call_proxy; |
| 1267 ParameterCount actual(eax); |
1102 __ mov(edi, Operand(ebp, kFunctionOffset)); | 1268 __ mov(edi, Operand(ebp, kFunctionOffset)); |
1103 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 1269 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
| 1270 __ j(not_equal, &call_proxy); |
| 1271 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper()); |
| 1272 |
| 1273 frame_scope.GenerateLeaveFrame(); |
| 1274 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
| 1275 |
| 1276 // Call the function proxy. |
| 1277 __ bind(&call_proxy); |
| 1278 __ push(edi); // add function proxy as last argument |
| 1279 __ inc(eax); |
| 1280 __ Move(ebx, Immediate(0)); |
| 1281 __ GetBuiltinEntry(edx, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX); |
| 1282 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
| 1283 RelocInfo::CODE_TARGET); |
1104 | 1284 |
1105 // Leave internal frame. | 1285 // Leave internal frame. |
1106 } | 1286 } |
1107 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments | 1287 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1108 } | 1288 } |
1109 | 1289 |
1110 | 1290 |
1111 // Used by ReflectConstruct | 1291 // Used by ReflectConstruct |
1112 static void Generate_ConstructHelper(MacroAssembler* masm) { | 1292 static void Generate_ConstructHelper(MacroAssembler* masm) { |
1113 const int kFormalParameters = 3; | 1293 const int kFormalParameters = 3; |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1430 __ leave(); | 1610 __ leave(); |
1431 | 1611 |
1432 // Remove caller arguments from the stack. | 1612 // Remove caller arguments from the stack. |
1433 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1613 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
1434 __ pop(ecx); | 1614 __ pop(ecx); |
1435 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 1615 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
1436 __ push(ecx); | 1616 __ push(ecx); |
1437 } | 1617 } |
1438 | 1618 |
1439 | 1619 |
1440 // static | |
1441 void Builtins::Generate_CallFunction(MacroAssembler* masm) { | |
1442 // ----------- S t a t e ------------- | |
1443 // -- eax : the number of arguments (not including the receiver) | |
1444 // -- edi : the function to call (checked to be a JSFunction) | |
1445 // ----------------------------------- | |
1446 | |
1447 Label convert, convert_global_proxy, convert_to_object, done_convert; | |
1448 __ AssertFunction(edi); | |
1449 // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal | |
1450 // slot is "classConstructor". | |
1451 // Enter the context of the function; ToObject has to run in the function | |
1452 // context, and we also need to take the global proxy from the function | |
1453 // context in case of conversion. | |
1454 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) | |
1455 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset == | |
1456 SharedFunctionInfo::kStrictModeByteOffset); | |
1457 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | |
1458 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
1459 // We need to convert the receiver for non-native sloppy mode functions. | |
1460 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset), | |
1461 (1 << SharedFunctionInfo::kNativeBitWithinByte) | | |
1462 (1 << SharedFunctionInfo::kStrictModeBitWithinByte)); | |
1463 __ j(not_zero, &done_convert); | |
1464 { | |
1465 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize)); | |
1466 | |
1467 // ----------- S t a t e ------------- | |
1468 // -- eax : the number of arguments (not including the receiver) | |
1469 // -- ecx : the receiver | |
1470 // -- edx : the shared function info. | |
1471 // -- edi : the function to call (checked to be a JSFunction) | |
1472 // -- esi : the function context. | |
1473 // ----------------------------------- | |
1474 | |
1475 Label convert_receiver; | |
1476 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear); | |
1477 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | |
1478 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx); | |
1479 __ j(above_equal, &done_convert); | |
1480 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, &convert_global_proxy, | |
1481 Label::kNear); | |
1482 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object, | |
1483 Label::kNear); | |
1484 __ bind(&convert_global_proxy); | |
1485 { | |
1486 // Patch receiver to global proxy. | |
1487 __ LoadGlobalProxy(ecx); | |
1488 } | |
1489 __ jmp(&convert_receiver); | |
1490 __ bind(&convert_to_object); | |
1491 { | |
1492 // Convert receiver using ToObject. | |
1493 // TODO(bmeurer): Inline the allocation here to avoid building the frame | |
1494 // in the fast case? (fall back to AllocateInNewSpace?) | |
1495 FrameScope scope(masm, StackFrame::INTERNAL); | |
1496 __ SmiTag(eax); | |
1497 __ Push(eax); | |
1498 __ Push(edi); | |
1499 __ mov(eax, ecx); | |
1500 ToObjectStub stub(masm->isolate()); | |
1501 __ CallStub(&stub); | |
1502 __ mov(ecx, eax); | |
1503 __ Pop(edi); | |
1504 __ Pop(eax); | |
1505 __ SmiUntag(eax); | |
1506 } | |
1507 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | |
1508 __ bind(&convert_receiver); | |
1509 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx); | |
1510 } | |
1511 __ bind(&done_convert); | |
1512 | |
1513 // ----------- S t a t e ------------- | |
1514 // -- eax : the number of arguments (not including the receiver) | |
1515 // -- edx : the shared function info. | |
1516 // -- edi : the function to call (checked to be a JSFunction) | |
1517 // -- esi : the function context. | |
1518 // ----------------------------------- | |
1519 | |
1520 __ mov(ebx, | |
1521 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); | |
1522 __ SmiUntag(ebx); | |
1523 ParameterCount actual(eax); | |
1524 ParameterCount expected(ebx); | |
1525 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), expected, | |
1526 actual, JUMP_FUNCTION, NullCallWrapper()); | |
1527 } | |
1528 | |
1529 | |
1530 // static | |
1531 void Builtins::Generate_Call(MacroAssembler* masm) { | |
1532 // ----------- S t a t e ------------- | |
1533 // -- eax : the number of arguments (not including the receiver) | |
1534 // -- edi : the target to call (can be any Object). | |
1535 // ----------------------------------- | |
1536 | |
1537 Label non_smi, non_function; | |
1538 __ JumpIfSmi(edi, &non_function); | |
1539 __ bind(&non_smi); | |
1540 __ CmpObjectType(edi, JS_FUNCTION_TYPE, edx); | |
1541 __ j(equal, masm->isolate()->builtins()->CallFunction(), | |
1542 RelocInfo::CODE_TARGET); | |
1543 __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE); | |
1544 __ j(not_equal, &non_function); | |
1545 | |
1546 // 1. Call to function proxy. | |
1547 // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies. | |
1548 __ mov(edi, FieldOperand(edi, JSFunctionProxy::kCallTrapOffset)); | |
1549 __ AssertNotSmi(edi); | |
1550 __ jmp(&non_smi); | |
1551 | |
1552 // 2. Call to something else, which might have a [[Call]] internal method (if | |
1553 // not we raise an exception). | |
1554 __ bind(&non_function); | |
1555 // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could | |
1556 // be awesome instead; i.e. a trivial improvement would be to call into the | |
1557 // runtime and just deal with the API function there instead of returning a | |
1558 // delegate from a runtime call that just jumps back to the runtime once | |
1559 // called. Or, bonus points, call directly into the C API function here, as | |
1560 // we do in some Crankshaft fast cases. | |
1561 // Overwrite the original receiver with the (original) target. | |
1562 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); | |
1563 { | |
1564 // Determine the delegate for the target (if any). | |
1565 FrameScope scope(masm, StackFrame::INTERNAL); | |
1566 __ SmiTag(eax); | |
1567 __ Push(eax); | |
1568 __ Push(edi); | |
1569 __ CallRuntime(Runtime::kGetFunctionDelegate, 1); | |
1570 __ mov(edi, eax); | |
1571 __ Pop(eax); | |
1572 __ SmiUntag(eax); | |
1573 } | |
1574 // The delegate is always a regular function. | |
1575 __ AssertFunction(edi); | |
1576 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET); | |
1577 } | |
1578 | |
1579 | |
1580 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 1620 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
1581 // ----------- S t a t e ------------- | 1621 // ----------- S t a t e ------------- |
1582 // -- eax : actual number of arguments | 1622 // -- eax : actual number of arguments |
1583 // -- ebx : expected number of arguments | 1623 // -- ebx : expected number of arguments |
1584 // -- edi : function (passed through to callee) | 1624 // -- edi : function (passed through to callee) |
1585 // ----------------------------------- | 1625 // ----------------------------------- |
1586 | 1626 |
1587 Label invoke, dont_adapt_arguments; | 1627 Label invoke, dont_adapt_arguments; |
1588 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); | 1628 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); |
1589 | 1629 |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 | 1798 |
1759 __ bind(&ok); | 1799 __ bind(&ok); |
1760 __ ret(0); | 1800 __ ret(0); |
1761 } | 1801 } |
1762 | 1802 |
1763 #undef __ | 1803 #undef __ |
1764 } // namespace internal | 1804 } // namespace internal |
1765 } // namespace v8 | 1805 } // namespace v8 |
1766 | 1806 |
1767 #endif // V8_TARGET_ARCH_IA32 | 1807 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |