OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/debug.h" | 10 #include "src/debug.h" |
(...skipping 1306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1317 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1317 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1318 RelocInfo::CODE_TARGET); | 1318 RelocInfo::CODE_TARGET); |
1319 __ Bind(&dont_adapt_args); | 1319 __ Bind(&dont_adapt_args); |
1320 | 1320 |
1321 __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 1321 __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
1322 ParameterCount expected(0); | 1322 ParameterCount expected(0); |
1323 __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper()); | 1323 __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper()); |
1324 } | 1324 } |
1325 | 1325 |
1326 | 1326 |
1327 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 1327 static void Generate_CheckStackOverflow(MacroAssembler* masm, |
1328 ASM_LOCATION("Builtins::Generate_FunctionApply"); | 1328 const int calleeOffset) { |
1329 const int kIndexOffset = | 1329 Register argc = x0; |
1330 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); | 1330 Register receiver = x14; |
1331 const int kLimitOffset = | 1331 Register function = x15; |
1332 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); | 1332 |
1333 const int kArgsOffset = 2 * kPointerSize; | 1333 // Check the stack for overflow. |
1334 const int kReceiverOffset = 3 * kPointerSize; | 1334 // We are not trying to catch interruptions (e.g. debug break and |
1335 const int kFunctionOffset = 4 * kPointerSize; | 1335 // preemption) here, so the "real stack limit" is checked. |
| 1336 Label enough_stack_space; |
| 1337 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex); |
| 1338 __ Ldr(function, MemOperand(fp, calleeOffset)); |
| 1339 // Make x10 the space we have left. The stack might already be overflowed |
| 1340 // here which will cause x10 to become negative. |
| 1341 // TODO(jbramley): Check that the stack usage here is safe. |
| 1342 __ Sub(x10, jssp, x10); |
| 1343 // Check if the arguments will overflow the stack. |
| 1344 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2)); |
| 1345 __ B(gt, &enough_stack_space); |
| 1346 // There is not enough stack space, so use a builtin to throw an appropriate |
| 1347 // error. |
| 1348 __ Push(function, argc); |
| 1349 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
| 1350 // We should never return from the APPLY_OVERFLOW builtin. |
| 1351 if (__ emit_debug_code()) { |
| 1352 __ Unreachable(); |
| 1353 } |
| 1354 |
| 1355 __ Bind(&enough_stack_space); |
| 1356 } |
| 1357 |
| 1358 |
| 1359 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 1360 const int argumentsOffset, |
| 1361 const int indexOffset, |
| 1362 const int limitOffset) { |
| 1363 Label entry, loop; |
| 1364 Register current = x0; |
| 1365 __ Ldr(current, MemOperand(fp, indexOffset)); |
| 1366 __ B(&entry); |
| 1367 |
| 1368 __ Bind(&loop); |
| 1369 // Load the current argument from the arguments array and push it. |
| 1370 // TODO(all): Couldn't we optimize this for JS arrays? |
| 1371 |
| 1372 __ Ldr(x1, MemOperand(fp, argumentsOffset)); |
| 1373 __ Push(x1, current); |
| 1374 |
| 1375 // Call the runtime to access the property in the arguments array. |
| 1376 __ CallRuntime(Runtime::kGetProperty, 2); |
| 1377 __ Push(x0); |
| 1378 |
| 1379 // Use inline caching to access the arguments. |
| 1380 __ Ldr(current, MemOperand(fp, indexOffset)); |
| 1381 __ Add(current, current, Smi::FromInt(1)); |
| 1382 __ Str(current, MemOperand(fp, indexOffset)); |
| 1383 |
| 1384 // Test if the copy loop has finished copying all the elements from the |
| 1385 // arguments object. |
| 1386 __ Bind(&entry); |
| 1387 __ Ldr(x1, MemOperand(fp, limitOffset)); |
| 1388 __ Cmp(current, x1); |
| 1389 __ B(ne, &loop); |
| 1390 |
| 1391 // On exit, the pushed arguments count is in x0, untagged |
| 1392 __ SmiUntag(current); |
| 1393 } |
| 1394 |
| 1395 |
| 1396 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) { |
| 1397 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1398 const int kStackSize = kFormalParameters + 1; |
1336 | 1399 |
1337 { | 1400 { |
1338 FrameScope frame_scope(masm, StackFrame::INTERNAL); | 1401 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
1339 | 1402 |
| 1403 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
| 1404 const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
| 1405 const int kFunctionOffset = kReceiverOffset + kPointerSize; |
| 1406 const int kIndexOffset = |
| 1407 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); |
| 1408 const int kLimitOffset = |
| 1409 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); |
| 1410 |
1340 Register args = x12; | 1411 Register args = x12; |
1341 Register receiver = x14; | 1412 Register receiver = x14; |
1342 Register function = x15; | 1413 Register function = x15; |
1343 | 1414 |
1344 // Get the length of the arguments via a builtin call. | 1415 // Get the length of the arguments via a builtin call. |
1345 __ Ldr(function, MemOperand(fp, kFunctionOffset)); | 1416 __ Ldr(function, MemOperand(fp, kFunctionOffset)); |
1346 __ Ldr(args, MemOperand(fp, kArgsOffset)); | 1417 __ Ldr(args, MemOperand(fp, kArgumentsOffset)); |
1347 __ Push(function, args); | 1418 __ Push(function, args); |
1348 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 1419 if (targetIsArgument) { |
| 1420 __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION); |
| 1421 } else { |
| 1422 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
| 1423 } |
1349 Register argc = x0; | 1424 Register argc = x0; |
1350 | 1425 |
1351 // Check the stack for overflow. | 1426 Generate_CheckStackOverflow(masm, kFunctionOffset); |
1352 // We are not trying to catch interruptions (e.g. debug break and | |
1353 // preemption) here, so the "real stack limit" is checked. | |
1354 Label enough_stack_space; | |
1355 __ LoadRoot(x10, Heap::kRealStackLimitRootIndex); | |
1356 __ Ldr(function, MemOperand(fp, kFunctionOffset)); | |
1357 // Make x10 the space we have left. The stack might already be overflowed | |
1358 // here which will cause x10 to become negative. | |
1359 // TODO(jbramley): Check that the stack usage here is safe. | |
1360 __ Sub(x10, jssp, x10); | |
1361 // Check if the arguments will overflow the stack. | |
1362 __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2)); | |
1363 __ B(gt, &enough_stack_space); | |
1364 // There is not enough stack space, so use a builtin to throw an appropriate | |
1365 // error. | |
1366 __ Push(function, argc); | |
1367 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); | |
1368 // We should never return from the APPLY_OVERFLOW builtin. | |
1369 if (__ emit_debug_code()) { | |
1370 __ Unreachable(); | |
1371 } | |
1372 | 1427 |
1373 __ Bind(&enough_stack_space); | |
1374 // Push current limit and index. | 1428 // Push current limit and index. |
1375 __ Mov(x1, 0); // Initial index. | 1429 __ Mov(x1, 0); // Initial index. |
1376 __ Push(argc, x1); | 1430 __ Push(argc, x1); |
1377 | 1431 |
1378 Label push_receiver; | 1432 Label push_receiver; |
1379 __ Ldr(receiver, MemOperand(fp, kReceiverOffset)); | 1433 __ Ldr(receiver, MemOperand(fp, kReceiverOffset)); |
1380 | 1434 |
1381 // Check that the function is a JS function. Otherwise it must be a proxy. | 1435 // Check that the function is a JS function. Otherwise it must be a proxy. |
1382 // When it is not the function proxy will be invoked later. | 1436 // When it is not the function proxy will be invoked later. |
1383 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, | 1437 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1417 | 1471 |
1418 __ Bind(&use_global_proxy); | 1472 __ Bind(&use_global_proxy); |
1419 __ Ldr(x10, GlobalObjectMemOperand()); | 1473 __ Ldr(x10, GlobalObjectMemOperand()); |
1420 __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset)); | 1474 __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset)); |
1421 | 1475 |
1422 // Push the receiver | 1476 // Push the receiver |
1423 __ Bind(&push_receiver); | 1477 __ Bind(&push_receiver); |
1424 __ Push(receiver); | 1478 __ Push(receiver); |
1425 | 1479 |
1426 // Copy all arguments from the array to the stack. | 1480 // Copy all arguments from the array to the stack. |
1427 Label entry, loop; | 1481 Generate_PushAppliedArguments( |
1428 Register current = x0; | 1482 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
1429 __ Ldr(current, MemOperand(fp, kIndexOffset)); | |
1430 __ B(&entry); | |
1431 | |
1432 __ Bind(&loop); | |
1433 // Load the current argument from the arguments array and push it. | |
1434 // TODO(all): Couldn't we optimize this for JS arrays? | |
1435 | |
1436 __ Ldr(x1, MemOperand(fp, kArgsOffset)); | |
1437 __ Push(x1, current); | |
1438 | |
1439 // Call the runtime to access the property in the arguments array. | |
1440 __ CallRuntime(Runtime::kGetProperty, 2); | |
1441 __ Push(x0); | |
1442 | |
1443 // Use inline caching to access the arguments. | |
1444 __ Ldr(current, MemOperand(fp, kIndexOffset)); | |
1445 __ Add(current, current, Smi::FromInt(1)); | |
1446 __ Str(current, MemOperand(fp, kIndexOffset)); | |
1447 | |
1448 // Test if the copy loop has finished copying all the elements from the | |
1449 // arguments object. | |
1450 __ Bind(&entry); | |
1451 __ Ldr(x1, MemOperand(fp, kLimitOffset)); | |
1452 __ Cmp(current, x1); | |
1453 __ B(ne, &loop); | |
1454 | 1483 |
1455 // At the end of the loop, the number of arguments is stored in 'current', | 1484 // At the end of the loop, the number of arguments is stored in 'current', |
1456 // represented as a smi. | 1485 // represented as a smi. |
1457 | 1486 |
1458 function = x1; // From now on we want the function to be kept in x1; | 1487 function = x1; // From now on we want the function to be kept in x1; |
1459 __ Ldr(function, MemOperand(fp, kFunctionOffset)); | 1488 __ Ldr(function, MemOperand(fp, kFunctionOffset)); |
1460 | 1489 |
1461 // Call the function. | 1490 // Call the function. |
1462 Label call_proxy; | 1491 Label call_proxy; |
1463 ParameterCount actual(current); | 1492 ParameterCount actual(x0); |
1464 __ SmiUntag(current); | |
1465 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy); | 1493 __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy); |
1466 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper()); | 1494 __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper()); |
1467 frame_scope.GenerateLeaveFrame(); | 1495 frame_scope.GenerateLeaveFrame(); |
1468 __ Drop(3); | 1496 __ Drop(kStackSize); |
1469 __ Ret(); | 1497 __ Ret(); |
1470 | 1498 |
1471 // Call the function proxy. | 1499 // Call the function proxy. |
1472 __ Bind(&call_proxy); | 1500 __ Bind(&call_proxy); |
1473 // x0 : argc | 1501 // x0 : argc |
1474 // x1 : function | 1502 // x1 : function |
1475 __ Push(function); // Add function proxy as last argument. | 1503 __ Push(function); // Add function proxy as last argument. |
1476 __ Add(x0, x0, 1); | 1504 __ Add(x0, x0, 1); |
1477 __ Mov(x2, 0); | 1505 __ Mov(x2, 0); |
1478 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); | 1506 __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY); |
1479 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1507 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1480 RelocInfo::CODE_TARGET); | 1508 RelocInfo::CODE_TARGET); |
1481 } | 1509 } |
1482 __ Drop(3); | 1510 __ Drop(kStackSize); |
1483 __ Ret(); | 1511 __ Ret(); |
1484 } | 1512 } |
1485 | 1513 |
1486 | 1514 |
| 1515 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1516 const int kFormalParameters = 3; |
| 1517 const int kStackSize = kFormalParameters + 1; |
| 1518 |
| 1519 { |
| 1520 FrameScope frame_scope(masm, StackFrame::INTERNAL); |
| 1521 |
| 1522 const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize; |
| 1523 const int kArgumentsOffset = kNewTargetOffset + kPointerSize; |
| 1524 const int kFunctionOffset = kArgumentsOffset + kPointerSize; |
| 1525 |
| 1526 const int kIndexOffset = |
| 1527 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); |
| 1528 const int kLimitOffset = |
| 1529 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); |
| 1530 |
| 1531 // Is x11 safe to use? |
| 1532 Register newTarget = x11; |
| 1533 Register args = x12; |
| 1534 Register receiver = x14; |
| 1535 Register function = x15; |
| 1536 |
| 1537 // If newTarget is not supplied, set it to constructor |
| 1538 Label validate_arguments; |
| 1539 __ Ldr(x0, MemOperand(fp, kNewTargetOffset)); |
| 1540 __ CompareRoot(x0, Heap::kUndefinedValueRootIndex); |
| 1541 __ B(ne, &validate_arguments); |
| 1542 __ Ldr(x0, MemOperand(fp, kFunctionOffset)); |
| 1543 __ Str(x0, MemOperand(fp, kNewTargetOffset)); |
| 1544 |
| 1545 // Validate arguments |
| 1546 __ Bind(&validate_arguments); |
| 1547 __ Ldr(function, MemOperand(fp, kFunctionOffset)); |
| 1548 __ Ldr(args, MemOperand(fp, kArgumentsOffset)); |
| 1549 __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset)); |
| 1550 __ Push(function, args, newTarget); |
| 1551 __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION); |
| 1552 Register argc = x0; |
| 1553 |
| 1554 Generate_CheckStackOverflow(masm, kFunctionOffset); |
| 1555 |
| 1556 // Push current limit and index, constructor & newTarget |
| 1557 __ Mov(x1, 0); // Initial index. |
| 1558 __ Ldr(newTarget, MemOperand(fp, kNewTargetOffset)); |
| 1559 __ Push(argc, x1, newTarget, function); |
| 1560 |
| 1561 // Copy all arguments from the array to the stack. |
| 1562 Generate_PushAppliedArguments( |
| 1563 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
| 1564 |
| 1565 __ Ldr(x1, MemOperand(fp, kFunctionOffset)); |
| 1566 // Use undefined feedback vector |
| 1567 __ LoadRoot(x2, Heap::kUndefinedValueRootIndex); |
| 1568 |
| 1569 // Call the function. |
| 1570 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); |
| 1571 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); |
| 1572 |
| 1573 __ Drop(1); |
| 1574 } |
| 1575 __ Drop(kStackSize); |
| 1576 __ Ret(); |
| 1577 } |
| 1578 |
| 1579 |
| 1580 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 1581 ASM_LOCATION("Builtins::Generate_FunctionApply"); |
| 1582 Generate_ApplyHelper(masm, false); |
| 1583 } |
| 1584 |
| 1585 |
| 1586 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { |
| 1587 ASM_LOCATION("Builtins::Generate_ReflectApply"); |
| 1588 Generate_ApplyHelper(masm, true); |
| 1589 } |
| 1590 |
| 1591 |
| 1592 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { |
| 1593 ASM_LOCATION("Builtins::Generate_ReflectConstruct"); |
| 1594 Generate_ConstructHelper(masm); |
| 1595 } |
| 1596 |
| 1597 |
1487 static void ArgumentAdaptorStackCheck(MacroAssembler* masm, | 1598 static void ArgumentAdaptorStackCheck(MacroAssembler* masm, |
1488 Label* stack_overflow) { | 1599 Label* stack_overflow) { |
1489 // ----------- S t a t e ------------- | 1600 // ----------- S t a t e ------------- |
1490 // -- x0 : actual number of arguments | 1601 // -- x0 : actual number of arguments |
1491 // -- x1 : function (passed through to callee) | 1602 // -- x1 : function (passed through to callee) |
1492 // -- x2 : expected number of arguments | 1603 // -- x2 : expected number of arguments |
1493 // ----------------------------------- | 1604 // ----------------------------------- |
1494 // Check the stack for overflow. | 1605 // Check the stack for overflow. |
1495 // We are not trying to catch interruptions (e.g. debug break and | 1606 // We are not trying to catch interruptions (e.g. debug break and |
1496 // preemption) here, so the "real stack limit" is checked. | 1607 // preemption) here, so the "real stack limit" is checked. |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1669 __ Unreachable(); | 1780 __ Unreachable(); |
1670 } | 1781 } |
1671 } | 1782 } |
1672 | 1783 |
1673 | 1784 |
1674 #undef __ | 1785 #undef __ |
1675 | 1786 |
1676 } } // namespace v8::internal | 1787 } } // namespace v8::internal |
1677 | 1788 |
1678 #endif // V8_TARGET_ARCH_ARM | 1789 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |