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