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_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/debug.h" | 10 #include "src/debug.h" |
(...skipping 1318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1329 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1329 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1330 RelocInfo::CODE_TARGET, | 1330 RelocInfo::CODE_TARGET, |
1331 ne); | 1331 ne); |
1332 | 1332 |
1333 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); | 1333 __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); |
1334 ParameterCount expected(0); | 1334 ParameterCount expected(0); |
1335 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION, NullCallWrapper()); | 1335 __ InvokeCode(r3, expected, expected, JUMP_FUNCTION, NullCallWrapper()); |
1336 } | 1336 } |
1337 | 1337 |
1338 | 1338 |
1339 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { | 1339 static void Generate_CheckStackOverflow(MacroAssembler* masm, |
1340 const int kIndexOffset = | 1340 const int calleeOffset) { |
1341 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); | 1341 // Check the stack for overflow. We are not trying to catch |
1342 const int kLimitOffset = | 1342 // interruptions (e.g. debug break and preemption) here, so the "real stack |
1343 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); | 1343 // limit" is checked. |
1344 const int kArgsOffset = 2 * kPointerSize; | 1344 Label okay; |
1345 const int kRecvOffset = 3 * kPointerSize; | 1345 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); |
1346 const int kFunctionOffset = 4 * kPointerSize; | 1346 // Make r2 the space we have left. The stack might already be overflowed |
| 1347 // here which will cause r2 to become negative. |
| 1348 __ sub(r2, sp, r2); |
| 1349 // Check if the arguments will overflow the stack. |
| 1350 __ cmp(r2, Operand::PointerOffsetFromSmiKey(r0)); |
| 1351 __ b(gt, &okay); // Signed comparison. |
| 1352 |
| 1353 // Out of stack space. |
| 1354 __ ldr(r1, MemOperand(fp, calleeOffset)); |
| 1355 __ Push(r1, r0); |
| 1356 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); |
| 1357 |
| 1358 __ bind(&okay); |
| 1359 } |
| 1360 |
| 1361 |
| 1362 static void Generate_PushAppliedArguments(MacroAssembler* masm, |
| 1363 const int argumentsOffset, |
| 1364 const int indexOffset, |
| 1365 const int limitOffset) { |
| 1366 Label entry, loop; |
| 1367 __ ldr(r0, MemOperand(fp, indexOffset)); |
| 1368 __ b(&entry); |
| 1369 |
| 1370 // Load the current argument from the arguments array and push it to the |
| 1371 // stack. |
| 1372 // r0: current argument index |
| 1373 __ bind(&loop); |
| 1374 __ ldr(r1, MemOperand(fp, argumentsOffset)); |
| 1375 __ Push(r1, r0); |
| 1376 |
| 1377 // Call the runtime to access the property in the arguments array. |
| 1378 __ CallRuntime(Runtime::kGetProperty, 2); |
| 1379 __ push(r0); |
| 1380 |
| 1381 // Use inline caching to access the arguments. |
| 1382 __ ldr(r0, MemOperand(fp, indexOffset)); |
| 1383 __ add(r0, r0, Operand(1 << kSmiTagSize)); |
| 1384 __ str(r0, MemOperand(fp, indexOffset)); |
| 1385 |
| 1386 // Test if the copy loop has finished copying all the elements from the |
| 1387 // arguments object. |
| 1388 __ bind(&entry); |
| 1389 __ ldr(r1, MemOperand(fp, limitOffset)); |
| 1390 __ cmp(r0, r1); |
| 1391 __ b(ne, &loop); |
| 1392 |
| 1393 // On exit, the pushed arguments count is in r0, untagged |
| 1394 __ SmiUntag(r0); |
| 1395 } |
| 1396 |
| 1397 |
| 1398 // Used by FunctionApply and ReflectApply |
| 1399 static void Generate_ApplyHelper(MacroAssembler* masm, bool targetIsArgument) { |
| 1400 const int kFormalParameters = targetIsArgument ? 3 : 2; |
| 1401 const int kStackSize = kFormalParameters + 1; |
1347 | 1402 |
1348 { | 1403 { |
1349 FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); | 1404 FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); |
| 1405 const int kArgumentsOffset = kFPOnStackSize + kPCOnStackSize; |
| 1406 const int kReceiverOffset = kArgumentsOffset + kPointerSize; |
| 1407 const int kFunctionOffset = kReceiverOffset + kPointerSize; |
1350 | 1408 |
1351 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function | 1409 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function |
1352 __ push(r0); | 1410 __ push(r0); |
1353 __ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array | 1411 __ ldr(r0, MemOperand(fp, kArgumentsOffset)); // get the args array |
1354 __ push(r0); | 1412 __ push(r0); |
1355 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); | 1413 if (targetIsArgument) { |
| 1414 __ InvokeBuiltin(Builtins::REFLECT_APPLY_PREPARE, CALL_FUNCTION); |
| 1415 } else { |
| 1416 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); |
| 1417 } |
1356 | 1418 |
1357 // Check the stack for overflow. We are not trying to catch | 1419 Generate_CheckStackOverflow(masm, kFunctionOffset); |
1358 // interruptions (e.g. debug break and preemption) here, so the "real stack | |
1359 // limit" is checked. | |
1360 Label okay; | |
1361 __ LoadRoot(r2, Heap::kRealStackLimitRootIndex); | |
1362 // Make r2 the space we have left. The stack might already be overflowed | |
1363 // here which will cause r2 to become negative. | |
1364 __ sub(r2, sp, r2); | |
1365 // Check if the arguments will overflow the stack. | |
1366 __ cmp(r2, Operand::PointerOffsetFromSmiKey(r0)); | |
1367 __ b(gt, &okay); // Signed comparison. | |
1368 | |
1369 // Out of stack space. | |
1370 __ ldr(r1, MemOperand(fp, kFunctionOffset)); | |
1371 __ Push(r1, r0); | |
1372 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); | |
1373 // End of stack check. | |
1374 | 1420 |
1375 // Push current limit and index. | 1421 // Push current limit and index. |
1376 __ bind(&okay); | 1422 const int kIndexOffset = |
| 1423 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); |
| 1424 const int kLimitOffset = |
| 1425 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); |
1377 __ push(r0); // limit | 1426 __ push(r0); // limit |
1378 __ mov(r1, Operand::Zero()); // initial index | 1427 __ mov(r1, Operand::Zero()); // initial index |
1379 __ push(r1); | 1428 __ push(r1); |
1380 | 1429 |
1381 // Get the receiver. | 1430 // Get the receiver. |
1382 __ ldr(r0, MemOperand(fp, kRecvOffset)); | 1431 __ ldr(r0, MemOperand(fp, kReceiverOffset)); |
1383 | 1432 |
1384 // Check that the function is a JS function (otherwise it must be a proxy). | 1433 // Check that the function is a JS function (otherwise it must be a proxy). |
1385 Label push_receiver; | 1434 Label push_receiver; |
1386 __ ldr(r1, MemOperand(fp, kFunctionOffset)); | 1435 __ ldr(r1, MemOperand(fp, kFunctionOffset)); |
1387 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); | 1436 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); |
1388 __ b(ne, &push_receiver); | 1437 __ b(ne, &push_receiver); |
1389 | 1438 |
1390 // Change context eagerly to get the right global object if necessary. | 1439 // Change context eagerly to get the right global object if necessary. |
1391 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | 1440 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
1392 // Load the shared function info while the function is still in r1. | 1441 // Load the shared function info while the function is still in r1. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1429 __ bind(&use_global_proxy); | 1478 __ bind(&use_global_proxy); |
1430 __ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); | 1479 __ ldr(r0, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); |
1431 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalProxyOffset)); | 1480 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalProxyOffset)); |
1432 | 1481 |
1433 // Push the receiver. | 1482 // Push the receiver. |
1434 // r0: receiver | 1483 // r0: receiver |
1435 __ bind(&push_receiver); | 1484 __ bind(&push_receiver); |
1436 __ push(r0); | 1485 __ push(r0); |
1437 | 1486 |
1438 // Copy all arguments from the array to the stack. | 1487 // Copy all arguments from the array to the stack. |
1439 Label entry, loop; | 1488 Generate_PushAppliedArguments( |
1440 __ ldr(r0, MemOperand(fp, kIndexOffset)); | 1489 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
1441 __ b(&entry); | |
1442 | |
1443 // Load the current argument from the arguments array and push it to the | |
1444 // stack. | |
1445 // r0: current argument index | |
1446 __ bind(&loop); | |
1447 __ ldr(r1, MemOperand(fp, kArgsOffset)); | |
1448 __ Push(r1, r0); | |
1449 | |
1450 // Call the runtime to access the property in the arguments array. | |
1451 __ CallRuntime(Runtime::kGetProperty, 2); | |
1452 __ push(r0); | |
1453 | |
1454 // Use inline caching to access the arguments. | |
1455 __ ldr(r0, MemOperand(fp, kIndexOffset)); | |
1456 __ add(r0, r0, Operand(1 << kSmiTagSize)); | |
1457 __ str(r0, MemOperand(fp, kIndexOffset)); | |
1458 | |
1459 // Test if the copy loop has finished copying all the elements from the | |
1460 // arguments object. | |
1461 __ bind(&entry); | |
1462 __ ldr(r1, MemOperand(fp, kLimitOffset)); | |
1463 __ cmp(r0, r1); | |
1464 __ b(ne, &loop); | |
1465 | 1490 |
1466 // Call the function. | 1491 // Call the function. |
1467 Label call_proxy; | 1492 Label call_proxy; |
1468 ParameterCount actual(r0); | 1493 ParameterCount actual(r0); |
1469 __ SmiUntag(r0); | |
1470 __ ldr(r1, MemOperand(fp, kFunctionOffset)); | 1494 __ ldr(r1, MemOperand(fp, kFunctionOffset)); |
1471 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); | 1495 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); |
1472 __ b(ne, &call_proxy); | 1496 __ b(ne, &call_proxy); |
1473 __ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper()); | 1497 __ InvokeFunction(r1, actual, CALL_FUNCTION, NullCallWrapper()); |
1474 | 1498 |
1475 frame_scope.GenerateLeaveFrame(); | 1499 frame_scope.GenerateLeaveFrame(); |
1476 __ add(sp, sp, Operand(3 * kPointerSize)); | 1500 __ add(sp, sp, Operand(kStackSize * kPointerSize)); |
1477 __ Jump(lr); | 1501 __ Jump(lr); |
1478 | 1502 |
1479 // Call the function proxy. | 1503 // Call the function proxy. |
1480 __ bind(&call_proxy); | 1504 __ bind(&call_proxy); |
1481 __ push(r1); // add function proxy as last argument | 1505 __ push(r1); // add function proxy as last argument |
1482 __ add(r0, r0, Operand(1)); | 1506 __ add(r0, r0, Operand(1)); |
1483 __ mov(r2, Operand::Zero()); | 1507 __ mov(r2, Operand::Zero()); |
1484 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); | 1508 __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY); |
1485 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), | 1509 __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
1486 RelocInfo::CODE_TARGET); | 1510 RelocInfo::CODE_TARGET); |
1487 | 1511 |
1488 // Tear down the internal frame and remove function, receiver and args. | 1512 // Tear down the internal frame and remove function, receiver and args. |
1489 } | 1513 } |
1490 __ add(sp, sp, Operand(3 * kPointerSize)); | 1514 __ add(sp, sp, Operand(kStackSize * kPointerSize)); |
1491 __ Jump(lr); | 1515 __ Jump(lr); |
1492 } | 1516 } |
1493 | 1517 |
1494 | 1518 |
| 1519 static void Generate_ConstructHelper(MacroAssembler* masm) { |
| 1520 const int kFormalParameters = 3; |
| 1521 const int kStackSize = kFormalParameters + 1; |
| 1522 |
| 1523 { |
| 1524 FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); |
| 1525 const int kNewTargetOffset = kFPOnStackSize + kPCOnStackSize; |
| 1526 const int kArgumentsOffset = kNewTargetOffset + kPointerSize; |
| 1527 const int kFunctionOffset = kArgumentsOffset + kPointerSize; |
| 1528 |
| 1529 // If newTarget is not supplied, set it to constructor |
| 1530 Label validate_arguments; |
| 1531 __ ldr(r0, MemOperand(fp, kNewTargetOffset)); |
| 1532 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); |
| 1533 __ b(ne, &validate_arguments); |
| 1534 __ ldr(r0, MemOperand(fp, kFunctionOffset)); |
| 1535 __ str(r0, MemOperand(fp, kNewTargetOffset)); |
| 1536 |
| 1537 // Validate arguments |
| 1538 __ bind(&validate_arguments); |
| 1539 __ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function |
| 1540 __ push(r0); |
| 1541 __ ldr(r0, MemOperand(fp, kArgumentsOffset)); // get the args array |
| 1542 __ push(r0); |
| 1543 __ ldr(r0, MemOperand(fp, kNewTargetOffset)); // get the new.target |
| 1544 __ push(r0); |
| 1545 __ InvokeBuiltin(Builtins::REFLECT_CONSTRUCT_PREPARE, CALL_FUNCTION); |
| 1546 |
| 1547 Generate_CheckStackOverflow(masm, kFunctionOffset); |
| 1548 |
| 1549 // Push current limit and index. |
| 1550 const int kIndexOffset = |
| 1551 StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize); |
| 1552 const int kLimitOffset = |
| 1553 StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize); |
| 1554 __ push(r0); // limit |
| 1555 __ mov(r1, Operand::Zero()); // initial index |
| 1556 __ push(r1); |
| 1557 // Push newTarget and callee functions |
| 1558 __ ldr(r0, MemOperand(fp, kNewTargetOffset)); |
| 1559 __ push(r0); |
| 1560 __ ldr(r0, MemOperand(fp, kFunctionOffset)); |
| 1561 __ push(r0); |
| 1562 |
| 1563 // Copy all arguments from the array to the stack. |
| 1564 Generate_PushAppliedArguments( |
| 1565 masm, kArgumentsOffset, kIndexOffset, kLimitOffset); |
| 1566 |
| 1567 // Use undefined feedback vector |
| 1568 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| 1569 __ ldr(r1, MemOperand(fp, kFunctionOffset)); |
| 1570 |
| 1571 // Call the function. |
| 1572 CallConstructStub stub(masm->isolate(), SUPER_CONSTRUCTOR_CALL); |
| 1573 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL); |
| 1574 |
| 1575 __ Drop(1); |
| 1576 |
| 1577 // Leave internal frame. |
| 1578 } |
| 1579 __ add(sp, sp, Operand(kStackSize * kPointerSize)); |
| 1580 __ Jump(lr); |
| 1581 } |
| 1582 |
| 1583 |
| 1584 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { |
| 1585 Generate_ApplyHelper(masm, false); |
| 1586 } |
| 1587 |
| 1588 |
| 1589 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { |
| 1590 Generate_ApplyHelper(masm, true); |
| 1591 } |
| 1592 |
| 1593 |
| 1594 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { |
| 1595 Generate_ConstructHelper(masm); |
| 1596 } |
| 1597 |
| 1598 |
1495 static void ArgumentAdaptorStackCheck(MacroAssembler* masm, | 1599 static void ArgumentAdaptorStackCheck(MacroAssembler* masm, |
1496 Label* stack_overflow) { | 1600 Label* stack_overflow) { |
1497 // ----------- S t a t e ------------- | 1601 // ----------- S t a t e ------------- |
1498 // -- r0 : actual number of arguments | 1602 // -- r0 : actual number of arguments |
1499 // -- r1 : function (passed through to callee) | 1603 // -- r1 : function (passed through to callee) |
1500 // -- r2 : expected number of arguments | 1604 // -- r2 : expected number of arguments |
1501 // ----------------------------------- | 1605 // ----------------------------------- |
1502 // Check the stack for overflow. We are not trying to catch | 1606 // Check the stack for overflow. We are not trying to catch |
1503 // interruptions (e.g. debug break and preemption) here, so the "real stack | 1607 // interruptions (e.g. debug break and preemption) here, so the "real stack |
1504 // limit" is checked. | 1608 // limit" is checked. |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1655 __ bkpt(0); | 1759 __ bkpt(0); |
1656 } | 1760 } |
1657 } | 1761 } |
1658 | 1762 |
1659 | 1763 |
1660 #undef __ | 1764 #undef __ |
1661 | 1765 |
1662 } } // namespace v8::internal | 1766 } } // namespace v8::internal |
1663 | 1767 |
1664 #endif // V8_TARGET_ARCH_ARM | 1768 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |