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 |
959 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | 960 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
960 Factory* factory = masm->isolate()->factory(); | 961 // Stack Layout: |
961 | 962 // esp[0] : Return address |
| 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 // |
962 // 1. Make sure we have at least one argument. | 971 // 1. Make sure we have at least one argument. |
963 { Label done; | 972 { |
| 973 Label done; |
964 __ test(eax, eax); | 974 __ test(eax, eax); |
965 __ j(not_zero, &done); | 975 __ j(not_zero, &done, Label::kNear); |
966 __ pop(ebx); | 976 __ PopReturnAddressTo(ebx); |
967 __ push(Immediate(factory->undefined_value())); | 977 __ PushRoot(Heap::kUndefinedValueRootIndex); |
968 __ push(ebx); | 978 __ PushReturnAddressFrom(ebx); |
969 __ inc(eax); | 979 __ inc(eax); |
970 __ bind(&done); | 980 __ bind(&done); |
971 } | 981 } |
972 | 982 |
973 // 2. Get the function to call (passed as receiver) from the stack, check | 983 // 2. Get the callable to call (passed as receiver) from the stack. |
974 // if it is a function. | 984 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); |
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); | |
981 | 985 |
982 | 986 // 3. Shift arguments and return address one slot down on the stack |
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 | |
1062 // (overwriting the original receiver). Adjust argument count to make | 987 // (overwriting the original receiver). Adjust argument count to make |
1063 // the original first argument the new receiver. | 988 // the original first argument the new receiver. |
1064 __ bind(&shift_arguments); | 989 { |
1065 { Label loop; | 990 Label loop; |
1066 __ mov(ecx, eax); | 991 __ mov(ecx, eax); |
1067 __ bind(&loop); | 992 __ bind(&loop); |
1068 __ mov(ebx, Operand(esp, ecx, times_4, 0)); | 993 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0)); |
1069 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); | 994 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx); |
1070 __ dec(ecx); | 995 __ dec(ecx); |
1071 __ j(not_sign, &loop); // While non-negative (to copy return address). | 996 __ j(not_sign, &loop); // While non-negative (to copy return address). |
1072 __ pop(ebx); // Discard copy of return address. | 997 __ pop(ebx); // Discard copy of return address. |
1073 __ dec(eax); // One fewer argument (first argument is new receiver). | 998 __ dec(eax); // One fewer argument (first argument is new receiver). |
1074 } | 999 } |
1075 | 1000 |
1076 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, | 1001 // 4. Call the callable. |
1077 // or a function proxy via CALL_FUNCTION_PROXY. | 1002 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
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()); | |
1114 } | 1003 } |
1115 | 1004 |
1116 | 1005 |
1117 static void Generate_PushAppliedArguments(MacroAssembler* masm, | 1006 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
1118 const int argumentsOffset, | 1007 const int argumentsOffset, |
1119 const int indexOffset, | 1008 const int indexOffset, |
1120 const int limitOffset) { | 1009 const int limitOffset) { |
1121 // Copy all arguments from the array to the stack. | 1010 // Copy all arguments from the array to the stack. |
1122 Label entry, loop; | 1011 Label entry, loop; |
1123 Register receiver = LoadDescriptor::ReceiverRegister(); | 1012 Register receiver = LoadDescriptor::ReceiverRegister(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1178 // Stack frame: | 1067 // Stack frame: |
1179 // ebp : Old base pointer | 1068 // ebp : Old base pointer |
1180 // ebp[4] : return address | 1069 // ebp[4] : return address |
1181 // ebp[8] : function arguments | 1070 // ebp[8] : function arguments |
1182 // ebp[12] : receiver | 1071 // ebp[12] : receiver |
1183 // ebp[16] : function | 1072 // ebp[16] : function |
1184 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; | 1073 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
1185 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; | 1074 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
1186 static const int kFunctionOffset = kReceiverOffset + kPointerSize; | 1075 static const int kFunctionOffset = kReceiverOffset + kPointerSize; |
1187 | 1076 |
1188 __ push(Operand(ebp, kFunctionOffset)); // push this | 1077 __ push(Operand(ebp, kFunctionOffset)); // push this |
1189 __ push(Operand(ebp, kArgumentsOffset)); // push arguments | 1078 __ push(Operand(ebp, kArgumentsOffset)); // push arguments |
1190 if (targetIsArgument) { | 1079 if (targetIsArgument) { |
1191 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, | 1080 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, |
1192 CALL_FUNCTION); | 1081 CALL_FUNCTION); |
1193 } else { | 1082 } else { |
1194 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); | 1083 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); |
1195 } | 1084 } |
1196 | 1085 |
1197 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged); | 1086 Generate_CheckStackOverflow(masm, kFunctionOffset, kEaxIsSmiTagged); |
1198 | 1087 |
1199 // Push current index and limit. | 1088 // Push current index and limit. |
1200 const int kLimitOffset = | 1089 const int kLimitOffset = |
1201 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 1090 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
1202 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 1091 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
1203 __ push(eax); // limit | 1092 __ Push(eax); // limit |
1204 __ push(Immediate(0)); // index | 1093 __ Push(Immediate(0)); // index |
1205 | 1094 __ Push(Operand(ebp, kReceiverOffset)); // receiver |
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); | |
1260 | 1095 |
1261 // Loop over the arguments array, pushing each value to the stack | 1096 // Loop over the arguments array, pushing each value to the stack |
1262 Generate_PushAppliedArguments( | 1097 Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset, |
1263 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); | 1098 kLimitOffset); |
1264 | 1099 |
1265 // Call the function. | 1100 // Call the callable. |
1266 Label call_proxy; | 1101 // TODO(bmeurer): This should be a tail call according to ES6. |
1267 ParameterCount actual(eax); | |
1268 __ mov(edi, Operand(ebp, kFunctionOffset)); | 1102 __ mov(edi, Operand(ebp, kFunctionOffset)); |
1269 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 1103 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
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); | |
1284 | 1104 |
1285 // Leave internal frame. | 1105 // Leave internal frame. |
1286 } | 1106 } |
1287 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments | 1107 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1288 } | 1108 } |
1289 | 1109 |
1290 | 1110 |
1291 // Used by ReflectConstruct | 1111 // Used by ReflectConstruct |
1292 static void Generate_ConstructHelper(MacroAssembler* masm) { | 1112 static void Generate_ConstructHelper(MacroAssembler* masm) { |
1293 const int kFormalParameters = 3; | 1113 const int kFormalParameters = 3; |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1610 __ leave(); | 1430 __ leave(); |
1611 | 1431 |
1612 // Remove caller arguments from the stack. | 1432 // Remove caller arguments from the stack. |
1613 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1433 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
1614 __ pop(ecx); | 1434 __ pop(ecx); |
1615 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 1435 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
1616 __ push(ecx); | 1436 __ push(ecx); |
1617 } | 1437 } |
1618 | 1438 |
1619 | 1439 |
| 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 |
1620 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 1580 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
1621 // ----------- S t a t e ------------- | 1581 // ----------- S t a t e ------------- |
1622 // -- eax : actual number of arguments | 1582 // -- eax : actual number of arguments |
1623 // -- ebx : expected number of arguments | 1583 // -- ebx : expected number of arguments |
1624 // -- edi : function (passed through to callee) | 1584 // -- edi : function (passed through to callee) |
1625 // ----------------------------------- | 1585 // ----------------------------------- |
1626 | 1586 |
1627 Label invoke, dont_adapt_arguments; | 1587 Label invoke, dont_adapt_arguments; |
1628 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); | 1588 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); |
1629 | 1589 |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1798 | 1758 |
1799 __ bind(&ok); | 1759 __ bind(&ok); |
1800 __ ret(0); | 1760 __ ret(0); |
1801 } | 1761 } |
1802 | 1762 |
1803 #undef __ | 1763 #undef __ |
1804 } // namespace internal | 1764 } // namespace internal |
1805 } // namespace v8 | 1765 } // namespace v8 |
1806 | 1766 |
1807 #endif // V8_TARGET_ARCH_IA32 | 1767 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |