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 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
8 | 8 |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 972 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
983 __ SmiUntag(ebx); | 983 __ SmiUntag(ebx); |
984 __ cmp(eax, ebx); | 984 __ cmp(eax, ebx); |
985 __ j(not_equal, | 985 __ j(not_equal, |
986 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); | 986 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); |
987 | 987 |
988 ParameterCount expected(0); | 988 ParameterCount expected(0); |
989 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); | 989 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); |
990 } | 990 } |
991 | 991 |
992 | 992 |
993 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 993 static void Generate_CheckStackOverflow(MacroAssembler* masm, |
994 static const int kArgumentsOffset = 2 * kPointerSize; | 994 const int calleeOffset) { |
995 static const int kReceiverOffset = 3 * kPointerSize; | 995 // eax : the number of items to be pushed to the stack |
996 static const int kFunctionOffset = 4 * kPointerSize; | 996 // |
| 997 // Check the stack for overflow. We are not trying to catch |
| 998 // interruptions (e.g. debug break and preemption) here, so the "real stack |
| 999 // limit" is checked. |
| 1000 Label okay; |
| 1001 ExternalReference real_stack_limit = |
| 1002 ExternalReference::address_of_real_stack_limit(masm->isolate()); |
| 1003 __ mov(edi, Operand::StaticVariable(real_stack_limit)); |
| 1004 // Make ecx the space we have left. The stack might already be overflowed |
| 1005 // here which will cause ecx to become negative. |
| 1006 __ mov(ecx, esp); |
| 1007 __ sub(ecx, edi); |
| 1008 // Make edx the space we need for the array when it is unrolled onto the |
| 1009 // stack. |
| 1010 __ mov(edx, eax); |
| 1011 __ shl(edx, kPointerSizeLog2 - kSmiTagSize); |
| 1012 // Check if the arguments will overflow the stack. |
| 1013 __ cmp(ecx, edx); |
| 1014 __ j(greater, &okay); // Signed comparison. |
| 1015 |
| 1016 // Out of stack space. |
| 1017 __ push(Operand(ebp, calleeOffset)); // push this |
| 1018 __ push(eax); |
| 1019 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
| 1020 |
| 1021 __ bind(&okay); |
| 1022 } |
| 1023 |
| 1024 |
| 1025 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 1026 const int argumentsOffset, |
| 1027 const int indexOffset, |
| 1028 const int limitOffset) { |
| 1029 // Copy all arguments from the array to the stack. |
| 1030 Label entry, loop; |
| 1031 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 1032 Register key = LoadDescriptor::NameRegister(); |
| 1033 __ mov(key, Operand(ebp, indexOffset)); |
| 1034 __ jmp(&entry); |
| 1035 __ bind(&loop); |
| 1036 __ mov(receiver, Operand(ebp, argumentsOffset)); // load arguments |
| 1037 |
| 1038 if (FLAG_vector_ics) { |
| 1039 // TODO(mvstanton): Vector-based ics need additional infrastructure to |
| 1040 // be embedded here. For now, just call the runtime. |
| 1041 __ push(receiver); |
| 1042 __ push(key); |
| 1043 __ CallRuntime(Runtime::kGetProperty, 2); |
| 1044 } else { |
| 1045 // Use inline caching to speed up access to arguments. |
| 1046 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); |
| 1047 __ call(ic, RelocInfo::CODE_TARGET); |
| 1048 // It is important that we do not have a test instruction after the |
| 1049 // call. A test instruction after the call is used to indicate that |
| 1050 // we have generated an inline version of the keyed load. In this |
| 1051 // case, we know that we are not generating a test instruction next. |
| 1052 } |
| 1053 |
| 1054 // Push the nth argument. |
| 1055 __ push(eax); |
| 1056 |
| 1057 // Update the index on the stack and in register key. |
| 1058 __ mov(key, Operand(ebp, indexOffset)); |
| 1059 __ add(key, Immediate(1 << kSmiTagSize)); |
| 1060 __ mov(Operand(ebp, indexOffset), key); |
| 1061 |
| 1062 __ bind(&entry); |
| 1063 __ cmp(key, Operand(ebp, limitOffset)); |
| 1064 __ j(not_equal, &loop); |
| 1065 |
| 1066 // On exit, the pushed arguments count is in eax, untagged |
| 1067 __ Move(eax, key); |
| 1068 __ SmiUntag(eax); |
| 1069 } |
| 1070 |
| 1071 |
| 1072 // Used by FunctionApply and ReflectApply |
| 1073 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) { |
| 1074 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1075 const int kStackSize = kFormalParameters + 1; |
| 1076 |
| 1077 // Stack at entry: |
| 1078 // esp : return address |
| 1079 // esp[4] : arguments |
| 1080 // esp[8] : receiver ("this") |
| 1081 // esp[12] : function |
997 { | 1082 { |
998 FrameScope frame_scope(masm, StackFrame::INTERNAL); | 1083 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1084 // Stack frame: |
| 1085 // ebp : Old base pointer |
| 1086 // ebp[4] : return address |
| 1087 // ebp[8] : function arguments |
| 1088 // ebp[12] : receiver |
| 1089 // ebp[16] : function |
| 1090 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
| 1091 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
| 1092 static const int kFunctionOffset = kReceiverOffset + kPointerSize; |
999 | 1093 |
1000 __ push(Operand(ebp, kFunctionOffset)); // push this | 1094 __ push(Operand(ebp, kFunctionOffset)); // push this |
1001 __ push(Operand(ebp, kArgumentsOffset)); // push arguments | 1095 __ push(Operand(ebp, kArgumentsOffset)); // push arguments |
1002 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 1096 if (targetIsArgument) { |
| 1097 __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION); |
| 1098 } else { |
| 1099 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
| 1100 } |
1003 | 1101 |
1004 // Check the stack for overflow. We are not trying to catch | 1102 Generate_CheckStackOverflow(masm, kFunctionOffset); |
1005 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
1006 // limit" is checked. | |
1007 Label okay; | |
1008 ExternalReference real_stack_limit = | |
1009 ExternalReference::address_of_real_stack_limit(masm->isolate()); | |
1010 __ mov(edi, Operand::StaticVariable(real_stack_limit)); | |
1011 // Make ecx the space we have left. The stack might already be overflowed | |
1012 // here which will cause ecx to become negative. | |
1013 __ mov(ecx, esp); | |
1014 __ sub(ecx, edi); | |
1015 // Make edx the space we need for the array when it is unrolled onto the | |
1016 // stack. | |
1017 __ mov(edx, eax); | |
1018 __ shl(edx, kPointerSizeLog2 - kSmiTagSize); | |
1019 // Check if the arguments will overflow the stack. | |
1020 __ cmp(ecx, edx); | |
1021 __ j(greater, &okay); // Signed comparison. | |
1022 | |
1023 // Out of stack space. | |
1024 __ push(Operand(ebp, 4 * kPointerSize)); // push this | |
1025 __ push(eax); | |
1026 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); | |
1027 __ bind(&okay); | |
1028 // End of stack check. | |
1029 | 1103 |
1030 // Push current index and limit. | 1104 // Push current index and limit. |
1031 const int kLimitOffset = | 1105 const int kLimitOffset = |
1032 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 1106 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
1033 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 1107 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
1034 __ push(eax); // limit | 1108 __ push(eax); // limit |
1035 __ push(Immediate(0)); // index | 1109 __ push(Immediate(0)); // index |
1036 | 1110 |
1037 // Get the receiver. | 1111 // Get the receiver. |
1038 __ mov(ebx, Operand(ebp, kReceiverOffset)); | 1112 __ mov(ebx, Operand(ebp, kReceiverOffset)); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1081 | 1155 |
1082 __ bind(&use_global_proxy); | 1156 __ bind(&use_global_proxy); |
1083 __ mov(ebx, | 1157 __ mov(ebx, |
1084 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 1158 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
1085 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); | 1159 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); |
1086 | 1160 |
1087 // Push the receiver. | 1161 // Push the receiver. |
1088 __ bind(&push_receiver); | 1162 __ bind(&push_receiver); |
1089 __ push(ebx); | 1163 __ push(ebx); |
1090 | 1164 |
1091 // Copy all arguments from the array to the stack. | 1165 // Loop over the arguments array, pushing each value to the stack |
1092 Label entry, loop; | 1166 Generate_PushAppliedArguments( |
1093 Register receiver = LoadDescriptor::ReceiverRegister(); | 1167 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
1094 Register key = LoadDescriptor::NameRegister(); | |
1095 __ mov(key, Operand(ebp, kIndexOffset)); | |
1096 __ jmp(&entry); | |
1097 __ bind(&loop); | |
1098 __ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments | |
1099 | |
1100 if (FLAG_vector_ics) { | |
1101 // TODO(mvstanton): Vector-based ics need additional infrastructure to | |
1102 // be embedded here. For now, just call the runtime. | |
1103 __ push(receiver); | |
1104 __ push(key); | |
1105 __ CallRuntime(Runtime::kGetProperty, 2); | |
1106 } else { | |
1107 // Use inline caching to speed up access to arguments. | |
1108 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); | |
1109 __ call(ic, RelocInfo::CODE_TARGET); | |
1110 // It is important that we do not have a test instruction after the | |
1111 // call. A test instruction after the call is used to indicate that | |
1112 // we have generated an inline version of the keyed load. In this | |
1113 // case, we know that we are not generating a test instruction next. | |
1114 } | |
1115 | |
1116 // Push the nth argument. | |
1117 __ push(eax); | |
1118 | |
1119 // Update the index on the stack and in register key. | |
1120 __ mov(key, Operand(ebp, kIndexOffset)); | |
1121 __ add(key, Immediate(1 << kSmiTagSize)); | |
1122 __ mov(Operand(ebp, kIndexOffset), key); | |
1123 | |
1124 __ bind(&entry); | |
1125 __ cmp(key, Operand(ebp, kLimitOffset)); | |
1126 __ j(not_equal, &loop); | |
1127 | 1168 |
1128 // Call the function. | 1169 // Call the function. |
1129 Label call_proxy; | 1170 Label call_proxy; |
1130 ParameterCount actual(eax); | 1171 ParameterCount actual(eax); |
1131 __ Move(eax, key); | |
1132 __ SmiUntag(eax); | |
1133 __ mov(edi, Operand(ebp, kFunctionOffset)); | 1172 __ mov(edi, Operand(ebp, kFunctionOffset)); |
1134 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); | 1173 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); |
1135 __ j(not_equal, &call_proxy); | 1174 __ j(not_equal, &call_proxy); |
1136 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper()); | 1175 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper()); |
1137 | 1176 |
1138 frame_scope.GenerateLeaveFrame(); | 1177 frame_scope.GenerateLeaveFrame(); |
1139 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 1178 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1140 | 1179 |
1141 // Call the function proxy. | 1180 // Call the function proxy. |
1142 __ bind(&call_proxy); | 1181 __ bind(&call_proxy); |
1143 __ push(edi); // add function proxy as last argument | 1182 __ push(edi); // add function proxy as last argument |
1144 __ inc(eax); | 1183 __ inc(eax); |
1145 __ Move(ebx, Immediate(0)); | 1184 __ Move(ebx, Immediate(0)); |
1146 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); | 1185 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); |
1147 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1186 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1148 RelocInfo::CODE_TARGET); | 1187 RelocInfo::CODE_TARGET); |
1149 | 1188 |
1150 // Leave internal frame. | 1189 // Leave internal frame. |
1151 } | 1190 } |
1152 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 1191 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1153 } | 1192 } |
1154 | 1193 |
1155 | 1194 |
| 1195 // Used by ReflectConstruct |
| 1196 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1197 const int kFormalParameters = 3; |
| 1198 const int kStackSize = kFormalParameters + 1; |
| 1199 |
| 1200 // Stack at entry: |
| 1201 // esp : return address |
| 1202 // esp[4] : original constructor (new.target) |
| 1203 // esp[8] : arguments |
| 1204 // esp[16] : constructor |
| 1205 { |
| 1206 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1207 // Stack frame: |
| 1208 // ebp : Old base pointer |
| 1209 // ebp[4] : return address |
| 1210 // ebp[8] : original constructor (new.target) |
| 1211 // ebp[12] : arguments |
| 1212 // ebp[16] : constructor |
| 1213 static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize; |
| 1214 static const int kArgumentsOffset = kNewTargetOffset + kPointerSize; |
| 1215 static const int kFunctionOffset = kArgumentsOffset + kPointerSize; |
| 1216 |
| 1217 // If newTarget is not supplied, set it to constructor |
| 1218 Label validate_arguments; |
| 1219 __ mov(eax, Operand(ebp, kNewTargetOffset)); |
| 1220 __ CompareRoot(eax, Heap::kUndefinedValueRootIndex); |
| 1221 __ j(not_equal, &validate_arguments, Label::kNear); |
| 1222 __ mov(eax, Operand(ebp, kFunctionOffset)); |
| 1223 __ mov(Operand(ebp, kNewTargetOffset), eax); |
| 1224 |
| 1225 // Validate arguments |
| 1226 __ bind(&validate_arguments); |
| 1227 __ push(Operand(ebp, kFunctionOffset)); |
| 1228 __ push(Operand(ebp, kArgumentsOffset)); |
| 1229 __ push(Operand(ebp, kNewTargetOffset)); |
| 1230 __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION); |
| 1231 |
| 1232 Generate_CheckStackOverflow(masm, kFunctionOffset); |
| 1233 |
| 1234 // Push current index and limit. |
| 1235 const int kLimitOffset = |
| 1236 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
| 1237 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
| 1238 __ Push(eax); // limit |
| 1239 __ push(Immediate(0)); // index |
| 1240 // Push newTarget and callee functions |
| 1241 __ push(Operand(ebp, kNewTargetOffset)); |
| 1242 __ push(Operand(ebp, kFunctionOffset)); |
| 1243 |
| 1244 // Loop over the arguments array, pushing each value to the stack |
| 1245 Generate_PushAppliedArguments( |
| 1246 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
| 1247 |
| 1248 // Use undefined feedback vector |
| 1249 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); |
| 1250 __ mov(edi, Operand(ebp, kFunctionOffset)); |
| 1251 |
| 1252 // Call the function. |
| 1253 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); |
| 1254 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); |
| 1255 |
| 1256 __ Drop(1); |
| 1257 |
| 1258 // Leave internal frame. |
| 1259 } |
| 1260 // remove this, target, arguments, and newTarget |
| 1261 __ ret(kStackSize * kPointerSize); |
| 1262 } |
| 1263 |
| 1264 |
| 1265 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 1266 Generate_ApplyHelper(masm, false); |
| 1267 } |
| 1268 |
| 1269 |
| 1270 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { |
| 1271 Generate_ApplyHelper(masm, true); |
| 1272 } |
| 1273 |
| 1274 |
| 1275 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { |
| 1276 Generate_ConstructHelper(masm); |
| 1277 } |
| 1278 |
| 1279 |
1156 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { | 1280 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
1157 // ----------- S t a t e ------------- | 1281 // ----------- S t a t e ------------- |
1158 // -- eax : argc | 1282 // -- eax : argc |
1159 // -- esp[0] : return address | 1283 // -- esp[0] : return address |
1160 // -- esp[4] : last argument | 1284 // -- esp[4] : last argument |
1161 // ----------------------------------- | 1285 // ----------------------------------- |
1162 Label generic_array_code; | 1286 Label generic_array_code; |
1163 | 1287 |
1164 // Get the InternalArray function. | 1288 // Get the InternalArray function. |
1165 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); | 1289 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1549 | 1673 |
1550 __ bind(&ok); | 1674 __ bind(&ok); |
1551 __ ret(0); | 1675 __ ret(0); |
1552 } | 1676 } |
1553 | 1677 |
1554 #undef __ | 1678 #undef __ |
1555 } | 1679 } |
1556 } // namespace v8::internal | 1680 } // namespace v8::internal |
1557 | 1681 |
1558 #endif // V8_TARGET_ARCH_IA32 | 1682 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |