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_X64 | 7 #if V8_TARGET_ARCH_X64 |
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 1033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1044 __ cmpp(rax, rbx); | 1044 __ cmpp(rax, rbx); |
1045 __ j(not_equal, | 1045 __ j(not_equal, |
1046 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1046 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1047 RelocInfo::CODE_TARGET); | 1047 RelocInfo::CODE_TARGET); |
1048 | 1048 |
1049 ParameterCount expected(0); | 1049 ParameterCount expected(0); |
1050 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); | 1050 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); |
1051 } | 1051 } |
1052 | 1052 |
1053 | 1053 |
1054 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 1054 static void Generate_CheckStackOverflow(MacroAssembler* masm, |
| 1055 const int calleeOffset) { |
| 1056 // rax : the number of items to be pushed to the stack |
| 1057 // |
| 1058 // Check the stack for overflow. We are not trying to catch |
| 1059 // interruptions (e.g. debug break and preemption) here, so the "real stack |
| 1060 // limit" is checked. |
| 1061 Label okay; |
| 1062 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); |
| 1063 __ movp(rcx, rsp); |
| 1064 // Make rcx the space we have left. The stack might already be overflowed |
| 1065 // here which will cause rcx to become negative. |
| 1066 __ subp(rcx, kScratchRegister); |
| 1067 // Make rdx the space we need for the array when it is unrolled onto the |
| 1068 // stack. |
| 1069 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2); |
| 1070 // Check if the arguments will overflow the stack. |
| 1071 __ cmpp(rcx, rdx); |
| 1072 __ j(greater, &okay); // Signed comparison. |
| 1073 |
| 1074 // Out of stack space. |
| 1075 __ Push(Operand(rbp, calleeOffset)); |
| 1076 __ Push(rax); |
| 1077 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
| 1078 |
| 1079 __ bind(&okay); |
| 1080 } |
| 1081 |
| 1082 |
| 1083 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 1084 const int argumentsOffset, |
| 1085 const int indexOffset, |
| 1086 const int limitOffset) { |
| 1087 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 1088 Register key = LoadDescriptor::NameRegister(); |
| 1089 |
| 1090 // Copy all arguments from the array to the stack. |
| 1091 Label entry, loop; |
| 1092 __ movp(key, Operand(rbp, indexOffset)); |
| 1093 __ jmp(&entry); |
| 1094 __ bind(&loop); |
| 1095 __ movp(receiver, Operand(rbp, argumentsOffset)); // load arguments |
| 1096 |
| 1097 // Use inline caching to speed up access to arguments. |
| 1098 if (FLAG_vector_ics) { |
| 1099 // TODO(mvstanton): Vector-based ics need additional infrastructure to |
| 1100 // be embedded here. For now, just call the runtime. |
| 1101 __ Push(receiver); |
| 1102 __ Push(key); |
| 1103 __ CallRuntime(Runtime::kGetProperty, 2); |
| 1104 } else { |
| 1105 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); |
| 1106 __ Call(ic, RelocInfo::CODE_TARGET); |
| 1107 // It is important that we do not have a test instruction after the |
| 1108 // call. A test instruction after the call is used to indicate that |
| 1109 // we have generated an inline version of the keyed load. In this |
| 1110 // case, we know that we are not generating a test instruction next. |
| 1111 } |
| 1112 |
| 1113 // Push the nth argument. |
| 1114 __ Push(rax); |
| 1115 |
| 1116 // Update the index on the stack and in register key. |
| 1117 __ movp(key, Operand(rbp, indexOffset)); |
| 1118 __ SmiAddConstant(key, key, Smi::FromInt(1)); |
| 1119 __ movp(Operand(rbp, indexOffset), key); |
| 1120 |
| 1121 __ bind(&entry); |
| 1122 __ cmpp(key, Operand(rbp, limitOffset)); |
| 1123 __ j(not_equal, &loop); |
| 1124 |
| 1125 // On exit, the pushed arguments count is in rax, untagged |
| 1126 __ SmiToInteger64(rax, key); |
| 1127 } |
| 1128 |
| 1129 |
| 1130 // Used by FunctionApply and ReflectApply |
| 1131 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) { |
| 1132 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1133 const int kStackSize = kFormalParameters + 1; |
| 1134 |
1055 // Stack at entry: | 1135 // Stack at entry: |
1056 // rsp : return address | 1136 // rsp : return address |
1057 // rsp[8] : arguments | 1137 // rsp[8] : arguments |
1058 // rsp[16] : receiver ("this") | 1138 // rsp[16] : receiver ("this") |
1059 // rsp[24] : function | 1139 // rsp[24] : function |
1060 { | 1140 { |
1061 FrameScope frame_scope(masm, StackFrame::INTERNAL); | 1141 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
1062 // Stack frame: | 1142 // Stack frame: |
1063 // rbp : Old base pointer | 1143 // rbp : Old base pointer |
1064 // rbp[8] : return address | 1144 // rbp[8] : return address |
1065 // rbp[16] : function arguments | 1145 // rbp[16] : function arguments |
1066 // rbp[24] : receiver | 1146 // rbp[24] : receiver |
1067 // rbp[32] : function | 1147 // rbp[32] : function |
1068 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; | 1148 static const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
1069 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; | 1149 static const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
1070 static const int kFunctionOffset = kReceiverOffset + kPointerSize; | 1150 static const int kFunctionOffset = kReceiverOffset + kPointerSize; |
1071 | 1151 |
1072 __ Push(Operand(rbp, kFunctionOffset)); | 1152 __ Push(Operand(rbp, kFunctionOffset)); |
1073 __ Push(Operand(rbp, kArgumentsOffset)); | 1153 __ Push(Operand(rbp, kArgumentsOffset)); |
1074 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 1154 if (targetIsArgument) { |
| 1155 __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION); |
| 1156 } else { |
| 1157 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
| 1158 } |
1075 | 1159 |
1076 // Check the stack for overflow. We are not trying to catch | 1160 Generate_CheckStackOverflow(masm, kFunctionOffset); |
1077 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
1078 // limit" is checked. | |
1079 Label okay; | |
1080 __ LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex); | |
1081 __ movp(rcx, rsp); | |
1082 // Make rcx the space we have left. The stack might already be overflowed | |
1083 // here which will cause rcx to become negative. | |
1084 __ subp(rcx, kScratchRegister); | |
1085 // Make rdx the space we need for the array when it is unrolled onto the | |
1086 // stack. | |
1087 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rax, kPointerSizeLog2); | |
1088 // Check if the arguments will overflow the stack. | |
1089 __ cmpp(rcx, rdx); | |
1090 __ j(greater, &okay); // Signed comparison. | |
1091 | |
1092 // Out of stack space. | |
1093 __ Push(Operand(rbp, kFunctionOffset)); | |
1094 __ Push(rax); | |
1095 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); | |
1096 __ bind(&okay); | |
1097 // End of stack check. | |
1098 | 1161 |
1099 // Push current index and limit. | 1162 // Push current index and limit. |
1100 const int kLimitOffset = | 1163 const int kLimitOffset = |
1101 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 1164 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
1102 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 1165 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
1103 __ Push(rax); // limit | 1166 __ Push(rax); // limit |
1104 __ Push(Immediate(0)); // index | 1167 __ Push(Immediate(0)); // index |
1105 | 1168 |
1106 // Get the receiver. | 1169 // Get the receiver. |
1107 __ movp(rbx, Operand(rbp, kReceiverOffset)); | 1170 __ movp(rbx, Operand(rbp, kReceiverOffset)); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 | 1212 |
1150 __ bind(&use_global_proxy); | 1213 __ bind(&use_global_proxy); |
1151 __ movp(rbx, | 1214 __ movp(rbx, |
1152 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 1215 Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
1153 __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset)); | 1216 __ movp(rbx, FieldOperand(rbx, GlobalObject::kGlobalProxyOffset)); |
1154 | 1217 |
1155 // Push the receiver. | 1218 // Push the receiver. |
1156 __ bind(&push_receiver); | 1219 __ bind(&push_receiver); |
1157 __ Push(rbx); | 1220 __ Push(rbx); |
1158 | 1221 |
1159 // Copy all arguments from the array to the stack. | 1222 // Loop over the arguments array, pushing each value to the stack |
1160 Label entry, loop; | 1223 Generate_PushAppliedArguments( |
1161 Register receiver = LoadDescriptor::ReceiverRegister(); | 1224 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
1162 Register key = LoadDescriptor::NameRegister(); | |
1163 __ movp(key, Operand(rbp, kIndexOffset)); | |
1164 __ jmp(&entry); | |
1165 __ bind(&loop); | |
1166 __ movp(receiver, Operand(rbp, kArgumentsOffset)); // load arguments | |
1167 | |
1168 // Use inline caching to speed up access to arguments. | |
1169 if (FLAG_vector_ics) { | |
1170 // TODO(mvstanton): Vector-based ics need additional infrastructure to | |
1171 // be embedded here. For now, just call the runtime. | |
1172 __ Push(receiver); | |
1173 __ Push(key); | |
1174 __ CallRuntime(Runtime::kGetProperty, 2); | |
1175 } else { | |
1176 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); | |
1177 __ Call(ic, RelocInfo::CODE_TARGET); | |
1178 // It is important that we do not have a test instruction after the | |
1179 // call. A test instruction after the call is used to indicate that | |
1180 // we have generated an inline version of the keyed load. In this | |
1181 // case, we know that we are not generating a test instruction next. | |
1182 } | |
1183 | |
1184 // Push the nth argument. | |
1185 __ Push(rax); | |
1186 | |
1187 // Update the index on the stack and in register key. | |
1188 __ movp(key, Operand(rbp, kIndexOffset)); | |
1189 __ SmiAddConstant(key, key, Smi::FromInt(1)); | |
1190 __ movp(Operand(rbp, kIndexOffset), key); | |
1191 | |
1192 __ bind(&entry); | |
1193 __ cmpp(key, Operand(rbp, kLimitOffset)); | |
1194 __ j(not_equal, &loop); | |
1195 | 1225 |
1196 // Call the function. | 1226 // Call the function. |
1197 Label call_proxy; | 1227 Label call_proxy; |
1198 ParameterCount actual(rax); | 1228 ParameterCount actual(rax); |
1199 __ SmiToInteger32(rax, key); | |
1200 __ movp(rdi, Operand(rbp, kFunctionOffset)); | 1229 __ movp(rdi, Operand(rbp, kFunctionOffset)); |
1201 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 1230 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
1202 __ j(not_equal, &call_proxy); | 1231 __ j(not_equal, &call_proxy); |
1203 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper()); | 1232 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper()); |
1204 | 1233 |
1205 frame_scope.GenerateLeaveFrame(); | 1234 frame_scope.GenerateLeaveFrame(); |
1206 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 1235 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1207 | 1236 |
1208 // Call the function proxy. | 1237 // Call the function proxy. |
1209 __ bind(&call_proxy); | 1238 __ bind(&call_proxy); |
1210 __ Push(rdi); // add function proxy as last argument | 1239 __ Push(rdi); // add function proxy as last argument |
1211 __ incp(rax); | 1240 __ incp(rax); |
1212 __ Set(rbx, 0); | 1241 __ Set(rbx, 0); |
1213 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); | 1242 __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY); |
1214 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1243 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1215 RelocInfo::CODE_TARGET); | 1244 RelocInfo::CODE_TARGET); |
1216 | 1245 |
1217 // Leave internal frame. | 1246 // Leave internal frame. |
1218 } | 1247 } |
1219 __ ret(3 * kPointerSize); // remove this, receiver, and arguments | 1248 __ ret(kStackSize * kPointerSize); // remove this, receiver, and arguments |
1220 } | 1249 } |
1221 | 1250 |
1222 | 1251 |
| 1252 // Used by ReflectConstruct |
| 1253 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1254 const int kFormalParameters = 3; |
| 1255 const int kStackSize = kFormalParameters + 1; |
| 1256 |
| 1257 // Stack at entry: |
| 1258 // rsp : return address |
| 1259 // rsp[8] : original constructor (new.target) |
| 1260 // rsp[16] : arguments |
| 1261 // rsp[24] : constructor |
| 1262 { |
| 1263 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1264 // Stack frame: |
| 1265 // rbp : Old base pointer |
| 1266 // rbp[8] : return address |
| 1267 // rbp[16] : original constructor (new.target) |
| 1268 // rbp[24] : arguments |
| 1269 // rbp[32] : constructor |
| 1270 static const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize; |
| 1271 static const int kArgumentsOffset = kNewTargetOffset + kPointerSize; |
| 1272 static const int kFunctionOffset = kArgumentsOffset + kPointerSize; |
| 1273 |
| 1274 // If newTarget is not supplied, set it to constructor |
| 1275 Label validate_arguments; |
| 1276 __ movp(rax, Operand(rbp, kNewTargetOffset)); |
| 1277 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1278 __ j(not_equal, &validate_arguments, Label::kNear); |
| 1279 __ movp(rax, Operand(rbp, kFunctionOffset)); |
| 1280 __ movp(Operand(rbp, kNewTargetOffset), rax); |
| 1281 |
| 1282 // Validate arguments |
| 1283 __ bind(&validate_arguments); |
| 1284 __ Push(Operand(rbp, kFunctionOffset)); |
| 1285 __ Push(Operand(rbp, kArgumentsOffset)); |
| 1286 __ Push(Operand(rbp, kNewTargetOffset)); |
| 1287 __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION); |
| 1288 |
| 1289 Generate_CheckStackOverflow(masm, kFunctionOffset); |
| 1290 |
| 1291 // Push current index and limit. |
| 1292 const int kLimitOffset = |
| 1293 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
| 1294 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
| 1295 __ Push(rax); // limit |
| 1296 __ Push(Immediate(0)); // index |
| 1297 // Push newTarget and callee functions |
| 1298 __ Push(Operand(rbp, kNewTargetOffset)); |
| 1299 __ Push(Operand(rbp, kFunctionOffset)); |
| 1300 |
| 1301 // Loop over the arguments array, pushing each value to the stack |
| 1302 Generate_PushAppliedArguments( |
| 1303 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
| 1304 |
| 1305 // Use undefined feedback vector |
| 1306 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); |
| 1307 __ movp(rdi, Operand(rbp, kFunctionOffset)); |
| 1308 |
| 1309 // Call the function. |
| 1310 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); |
| 1311 __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); |
| 1312 |
| 1313 __ Drop(1); |
| 1314 |
| 1315 // Leave internal frame. |
| 1316 } |
| 1317 // remove this, target, arguments and newTarget |
| 1318 __ ret(kStackSize * kPointerSize); |
| 1319 } |
| 1320 |
| 1321 |
| 1322 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 1323 Generate_ApplyHelper(masm, false); |
| 1324 } |
| 1325 |
| 1326 |
| 1327 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { |
| 1328 Generate_ApplyHelper(masm, true); |
| 1329 } |
| 1330 |
| 1331 |
| 1332 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { |
| 1333 Generate_ConstructHelper(masm); |
| 1334 } |
| 1335 |
| 1336 |
1223 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { | 1337 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { |
1224 // ----------- S t a t e ------------- | 1338 // ----------- S t a t e ------------- |
1225 // -- rax : argc | 1339 // -- rax : argc |
1226 // -- rsp[0] : return address | 1340 // -- rsp[0] : return address |
1227 // -- rsp[8] : last argument | 1341 // -- rsp[8] : last argument |
1228 // ----------------------------------- | 1342 // ----------------------------------- |
1229 Label generic_array_code; | 1343 Label generic_array_code; |
1230 | 1344 |
1231 // Get the InternalArray function. | 1345 // Get the InternalArray function. |
1232 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, rdi); | 1346 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, rdi); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1615 __ bind(&ok); | 1729 __ bind(&ok); |
1616 __ ret(0); | 1730 __ ret(0); |
1617 } | 1731 } |
1618 | 1732 |
1619 | 1733 |
1620 #undef __ | 1734 #undef __ |
1621 | 1735 |
1622 } } // namespace v8::internal | 1736 } } // namespace v8::internal |
1623 | 1737 |
1624 #endif // V8_TARGET_ARCH_X64 | 1738 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |