| 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 |