| 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_MIPS64 | 5 #if V8_TARGET_ARCH_MIPS64 |
| 6 | 6 |
| 7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
| 8 #include "src/debug/debug.h" | 8 #include "src/debug/debug.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 1231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1242 __ CallRuntime(Runtime::kStackGuard, 0); | 1242 __ CallRuntime(Runtime::kStackGuard, 0); |
| 1243 } | 1243 } |
| 1244 __ Jump(masm->isolate()->builtins()->OnStackReplacement(), | 1244 __ Jump(masm->isolate()->builtins()->OnStackReplacement(), |
| 1245 RelocInfo::CODE_TARGET); | 1245 RelocInfo::CODE_TARGET); |
| 1246 | 1246 |
| 1247 __ bind(&ok); | 1247 __ bind(&ok); |
| 1248 __ Ret(); | 1248 __ Ret(); |
| 1249 } | 1249 } |
| 1250 | 1250 |
| 1251 | 1251 |
| 1252 // static |
| 1252 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { | 1253 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { |
| 1253 // 1. Make sure we have at least one argument. | 1254 // 1. Make sure we have at least one argument. |
| 1254 // a0: actual number of arguments | 1255 // a0: actual number of arguments |
| 1255 { Label done; | 1256 { |
| 1257 Label done; |
| 1256 __ Branch(&done, ne, a0, Operand(zero_reg)); | 1258 __ Branch(&done, ne, a0, Operand(zero_reg)); |
| 1257 __ LoadRoot(a6, Heap::kUndefinedValueRootIndex); | 1259 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 1258 __ push(a6); | |
| 1259 __ Daddu(a0, a0, Operand(1)); | 1260 __ Daddu(a0, a0, Operand(1)); |
| 1260 __ bind(&done); | 1261 __ bind(&done); |
| 1261 } | 1262 } |
| 1262 | 1263 |
| 1263 // 2. Get the function to call (passed as receiver) from the stack, check | 1264 // 2. Get the function to call (passed as receiver) from the stack. |
| 1264 // if it is a function. | |
| 1265 // a0: actual number of arguments | 1265 // a0: actual number of arguments |
| 1266 Label slow, non_function; | |
| 1267 __ dsll(at, a0, kPointerSizeLog2); | 1266 __ dsll(at, a0, kPointerSizeLog2); |
| 1268 __ daddu(at, sp, at); | 1267 __ daddu(at, sp, at); |
| 1269 __ ld(a1, MemOperand(at)); | 1268 __ ld(a1, MemOperand(at)); |
| 1270 __ JumpIfSmi(a1, &non_function); | |
| 1271 __ GetObjectType(a1, a2, a2); | |
| 1272 __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE)); | |
| 1273 | 1269 |
| 1274 // 3a. Patch the first argument if necessary when calling a function. | 1270 // 3. Shift arguments and return address one slot down on the stack |
| 1275 // a0: actual number of arguments | |
| 1276 // a1: function | |
| 1277 Label shift_arguments; | |
| 1278 __ li(a4, Operand(0, RelocInfo::NONE32)); // Indicate regular JS_FUNCTION. | |
| 1279 { Label convert_to_object, use_global_proxy, patch_receiver; | |
| 1280 // Change context eagerly in case we need the global receiver. | |
| 1281 __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | |
| 1282 | |
| 1283 // Do not transform the receiver for strict mode functions. | |
| 1284 __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | |
| 1285 __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kStrictModeByteOffset)); | |
| 1286 __ And(a7, a3, Operand(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); | |
| 1287 __ Branch(&shift_arguments, ne, a7, Operand(zero_reg)); | |
| 1288 | |
| 1289 // Do not transform the receiver for native (Compilerhints already in a3). | |
| 1290 __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset)); | |
| 1291 __ And(a7, a3, Operand(1 << SharedFunctionInfo::kNativeBitWithinByte)); | |
| 1292 __ Branch(&shift_arguments, ne, a7, Operand(zero_reg)); | |
| 1293 | |
| 1294 // Compute the receiver in sloppy mode. | |
| 1295 // Load first argument in a2. a2 = -kPointerSize(sp + n_args << 2). | |
| 1296 __ dsll(at, a0, kPointerSizeLog2); | |
| 1297 __ daddu(a2, sp, at); | |
| 1298 __ ld(a2, MemOperand(a2, -kPointerSize)); | |
| 1299 // a0: actual number of arguments | |
| 1300 // a1: function | |
| 1301 // a2: first argument | |
| 1302 __ JumpIfSmi(a2, &convert_to_object, a6); | |
| 1303 | |
| 1304 __ LoadRoot(a3, Heap::kUndefinedValueRootIndex); | |
| 1305 __ Branch(&use_global_proxy, eq, a2, Operand(a3)); | |
| 1306 __ LoadRoot(a3, Heap::kNullValueRootIndex); | |
| 1307 __ Branch(&use_global_proxy, eq, a2, Operand(a3)); | |
| 1308 | |
| 1309 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | |
| 1310 __ GetObjectType(a2, a3, a3); | |
| 1311 __ Branch(&shift_arguments, ge, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); | |
| 1312 | |
| 1313 __ bind(&convert_to_object); | |
| 1314 // Enter an internal frame in order to preserve argument count. | |
| 1315 { | |
| 1316 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1317 __ SmiTag(a0); | |
| 1318 __ Push(a0); | |
| 1319 __ mov(a0, a2); | |
| 1320 ToObjectStub stub(masm->isolate()); | |
| 1321 __ CallStub(&stub); | |
| 1322 __ mov(a2, v0); | |
| 1323 | |
| 1324 __ pop(a0); | |
| 1325 __ SmiUntag(a0); | |
| 1326 // Leave internal frame. | |
| 1327 } | |
| 1328 // Restore the function to a1, and the flag to a4. | |
| 1329 __ dsll(at, a0, kPointerSizeLog2); | |
| 1330 __ daddu(at, sp, at); | |
| 1331 __ ld(a1, MemOperand(at)); | |
| 1332 __ Branch(USE_DELAY_SLOT, &patch_receiver); | |
| 1333 __ li(a4, Operand(0, RelocInfo::NONE32)); | |
| 1334 | |
| 1335 __ bind(&use_global_proxy); | |
| 1336 __ ld(a2, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); | |
| 1337 __ ld(a2, FieldMemOperand(a2, GlobalObject::kGlobalProxyOffset)); | |
| 1338 | |
| 1339 __ bind(&patch_receiver); | |
| 1340 __ dsll(at, a0, kPointerSizeLog2); | |
| 1341 __ daddu(a3, sp, at); | |
| 1342 __ sd(a2, MemOperand(a3, -kPointerSize)); | |
| 1343 | |
| 1344 __ Branch(&shift_arguments); | |
| 1345 } | |
| 1346 | |
| 1347 // 3b. Check for function proxy. | |
| 1348 __ bind(&slow); | |
| 1349 __ li(a4, Operand(1, RelocInfo::NONE32)); // Indicate function proxy. | |
| 1350 __ Branch(&shift_arguments, eq, a2, Operand(JS_FUNCTION_PROXY_TYPE)); | |
| 1351 | |
| 1352 __ bind(&non_function); | |
| 1353 __ li(a4, Operand(2, RelocInfo::NONE32)); // Indicate non-function. | |
| 1354 | |
| 1355 // 3c. Patch the first argument when calling a non-function. The | |
| 1356 // CALL_NON_FUNCTION builtin expects the non-function callee as | |
| 1357 // receiver, so overwrite the first argument which will ultimately | |
| 1358 // become the receiver. | |
| 1359 // a0: actual number of arguments | |
| 1360 // a1: function | |
| 1361 // a4: call type (0: JS function, 1: function proxy, 2: non-function) | |
| 1362 __ dsll(at, a0, kPointerSizeLog2); | |
| 1363 __ daddu(a2, sp, at); | |
| 1364 __ sd(a1, MemOperand(a2, -kPointerSize)); | |
| 1365 | |
| 1366 // 4. Shift arguments and return address one slot down on the stack | |
| 1367 // (overwriting the original receiver). Adjust argument count to make | 1271 // (overwriting the original receiver). Adjust argument count to make |
| 1368 // the original first argument the new receiver. | 1272 // the original first argument the new receiver. |
| 1369 // a0: actual number of arguments | 1273 // a0: actual number of arguments |
| 1370 // a1: function | 1274 // a1: function |
| 1371 // a4: call type (0: JS function, 1: function proxy, 2: non-function) | 1275 { |
| 1372 __ bind(&shift_arguments); | 1276 Label loop; |
| 1373 { Label loop; | |
| 1374 // Calculate the copy start address (destination). Copy end address is sp. | 1277 // Calculate the copy start address (destination). Copy end address is sp. |
| 1375 __ dsll(at, a0, kPointerSizeLog2); | 1278 __ dsll(at, a0, kPointerSizeLog2); |
| 1376 __ daddu(a2, sp, at); | 1279 __ daddu(a2, sp, at); |
| 1377 | 1280 |
| 1378 __ bind(&loop); | 1281 __ bind(&loop); |
| 1379 __ ld(at, MemOperand(a2, -kPointerSize)); | 1282 __ ld(at, MemOperand(a2, -kPointerSize)); |
| 1380 __ sd(at, MemOperand(a2)); | 1283 __ sd(at, MemOperand(a2)); |
| 1381 __ Dsubu(a2, a2, Operand(kPointerSize)); | 1284 __ Dsubu(a2, a2, Operand(kPointerSize)); |
| 1382 __ Branch(&loop, ne, a2, Operand(sp)); | 1285 __ Branch(&loop, ne, a2, Operand(sp)); |
| 1383 // Adjust the actual number of arguments and remove the top element | 1286 // Adjust the actual number of arguments and remove the top element |
| 1384 // (which is a copy of the last argument). | 1287 // (which is a copy of the last argument). |
| 1385 __ Dsubu(a0, a0, Operand(1)); | 1288 __ Dsubu(a0, a0, Operand(1)); |
| 1386 __ Pop(); | 1289 __ Pop(); |
| 1387 } | 1290 } |
| 1388 | 1291 |
| 1389 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, | 1292 // 4. Call the callable. |
| 1390 // or a function proxy via CALL_FUNCTION_PROXY. | 1293 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
| 1391 // a0: actual number of arguments | |
| 1392 // a1: function | |
| 1393 // a4: call type (0: JS function, 1: function proxy, 2: non-function) | |
| 1394 { Label function, non_proxy; | |
| 1395 __ Branch(&function, eq, a4, Operand(zero_reg)); | |
| 1396 // Expected number of arguments is 0 for CALL_NON_FUNCTION. | |
| 1397 __ mov(a2, zero_reg); | |
| 1398 __ Branch(&non_proxy, ne, a4, Operand(1)); | |
| 1399 | |
| 1400 __ push(a1); // Re-add proxy object as additional argument. | |
| 1401 __ Daddu(a0, a0, Operand(1)); | |
| 1402 __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX); | |
| 1403 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
| 1404 RelocInfo::CODE_TARGET); | |
| 1405 | |
| 1406 __ bind(&non_proxy); | |
| 1407 __ GetBuiltinFunction(a1, Context::CALL_NON_FUNCTION_BUILTIN_INDEX); | |
| 1408 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
| 1409 RelocInfo::CODE_TARGET); | |
| 1410 __ bind(&function); | |
| 1411 } | |
| 1412 | |
| 1413 // 5b. Get the code to call from the function and check that the number of | |
| 1414 // expected arguments matches what we're providing. If so, jump | |
| 1415 // (tail-call) to the code in register edx without checking arguments. | |
| 1416 // a0: actual number of arguments | |
| 1417 // a1: function | |
| 1418 __ ld(a3, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | |
| 1419 // The argument count is stored as int32_t on 64-bit platforms. | |
| 1420 // TODO(plind): Smi on 32-bit platforms. | |
| 1421 __ lw(a2, | |
| 1422 FieldMemOperand(a3, SharedFunctionInfo::kFormalParameterCountOffset)); | |
| 1423 // Check formal and actual parameter counts. | |
| 1424 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
| 1425 RelocInfo::CODE_TARGET, ne, a2, Operand(a0)); | |
| 1426 | |
| 1427 __ ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); | |
| 1428 ParameterCount expected(0); | |
| 1429 __ InvokeCode(a3, expected, expected, JUMP_FUNCTION, NullCallWrapper()); | |
| 1430 } | 1294 } |
| 1431 | 1295 |
| 1432 | 1296 |
| 1433 static void Generate_PushAppliedArguments(MacroAssembler* masm, | 1297 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 1434 const int argumentsOffset, | 1298 const int argumentsOffset, |
| 1435 const int indexOffset, | 1299 const int indexOffset, |
| 1436 const int limitOffset) { | 1300 const int limitOffset) { |
| 1437 Label entry, loop; | 1301 Label entry, loop; |
| 1438 Register receiver = LoadDescriptor::ReceiverRegister(); | 1302 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 1439 Register key = LoadDescriptor::NameRegister(); | 1303 Register key = LoadDescriptor::NameRegister(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1483 const int kFormalParameters = targetIsArgument ? 3 : 2; | 1347 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1484 const int kStackSize = kFormalParameters + 1; | 1348 const int kStackSize = kFormalParameters + 1; |
| 1485 | 1349 |
| 1486 { | 1350 { |
| 1487 FrameScope frame_scope(masm, StackFrame::INTERNAL); | 1351 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1488 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; | 1352 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
| 1489 const int kReceiverOffset = kArgumentsOffset + kPointerSize; | 1353 const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
| 1490 const int kFunctionOffset = kReceiverOffset + kPointerSize; | 1354 const int kFunctionOffset = kReceiverOffset + kPointerSize; |
| 1491 | 1355 |
| 1492 __ ld(a0, MemOperand(fp, kFunctionOffset)); // Get the function. | 1356 __ ld(a0, MemOperand(fp, kFunctionOffset)); // Get the function. |
| 1493 __ push(a0); | 1357 __ ld(a1, MemOperand(fp, kArgumentsOffset)); // Get the args array. |
| 1494 __ ld(a0, MemOperand(fp, kArgumentsOffset)); // Get the args array. | 1358 __ Push(a0, a1); |
| 1495 __ push(a0); | |
| 1496 | 1359 |
| 1497 // Returns (in v0) number of arguments to copy to stack as Smi. | 1360 // Returns (in v0) number of arguments to copy to stack as Smi. |
| 1498 if (targetIsArgument) { | 1361 if (targetIsArgument) { |
| 1499 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, | 1362 __ InvokeBuiltin(Context::REFLECT_APPLY_PREPARE_BUILTIN_INDEX, |
| 1500 CALL_FUNCTION); | 1363 CALL_FUNCTION); |
| 1501 } else { | 1364 } else { |
| 1502 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); | 1365 __ InvokeBuiltin(Context::APPLY_PREPARE_BUILTIN_INDEX, CALL_FUNCTION); |
| 1503 } | 1366 } |
| 1504 | 1367 |
| 1505 // Returns the result in v0. | 1368 // Returns the result in v0. |
| 1506 Generate_CheckStackOverflow(masm, kFunctionOffset, v0, kArgcIsSmiTagged); | 1369 Generate_CheckStackOverflow(masm, kFunctionOffset, v0, kArgcIsSmiTagged); |
| 1507 | 1370 |
| 1508 // Push current limit and index. | 1371 // Push current limit and index. |
| 1509 const int kIndexOffset = | 1372 const int kIndexOffset = |
| 1510 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); | 1373 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); |
| 1511 const int kLimitOffset = | 1374 const int kLimitOffset = |
| 1512 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); | 1375 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); |
| 1513 __ mov(a1, zero_reg); | 1376 __ mov(a1, zero_reg); |
| 1514 __ Push(v0, a1); // Limit and initial index. | 1377 __ ld(a2, MemOperand(fp, kReceiverOffset)); |
| 1515 | 1378 __ Push(v0, a1, a2); // limit, initial index and receiver. |
| 1516 // Get the receiver. | |
| 1517 __ ld(a0, MemOperand(fp, kReceiverOffset)); | |
| 1518 | |
| 1519 // Check that the function is a JS function (otherwise it must be a proxy). | |
| 1520 Label push_receiver; | |
| 1521 __ ld(a1, MemOperand(fp, kFunctionOffset)); | |
| 1522 __ GetObjectType(a1, a2, a2); | |
| 1523 __ Branch(&push_receiver, ne, a2, Operand(JS_FUNCTION_TYPE)); | |
| 1524 | |
| 1525 // Change context eagerly to get the right global object if necessary. | |
| 1526 __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | |
| 1527 // Load the shared function info while the function is still in a1. | |
| 1528 __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | |
| 1529 | |
| 1530 // Compute the receiver. | |
| 1531 // Do not transform the receiver for strict mode functions. | |
| 1532 Label call_to_object, use_global_proxy; | |
| 1533 __ lbu(a7, FieldMemOperand(a2, SharedFunctionInfo::kStrictModeByteOffset)); | |
| 1534 __ And(a7, a7, Operand(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); | |
| 1535 __ Branch(&push_receiver, ne, a7, Operand(zero_reg)); | |
| 1536 | |
| 1537 // Do not transform the receiver for native (Compilerhints already in a2). | |
| 1538 __ lbu(a7, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset)); | |
| 1539 __ And(a7, a7, Operand(1 << SharedFunctionInfo::kNativeBitWithinByte)); | |
| 1540 __ Branch(&push_receiver, ne, a7, Operand(zero_reg)); | |
| 1541 | |
| 1542 // Compute the receiver in sloppy mode. | |
| 1543 __ JumpIfSmi(a0, &call_to_object); | |
| 1544 __ LoadRoot(a1, Heap::kNullValueRootIndex); | |
| 1545 __ Branch(&use_global_proxy, eq, a0, Operand(a1)); | |
| 1546 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); | |
| 1547 __ Branch(&use_global_proxy, eq, a0, Operand(a2)); | |
| 1548 | |
| 1549 // Check if the receiver is already a JavaScript object. | |
| 1550 // a0: receiver | |
| 1551 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | |
| 1552 __ GetObjectType(a0, a1, a1); | |
| 1553 __ Branch(&push_receiver, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); | |
| 1554 | |
| 1555 // Convert the receiver to a regular object. | |
| 1556 // a0: receiver | |
| 1557 __ bind(&call_to_object); | |
| 1558 ToObjectStub stub(masm->isolate()); | |
| 1559 __ CallStub(&stub); | |
| 1560 __ mov(a0, v0); // Put object in a0 to match other paths to push_receiver. | |
| 1561 __ Branch(&push_receiver); | |
| 1562 | |
| 1563 __ bind(&use_global_proxy); | |
| 1564 __ ld(a0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); | |
| 1565 __ ld(a0, FieldMemOperand(a0, GlobalObject::kGlobalProxyOffset)); | |
| 1566 | |
| 1567 // Push the receiver. | |
| 1568 // a0: receiver | |
| 1569 __ bind(&push_receiver); | |
| 1570 __ push(a0); | |
| 1571 | 1379 |
| 1572 // Copy all arguments from the array to the stack. | 1380 // Copy all arguments from the array to the stack. |
| 1573 Generate_PushAppliedArguments( | 1381 Generate_PushAppliedArguments(masm, kArgumentsOffset, kIndexOffset, |
| 1574 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); | 1382 kLimitOffset); |
| 1575 | 1383 |
| 1576 // Call the function. | 1384 // Call the callable. |
| 1577 Label call_proxy; | 1385 // TODO(bmeurer): This should be a tail call according to ES6. |
| 1578 ParameterCount actual(a0); | |
| 1579 __ ld(a1, MemOperand(fp, kFunctionOffset)); | 1386 __ ld(a1, MemOperand(fp, kFunctionOffset)); |
| 1580 __ GetObjectType(a1, a2, a2); | 1387 __ Call(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
| 1581 __ Branch(&call_proxy, ne, a2, Operand(JS_FUNCTION_TYPE)); | |
| 1582 | 1388 |
| 1583 __ InvokeFunction(a1, actual, CALL_FUNCTION, NullCallWrapper()); | |
| 1584 | |
| 1585 frame_scope.GenerateLeaveFrame(); | |
| 1586 __ Ret(USE_DELAY_SLOT); | |
| 1587 __ Daddu(sp, sp, Operand(kStackSize * kPointerSize)); // In delay slot. | |
| 1588 | |
| 1589 // Call the function proxy. | |
| 1590 __ bind(&call_proxy); | |
| 1591 __ push(a1); // Add function proxy as last argument. | |
| 1592 __ Daddu(a0, a0, Operand(1)); | |
| 1593 __ li(a2, Operand(0, RelocInfo::NONE32)); | |
| 1594 __ GetBuiltinFunction(a1, Context::CALL_FUNCTION_PROXY_BUILTIN_INDEX); | |
| 1595 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | |
| 1596 RelocInfo::CODE_TARGET); | |
| 1597 // Tear down the internal frame and remove function, receiver and args. | 1389 // Tear down the internal frame and remove function, receiver and args. |
| 1598 } | 1390 } |
| 1599 | 1391 |
| 1600 __ Ret(USE_DELAY_SLOT); | 1392 __ Ret(USE_DELAY_SLOT); |
| 1601 __ Daddu(sp, sp, Operand(kStackSize * kPointerSize)); // In delay slot. | 1393 __ Daddu(sp, sp, Operand(kStackSize * kPointerSize)); // In delay slot. |
| 1602 } | 1394 } |
| 1603 | 1395 |
| 1604 | 1396 |
| 1605 static void Generate_ConstructHelper(MacroAssembler* masm) { | 1397 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1606 const int kFormalParameters = 3; | 1398 const int kFormalParameters = 3; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1723 kPointerSize))); | 1515 kPointerSize))); |
| 1724 __ mov(sp, fp); | 1516 __ mov(sp, fp); |
| 1725 __ MultiPop(fp.bit() | ra.bit()); | 1517 __ MultiPop(fp.bit() | ra.bit()); |
| 1726 __ SmiScale(a4, a1, kPointerSizeLog2); | 1518 __ SmiScale(a4, a1, kPointerSizeLog2); |
| 1727 __ Daddu(sp, sp, a4); | 1519 __ Daddu(sp, sp, a4); |
| 1728 // Adjust for the receiver. | 1520 // Adjust for the receiver. |
| 1729 __ Daddu(sp, sp, Operand(kPointerSize)); | 1521 __ Daddu(sp, sp, Operand(kPointerSize)); |
| 1730 } | 1522 } |
| 1731 | 1523 |
| 1732 | 1524 |
| 1525 // static |
| 1526 void Builtins::Generate_CallFunction(MacroAssembler* masm) { |
| 1527 // ----------- S t a t e ------------- |
| 1528 // -- a0 : the number of arguments (not including the receiver) |
| 1529 // -- a1 : the function to call (checked to be a JSFunction) |
| 1530 // ----------------------------------- |
| 1531 |
| 1532 Label convert, convert_global_proxy, convert_to_object, done_convert; |
| 1533 __ AssertFunction(a1); |
| 1534 // TODO(bmeurer): Throw a TypeError if function's [[FunctionKind]] internal |
| 1535 // slot is "classConstructor". |
| 1536 // Enter the context of the function; ToObject has to run in the function |
| 1537 // context, and we also need to take the global proxy from the function |
| 1538 // context in case of conversion. |
| 1539 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) |
| 1540 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset == |
| 1541 SharedFunctionInfo::kStrictModeByteOffset); |
| 1542 __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); |
| 1543 __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); |
| 1544 // We need to convert the receiver for non-native sloppy mode functions. |
| 1545 __ lbu(a3, FieldMemOperand(a2, SharedFunctionInfo::kNativeByteOffset)); |
| 1546 __ And(at, a3, Operand((1 << SharedFunctionInfo::kNativeBitWithinByte) | |
| 1547 (1 << SharedFunctionInfo::kStrictModeBitWithinByte))); |
| 1548 __ Branch(&done_convert, ne, at, Operand(zero_reg)); |
| 1549 { |
| 1550 __ dsll(at, a0, kPointerSizeLog2); |
| 1551 __ daddu(at, sp, at); |
| 1552 __ ld(a3, MemOperand(at)); |
| 1553 |
| 1554 // ----------- S t a t e ------------- |
| 1555 // -- a0 : the number of arguments (not including the receiver) |
| 1556 // -- a1 : the function to call (checked to be a JSFunction) |
| 1557 // -- a2 : the shared function info. |
| 1558 // -- a3 : the receiver |
| 1559 // -- cp : the function context. |
| 1560 // ----------------------------------- |
| 1561 |
| 1562 Label convert_receiver; |
| 1563 __ JumpIfSmi(a3, &convert_to_object); |
| 1564 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 1565 __ GetObjectType(a3, a4, a4); |
| 1566 __ Branch(&done_convert, hs, a4, Operand(FIRST_JS_RECEIVER_TYPE)); |
| 1567 __ JumpIfRoot(a3, Heap::kUndefinedValueRootIndex, &convert_global_proxy); |
| 1568 __ JumpIfNotRoot(a3, Heap::kNullValueRootIndex, &convert_to_object); |
| 1569 __ bind(&convert_global_proxy); |
| 1570 { |
| 1571 // Patch receiver to global proxy. |
| 1572 __ LoadGlobalProxy(a3); |
| 1573 } |
| 1574 __ Branch(&convert_receiver); |
| 1575 __ bind(&convert_to_object); |
| 1576 { |
| 1577 // Convert receiver using ToObject. |
| 1578 // TODO(bmeurer): Inline the allocation here to avoid building the frame |
| 1579 // in the fast case? (fall back to AllocateInNewSpace?) |
| 1580 FrameScope scope(masm, StackFrame::INTERNAL); |
| 1581 __ SmiTag(a0); |
| 1582 __ Push(a0, a1); |
| 1583 __ mov(a0, a3); |
| 1584 ToObjectStub stub(masm->isolate()); |
| 1585 __ CallStub(&stub); |
| 1586 __ mov(a3, v0); |
| 1587 __ Pop(a0, a1); |
| 1588 __ SmiUntag(a0); |
| 1589 } |
| 1590 __ ld(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); |
| 1591 __ bind(&convert_receiver); |
| 1592 __ dsll(at, a0, kPointerSizeLog2); |
| 1593 __ daddu(at, sp, at); |
| 1594 __ sd(a3, MemOperand(at)); |
| 1595 } |
| 1596 __ bind(&done_convert); |
| 1597 |
| 1598 // ----------- S t a t e ------------- |
| 1599 // -- a0 : the number of arguments (not including the receiver) |
| 1600 // -- a1 : the function to call (checked to be a JSFunction) |
| 1601 // -- a2 : the shared function info. |
| 1602 // -- cp : the function context. |
| 1603 // ----------------------------------- |
| 1604 |
| 1605 __ lw(a2, |
| 1606 FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset)); |
| 1607 __ ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); |
| 1608 ParameterCount actual(a0); |
| 1609 ParameterCount expected(a2); |
| 1610 __ InvokeCode(a3, expected, actual, JUMP_FUNCTION, NullCallWrapper()); |
| 1611 } |
| 1612 |
| 1613 |
| 1614 // static |
| 1615 void Builtins::Generate_Call(MacroAssembler* masm) { |
| 1616 // ----------- S t a t e ------------- |
| 1617 // -- a0 : the number of arguments (not including the receiver) |
| 1618 // -- a1 : the target to call (can be any Object). |
| 1619 // ----------------------------------- |
| 1620 |
| 1621 Label non_smi, non_function; |
| 1622 __ JumpIfSmi(a1, &non_function); |
| 1623 __ bind(&non_smi); |
| 1624 __ GetObjectType(a1, a2, a2); |
| 1625 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET, |
| 1626 eq, a2, Operand(JS_FUNCTION_TYPE)); |
| 1627 __ Branch(&non_function, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 1628 |
| 1629 // 1. Call to function proxy. |
| 1630 // TODO(neis): This doesn't match the ES6 spec for [[Call]] on proxies. |
| 1631 __ ld(a1, FieldMemOperand(a1, JSFunctionProxy::kCallTrapOffset)); |
| 1632 __ AssertNotSmi(a1); |
| 1633 __ Branch(&non_smi); |
| 1634 |
| 1635 // 2. Call to something else, which might have a [[Call]] internal method (if |
| 1636 // not we raise an exception). |
| 1637 __ bind(&non_function); |
| 1638 // TODO(bmeurer): I wonder why we prefer to have slow API calls? This could |
| 1639 // be awesome instead; i.e. a trivial improvement would be to call into the |
| 1640 // runtime and just deal with the API function there instead of returning a |
| 1641 // delegate from a runtime call that just jumps back to the runtime once |
| 1642 // called. Or, bonus points, call directly into the C API function here, as |
| 1643 // we do in some Crankshaft fast cases. |
| 1644 // Overwrite the original receiver with the (original) target. |
| 1645 __ dsll(at, a0, kPointerSizeLog2); |
| 1646 __ daddu(at, sp, at); |
| 1647 __ sd(a1, MemOperand(at)); |
| 1648 { |
| 1649 // Determine the delegate for the target (if any). |
| 1650 FrameScope scope(masm, StackFrame::INTERNAL); |
| 1651 __ SmiTag(a0); |
| 1652 __ Push(a0, a1); |
| 1653 __ CallRuntime(Runtime::kGetFunctionDelegate, 1); |
| 1654 __ mov(a1, v0); |
| 1655 __ Pop(a0); |
| 1656 __ SmiUntag(a0); |
| 1657 } |
| 1658 // The delegate is always a regular function. |
| 1659 __ AssertFunction(a1); |
| 1660 __ Jump(masm->isolate()->builtins()->CallFunction(), RelocInfo::CODE_TARGET); |
| 1661 } |
| 1662 |
| 1663 |
| 1733 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 1664 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
| 1734 // State setup as expected by MacroAssembler::InvokePrologue. | 1665 // State setup as expected by MacroAssembler::InvokePrologue. |
| 1735 // ----------- S t a t e ------------- | 1666 // ----------- S t a t e ------------- |
| 1736 // -- a0: actual arguments count | 1667 // -- a0: actual arguments count |
| 1737 // -- a1: function (passed through to callee) | 1668 // -- a1: function (passed through to callee) |
| 1738 // -- a2: expected arguments count | 1669 // -- a2: expected arguments count |
| 1739 // ----------------------------------- | 1670 // ----------------------------------- |
| 1740 | 1671 |
| 1741 Label stack_overflow; | 1672 Label stack_overflow; |
| 1742 ArgumentAdaptorStackCheck(masm, &stack_overflow); | 1673 ArgumentAdaptorStackCheck(masm, &stack_overflow); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1882 } | 1813 } |
| 1883 } | 1814 } |
| 1884 | 1815 |
| 1885 | 1816 |
| 1886 #undef __ | 1817 #undef __ |
| 1887 | 1818 |
| 1888 } // namespace internal | 1819 } // namespace internal |
| 1889 } // namespace v8 | 1820 } // namespace v8 |
| 1890 | 1821 |
| 1891 #endif // V8_TARGET_ARCH_MIPS64 | 1822 #endif // V8_TARGET_ARCH_MIPS64 |
| OLD | NEW |