| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 void MacroAssembler::PushRoot(Heap::RootListIndex index) { | 61 void MacroAssembler::PushRoot(Heap::RootListIndex index) { |
| 62 push(Operand(kRootRegister, index << kPointerSizeLog2)); | 62 push(Operand(kRootRegister, index << kPointerSizeLog2)); |
| 63 } | 63 } |
| 64 | 64 |
| 65 | 65 |
| 66 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { | 66 void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) { |
| 67 cmpq(with, Operand(kRootRegister, index << kPointerSizeLog2)); | 67 cmpq(with, Operand(kRootRegister, index << kPointerSizeLog2)); |
| 68 } | 68 } |
| 69 | 69 |
| 70 | 70 |
| 71 void MacroAssembler::CompareRoot(Operand with, Heap::RootListIndex index) { | 71 void MacroAssembler::CompareRoot(const Operand& with, |
| 72 Heap::RootListIndex index) { |
| 73 ASSERT(!with.AddressUsesRegister(kScratchRegister)); |
| 72 LoadRoot(kScratchRegister, index); | 74 LoadRoot(kScratchRegister, index); |
| 73 cmpq(with, kScratchRegister); | 75 cmpq(with, kScratchRegister); |
| 74 } | 76 } |
| 75 | 77 |
| 76 | 78 |
| 77 void MacroAssembler::RecordWriteHelper(Register object, | 79 void MacroAssembler::RecordWriteHelper(Register object, |
| 78 Register addr, | 80 Register addr, |
| 79 Register scratch, | 81 Register scratch, |
| 80 SaveFPRegsMode save_fp) { | 82 SaveFPRegsMode save_fp) { |
| 81 if (FLAG_debug_code) { | 83 if (FLAG_debug_code) { |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; | 294 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; |
| 293 // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag. | 295 // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag. |
| 294 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); | 296 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); |
| 295 #ifdef DEBUG | 297 #ifdef DEBUG |
| 296 if (msg != NULL) { | 298 if (msg != NULL) { |
| 297 RecordComment("Abort message: "); | 299 RecordComment("Abort message: "); |
| 298 RecordComment(msg); | 300 RecordComment(msg); |
| 299 } | 301 } |
| 300 #endif | 302 #endif |
| 301 // Disable stub call restrictions to always allow calls to abort. | 303 // Disable stub call restrictions to always allow calls to abort. |
| 302 set_allow_stub_calls(true); | 304 AllowStubCallsScope allow_scope(this, true); |
| 303 | 305 |
| 304 push(rax); | 306 push(rax); |
| 305 movq(kScratchRegister, p0, RelocInfo::NONE); | 307 movq(kScratchRegister, p0, RelocInfo::NONE); |
| 306 push(kScratchRegister); | 308 push(kScratchRegister); |
| 307 movq(kScratchRegister, | 309 movq(kScratchRegister, |
| 308 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(p1 - p0))), | 310 reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(p1 - p0))), |
| 309 RelocInfo::NONE); | 311 RelocInfo::NONE); |
| 310 push(kScratchRegister); | 312 push(kScratchRegister); |
| 311 CallRuntime(Runtime::kAbort, 2); | 313 CallRuntime(Runtime::kAbort, 2); |
| 312 // will not return here | 314 // will not return here |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 // there is no difference in using either key. | 381 // there is no difference in using either key. |
| 380 Integer32ToSmi(index, hash); | 382 Integer32ToSmi(index, hash); |
| 381 } | 383 } |
| 382 | 384 |
| 383 | 385 |
| 384 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { | 386 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { |
| 385 CallRuntime(Runtime::FunctionForId(id), num_arguments); | 387 CallRuntime(Runtime::FunctionForId(id), num_arguments); |
| 386 } | 388 } |
| 387 | 389 |
| 388 | 390 |
| 391 void MacroAssembler::CallRuntimeSaveDoubles(Runtime::FunctionId id) { |
| 392 Runtime::Function* function = Runtime::FunctionForId(id); |
| 393 Set(rax, function->nargs); |
| 394 movq(rbx, ExternalReference(function)); |
| 395 CEntryStub ces(1); |
| 396 ces.SaveDoubles(); |
| 397 CallStub(&ces); |
| 398 } |
| 399 |
| 400 |
| 389 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, | 401 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, |
| 390 int num_arguments) { | 402 int num_arguments) { |
| 391 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); | 403 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); |
| 392 } | 404 } |
| 393 | 405 |
| 394 | 406 |
| 395 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { | 407 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { |
| 396 // If the expected number of arguments of the runtime function is | 408 // If the expected number of arguments of the runtime function is |
| 397 // constant, we check that the actual number of arguments match the | 409 // constant, we check that the actual number of arguments match the |
| 398 // expectation. | 410 // expectation. |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 } | 901 } |
| 890 | 902 |
| 891 | 903 |
| 892 Condition MacroAssembler::CheckSmi(Register src) { | 904 Condition MacroAssembler::CheckSmi(Register src) { |
| 893 ASSERT_EQ(0, kSmiTag); | 905 ASSERT_EQ(0, kSmiTag); |
| 894 testb(src, Immediate(kSmiTagMask)); | 906 testb(src, Immediate(kSmiTagMask)); |
| 895 return zero; | 907 return zero; |
| 896 } | 908 } |
| 897 | 909 |
| 898 | 910 |
| 911 Condition MacroAssembler::CheckSmi(const Operand& src) { |
| 912 ASSERT_EQ(0, kSmiTag); |
| 913 testb(src, Immediate(kSmiTagMask)); |
| 914 return zero; |
| 915 } |
| 916 |
| 917 |
| 899 Condition MacroAssembler::CheckNonNegativeSmi(Register src) { | 918 Condition MacroAssembler::CheckNonNegativeSmi(Register src) { |
| 900 ASSERT_EQ(0, kSmiTag); | 919 ASSERT_EQ(0, kSmiTag); |
| 901 // Make mask 0x8000000000000001 and test that both bits are zero. | 920 // Make mask 0x8000000000000001 and test that both bits are zero. |
| 902 movq(kScratchRegister, src); | 921 movq(kScratchRegister, src); |
| 903 rol(kScratchRegister, Immediate(1)); | 922 rol(kScratchRegister, Immediate(1)); |
| 904 testb(kScratchRegister, Immediate(3)); | 923 testb(kScratchRegister, Immediate(3)); |
| 905 return zero; | 924 return zero; |
| 906 } | 925 } |
| 907 | 926 |
| 908 | 927 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 | 983 |
| 965 | 984 |
| 966 Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) { | 985 Condition MacroAssembler::CheckUInteger32ValidSmiValue(Register src) { |
| 967 // An unsigned 32-bit integer value is valid as long as the high bit | 986 // An unsigned 32-bit integer value is valid as long as the high bit |
| 968 // is not set. | 987 // is not set. |
| 969 testl(src, src); | 988 testl(src, src); |
| 970 return positive; | 989 return positive; |
| 971 } | 990 } |
| 972 | 991 |
| 973 | 992 |
| 993 void MacroAssembler::CheckSmiToIndicator(Register dst, Register src) { |
| 994 if (dst.is(src)) { |
| 995 andl(dst, Immediate(kSmiTagMask)); |
| 996 } else { |
| 997 movl(dst, Immediate(kSmiTagMask)); |
| 998 andl(dst, src); |
| 999 } |
| 1000 } |
| 1001 |
| 1002 |
| 1003 void MacroAssembler::CheckSmiToIndicator(Register dst, const Operand& src) { |
| 1004 if (!(src.AddressUsesRegister(dst))) { |
| 1005 movl(dst, Immediate(kSmiTagMask)); |
| 1006 andl(dst, src); |
| 1007 } else { |
| 1008 movl(dst, src); |
| 1009 andl(dst, Immediate(kSmiTagMask)); |
| 1010 } |
| 1011 } |
| 1012 |
| 1013 |
| 974 void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) { | 1014 void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) { |
| 975 if (constant->value() == 0) { | 1015 if (constant->value() == 0) { |
| 976 if (!dst.is(src)) { | 1016 if (!dst.is(src)) { |
| 977 movq(dst, src); | 1017 movq(dst, src); |
| 978 } | 1018 } |
| 979 return; | 1019 return; |
| 980 } else if (dst.is(src)) { | 1020 } else if (dst.is(src)) { |
| 981 ASSERT(!dst.is(kScratchRegister)); | 1021 ASSERT(!dst.is(kScratchRegister)); |
| 982 switch (constant->value()) { | 1022 switch (constant->value()) { |
| 983 case 1: | 1023 case 1: |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1278 } | 1318 } |
| 1279 | 1319 |
| 1280 | 1320 |
| 1281 void MacroAssembler::Move(Register dst, Register src) { | 1321 void MacroAssembler::Move(Register dst, Register src) { |
| 1282 if (!dst.is(src)) { | 1322 if (!dst.is(src)) { |
| 1283 movq(dst, src); | 1323 movq(dst, src); |
| 1284 } | 1324 } |
| 1285 } | 1325 } |
| 1286 | 1326 |
| 1287 | 1327 |
| 1288 | |
| 1289 | |
| 1290 void MacroAssembler::Move(Register dst, Handle<Object> source) { | 1328 void MacroAssembler::Move(Register dst, Handle<Object> source) { |
| 1291 ASSERT(!source->IsFailure()); | 1329 ASSERT(!source->IsFailure()); |
| 1292 if (source->IsSmi()) { | 1330 if (source->IsSmi()) { |
| 1293 Move(dst, Smi::cast(*source)); | 1331 Move(dst, Smi::cast(*source)); |
| 1294 } else { | 1332 } else { |
| 1295 movq(dst, source, RelocInfo::EMBEDDED_OBJECT); | 1333 movq(dst, source, RelocInfo::EMBEDDED_OBJECT); |
| 1296 } | 1334 } |
| 1297 } | 1335 } |
| 1298 | 1336 |
| 1299 | 1337 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1392 call(kScratchRegister); | 1430 call(kScratchRegister); |
| 1393 } | 1431 } |
| 1394 | 1432 |
| 1395 | 1433 |
| 1396 void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) { | 1434 void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) { |
| 1397 ASSERT(RelocInfo::IsCodeTarget(rmode)); | 1435 ASSERT(RelocInfo::IsCodeTarget(rmode)); |
| 1398 call(code_object, rmode); | 1436 call(code_object, rmode); |
| 1399 } | 1437 } |
| 1400 | 1438 |
| 1401 | 1439 |
| 1440 void MacroAssembler::Pushad() { |
| 1441 push(rax); |
| 1442 push(rcx); |
| 1443 push(rdx); |
| 1444 push(rbx); |
| 1445 // Not pushing rsp or rbp. |
| 1446 push(rsi); |
| 1447 push(rdi); |
| 1448 push(r8); |
| 1449 push(r9); |
| 1450 // r10 is kScratchRegister. |
| 1451 push(r11); |
| 1452 push(r12); |
| 1453 // r13 is kRootRegister. |
| 1454 push(r14); |
| 1455 // r15 is kSmiConstantRegister |
| 1456 STATIC_ASSERT(11 == kNumSafepointSavedRegisters); |
| 1457 // Use lea for symmetry with Popad. |
| 1458 lea(rsp, Operand(rsp, |
| 1459 -(kNumSafepointRegisters-kNumSafepointSavedRegisters) * kPointerSize)); |
| 1460 } |
| 1461 |
| 1462 |
| 1463 void MacroAssembler::Popad() { |
| 1464 // Popad must not change the flags, so use lea instead of addq. |
| 1465 lea(rsp, Operand(rsp, |
| 1466 (kNumSafepointRegisters-kNumSafepointSavedRegisters) * kPointerSize)); |
| 1467 pop(r14); |
| 1468 pop(r12); |
| 1469 pop(r11); |
| 1470 pop(r9); |
| 1471 pop(r8); |
| 1472 pop(rdi); |
| 1473 pop(rsi); |
| 1474 pop(rbx); |
| 1475 pop(rdx); |
| 1476 pop(rcx); |
| 1477 pop(rax); |
| 1478 } |
| 1479 |
| 1480 |
| 1481 void MacroAssembler::Dropad() { |
| 1482 addq(rsp, Immediate(kNumSafepointRegisters * kPointerSize)); |
| 1483 } |
| 1484 |
| 1485 |
| 1486 // Order general registers are pushed by Pushad: |
| 1487 // rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r12, r14. |
| 1488 int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = { |
| 1489 0, |
| 1490 1, |
| 1491 2, |
| 1492 3, |
| 1493 -1, |
| 1494 -1, |
| 1495 4, |
| 1496 5, |
| 1497 6, |
| 1498 7, |
| 1499 -1, |
| 1500 8, |
| 1501 9, |
| 1502 -1, |
| 1503 10, |
| 1504 -1 |
| 1505 }; |
| 1506 |
| 1507 |
| 1402 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 1508 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
| 1403 HandlerType type) { | 1509 HandlerType type) { |
| 1404 // Adjust this code if not the case. | 1510 // Adjust this code if not the case. |
| 1405 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 1511 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
| 1406 | 1512 |
| 1407 // The pc (return address) is already on TOS. This code pushes state, | 1513 // The pc (return address) is already on TOS. This code pushes state, |
| 1408 // frame pointer and current handler. Check that they are expected | 1514 // frame pointer and current handler. Check that they are expected |
| 1409 // next on the stack, in that order. | 1515 // next on the stack, in that order. |
| 1410 ASSERT_EQ(StackHandlerConstants::kStateOffset, | 1516 ASSERT_EQ(StackHandlerConstants::kStateOffset, |
| 1411 StackHandlerConstants::kPCOffset - kPointerSize); | 1517 StackHandlerConstants::kPCOffset - kPointerSize); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1440 void MacroAssembler::PopTryHandler() { | 1546 void MacroAssembler::PopTryHandler() { |
| 1441 ASSERT_EQ(0, StackHandlerConstants::kNextOffset); | 1547 ASSERT_EQ(0, StackHandlerConstants::kNextOffset); |
| 1442 // Unlink this handler. | 1548 // Unlink this handler. |
| 1443 movq(kScratchRegister, ExternalReference(Top::k_handler_address)); | 1549 movq(kScratchRegister, ExternalReference(Top::k_handler_address)); |
| 1444 pop(Operand(kScratchRegister, 0)); | 1550 pop(Operand(kScratchRegister, 0)); |
| 1445 // Remove the remaining fields. | 1551 // Remove the remaining fields. |
| 1446 addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); | 1552 addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); |
| 1447 } | 1553 } |
| 1448 | 1554 |
| 1449 | 1555 |
| 1556 void MacroAssembler::Throw(Register value) { |
| 1557 // Check that stack should contain next handler, frame pointer, state and |
| 1558 // return address in that order. |
| 1559 STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize == |
| 1560 StackHandlerConstants::kStateOffset); |
| 1561 STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize == |
| 1562 StackHandlerConstants::kPCOffset); |
| 1563 // Keep thrown value in rax. |
| 1564 if (!value.is(rax)) { |
| 1565 movq(rax, value); |
| 1566 } |
| 1567 |
| 1568 ExternalReference handler_address(Top::k_handler_address); |
| 1569 movq(kScratchRegister, handler_address); |
| 1570 movq(rsp, Operand(kScratchRegister, 0)); |
| 1571 // get next in chain |
| 1572 pop(rcx); |
| 1573 movq(Operand(kScratchRegister, 0), rcx); |
| 1574 pop(rbp); // pop frame pointer |
| 1575 pop(rdx); // remove state |
| 1576 |
| 1577 // Before returning we restore the context from the frame pointer if not NULL. |
| 1578 // The frame pointer is NULL in the exception handler of a JS entry frame. |
| 1579 Set(rsi, 0); // Tentatively set context pointer to NULL |
| 1580 NearLabel skip; |
| 1581 cmpq(rbp, Immediate(0)); |
| 1582 j(equal, &skip); |
| 1583 movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1584 bind(&skip); |
| 1585 ret(0); |
| 1586 } |
| 1587 |
| 1588 |
| 1589 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
| 1590 Register value) { |
| 1591 // Keep thrown value in rax. |
| 1592 if (!value.is(rax)) { |
| 1593 movq(rax, value); |
| 1594 } |
| 1595 // Fetch top stack handler. |
| 1596 ExternalReference handler_address(Top::k_handler_address); |
| 1597 movq(kScratchRegister, handler_address); |
| 1598 movq(rsp, Operand(kScratchRegister, 0)); |
| 1599 |
| 1600 // Unwind the handlers until the ENTRY handler is found. |
| 1601 NearLabel loop, done; |
| 1602 bind(&loop); |
| 1603 // Load the type of the current stack handler. |
| 1604 const int kStateOffset = StackHandlerConstants::kStateOffset; |
| 1605 cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY)); |
| 1606 j(equal, &done); |
| 1607 // Fetch the next handler in the list. |
| 1608 const int kNextOffset = StackHandlerConstants::kNextOffset; |
| 1609 movq(rsp, Operand(rsp, kNextOffset)); |
| 1610 jmp(&loop); |
| 1611 bind(&done); |
| 1612 |
| 1613 // Set the top handler address to next handler past the current ENTRY handler. |
| 1614 movq(kScratchRegister, handler_address); |
| 1615 pop(Operand(kScratchRegister, 0)); |
| 1616 |
| 1617 if (type == OUT_OF_MEMORY) { |
| 1618 // Set external caught exception to false. |
| 1619 ExternalReference external_caught(Top::k_external_caught_exception_address); |
| 1620 movq(rax, Immediate(false)); |
| 1621 store_rax(external_caught); |
| 1622 |
| 1623 // Set pending exception and rax to out of memory exception. |
| 1624 ExternalReference pending_exception(Top::k_pending_exception_address); |
| 1625 movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE); |
| 1626 store_rax(pending_exception); |
| 1627 } |
| 1628 |
| 1629 // Clear the context pointer. |
| 1630 Set(rsi, 0); |
| 1631 |
| 1632 // Restore registers from handler. |
| 1633 STATIC_ASSERT(StackHandlerConstants::kNextOffset + kPointerSize == |
| 1634 StackHandlerConstants::kFPOffset); |
| 1635 pop(rbp); // FP |
| 1636 STATIC_ASSERT(StackHandlerConstants::kFPOffset + kPointerSize == |
| 1637 StackHandlerConstants::kStateOffset); |
| 1638 pop(rdx); // State |
| 1639 |
| 1640 STATIC_ASSERT(StackHandlerConstants::kStateOffset + kPointerSize == |
| 1641 StackHandlerConstants::kPCOffset); |
| 1642 ret(0); |
| 1643 } |
| 1644 |
| 1645 |
| 1450 void MacroAssembler::Ret() { | 1646 void MacroAssembler::Ret() { |
| 1451 ret(0); | 1647 ret(0); |
| 1452 } | 1648 } |
| 1453 | 1649 |
| 1454 | 1650 |
| 1651 void MacroAssembler::Ret(int bytes_dropped, Register scratch) { |
| 1652 if (is_uint16(bytes_dropped)) { |
| 1653 ret(bytes_dropped); |
| 1654 } else { |
| 1655 pop(scratch); |
| 1656 addq(rsp, Immediate(bytes_dropped)); |
| 1657 push(scratch); |
| 1658 ret(0); |
| 1659 } |
| 1660 } |
| 1661 |
| 1662 |
| 1455 void MacroAssembler::FCmp() { | 1663 void MacroAssembler::FCmp() { |
| 1456 fucomip(); | 1664 fucomip(); |
| 1457 fstp(0); | 1665 fstp(0); |
| 1458 } | 1666 } |
| 1459 | 1667 |
| 1460 | 1668 |
| 1461 void MacroAssembler::CmpObjectType(Register heap_object, | 1669 void MacroAssembler::CmpObjectType(Register heap_object, |
| 1462 InstanceType type, | 1670 InstanceType type, |
| 1463 Register map) { | 1671 Register map) { |
| 1464 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset)); | 1672 movq(map, FieldOperand(heap_object, HeapObject::kMapOffset)); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 } | 1710 } |
| 1503 | 1711 |
| 1504 | 1712 |
| 1505 void MacroAssembler::AbortIfNotSmi(Register object) { | 1713 void MacroAssembler::AbortIfNotSmi(Register object) { |
| 1506 NearLabel ok; | 1714 NearLabel ok; |
| 1507 Condition is_smi = CheckSmi(object); | 1715 Condition is_smi = CheckSmi(object); |
| 1508 Assert(is_smi, "Operand is not a smi"); | 1716 Assert(is_smi, "Operand is not a smi"); |
| 1509 } | 1717 } |
| 1510 | 1718 |
| 1511 | 1719 |
| 1720 void MacroAssembler::AbortIfNotString(Register object) { |
| 1721 testb(object, Immediate(kSmiTagMask)); |
| 1722 Assert(not_equal, "Operand is not a string"); |
| 1723 push(object); |
| 1724 movq(object, FieldOperand(object, HeapObject::kMapOffset)); |
| 1725 CmpInstanceType(object, FIRST_NONSTRING_TYPE); |
| 1726 pop(object); |
| 1727 Assert(below, "Operand is not a string"); |
| 1728 } |
| 1729 |
| 1730 |
| 1512 void MacroAssembler::AbortIfNotRootValue(Register src, | 1731 void MacroAssembler::AbortIfNotRootValue(Register src, |
| 1513 Heap::RootListIndex root_value_index, | 1732 Heap::RootListIndex root_value_index, |
| 1514 const char* message) { | 1733 const char* message) { |
| 1515 ASSERT(!src.is(kScratchRegister)); | 1734 ASSERT(!src.is(kScratchRegister)); |
| 1516 LoadRoot(kScratchRegister, root_value_index); | 1735 LoadRoot(kScratchRegister, root_value_index); |
| 1517 cmpq(src, kScratchRegister); | 1736 cmpq(src, kScratchRegister); |
| 1518 Check(equal, message); | 1737 Check(equal, message); |
| 1519 } | 1738 } |
| 1520 | 1739 |
| 1521 | 1740 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1676 | 1895 |
| 1677 | 1896 |
| 1678 void MacroAssembler::InvokeFunction(JSFunction* function, | 1897 void MacroAssembler::InvokeFunction(JSFunction* function, |
| 1679 const ParameterCount& actual, | 1898 const ParameterCount& actual, |
| 1680 InvokeFlag flag) { | 1899 InvokeFlag flag) { |
| 1681 ASSERT(function->is_compiled()); | 1900 ASSERT(function->is_compiled()); |
| 1682 // Get the function and setup the context. | 1901 // Get the function and setup the context. |
| 1683 Move(rdi, Handle<JSFunction>(function)); | 1902 Move(rdi, Handle<JSFunction>(function)); |
| 1684 movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 1903 movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 1685 | 1904 |
| 1686 // Invoke the cached code. | 1905 if (V8::UseCrankshaft()) { |
| 1687 Handle<Code> code(function->code()); | 1906 // Since Crankshaft can recompile a function, we need to load |
| 1688 ParameterCount expected(function->shared()->formal_parameter_count()); | 1907 // the Code object every time we call the function. |
| 1689 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag); | 1908 movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 1909 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 1910 InvokeCode(rdx, expected, actual, flag); |
| 1911 } else { |
| 1912 // Invoke the cached code. |
| 1913 Handle<Code> code(function->code()); |
| 1914 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 1915 InvokeCode(code, expected, actual, RelocInfo::CODE_TARGET, flag); |
| 1916 } |
| 1690 } | 1917 } |
| 1691 | 1918 |
| 1692 | 1919 |
| 1693 void MacroAssembler::EnterFrame(StackFrame::Type type) { | 1920 void MacroAssembler::EnterFrame(StackFrame::Type type) { |
| 1694 push(rbp); | 1921 push(rbp); |
| 1695 movq(rbp, rsp); | 1922 movq(rbp, rsp); |
| 1696 push(rsi); // Context. | 1923 push(rsi); // Context. |
| 1697 Push(Smi::FromInt(type)); | 1924 Push(Smi::FromInt(type)); |
| 1698 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); | 1925 movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT); |
| 1699 push(kScratchRegister); | 1926 push(kScratchRegister); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1740 movq(r14, rax); // Backup rax before we use it. | 1967 movq(r14, rax); // Backup rax before we use it. |
| 1741 } | 1968 } |
| 1742 | 1969 |
| 1743 movq(rax, rbp); | 1970 movq(rax, rbp); |
| 1744 store_rax(c_entry_fp_address); | 1971 store_rax(c_entry_fp_address); |
| 1745 movq(rax, rsi); | 1972 movq(rax, rsi); |
| 1746 store_rax(context_address); | 1973 store_rax(context_address); |
| 1747 } | 1974 } |
| 1748 | 1975 |
| 1749 | 1976 |
| 1750 void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space) { | 1977 void MacroAssembler::EnterExitFrameEpilogue(int arg_stack_space, |
| 1978 bool save_doubles) { |
| 1751 #ifdef _WIN64 | 1979 #ifdef _WIN64 |
| 1752 const int kShaddowSpace = 4; | 1980 const int kShadowSpace = 4; |
| 1753 arg_stack_space += kShaddowSpace; | 1981 arg_stack_space += kShadowSpace; |
| 1754 #endif | 1982 #endif |
| 1755 if (arg_stack_space > 0) { | 1983 // Optionally save all XMM registers. |
| 1984 if (save_doubles) { |
| 1985 CpuFeatures::Scope scope(SSE2); |
| 1986 int space = XMMRegister::kNumRegisters * kDoubleSize + |
| 1987 arg_stack_space * kPointerSize; |
| 1988 subq(rsp, Immediate(space)); |
| 1989 int offset = -2 * kPointerSize; |
| 1990 for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) { |
| 1991 XMMRegister reg = XMMRegister::FromAllocationIndex(i); |
| 1992 movsd(Operand(rbp, offset - ((i + 1) * kDoubleSize)), reg); |
| 1993 } |
| 1994 } else if (arg_stack_space > 0) { |
| 1756 subq(rsp, Immediate(arg_stack_space * kPointerSize)); | 1995 subq(rsp, Immediate(arg_stack_space * kPointerSize)); |
| 1757 } | 1996 } |
| 1758 | 1997 |
| 1759 // Get the required frame alignment for the OS. | 1998 // Get the required frame alignment for the OS. |
| 1760 static const int kFrameAlignment = OS::ActivationFrameAlignment(); | 1999 static const int kFrameAlignment = OS::ActivationFrameAlignment(); |
| 1761 if (kFrameAlignment > 0) { | 2000 if (kFrameAlignment > 0) { |
| 1762 ASSERT(IsPowerOf2(kFrameAlignment)); | 2001 ASSERT(IsPowerOf2(kFrameAlignment)); |
| 1763 movq(kScratchRegister, Immediate(-kFrameAlignment)); | 2002 movq(kScratchRegister, Immediate(-kFrameAlignment)); |
| 1764 and_(rsp, kScratchRegister); | 2003 and_(rsp, kScratchRegister); |
| 1765 } | 2004 } |
| 1766 | 2005 |
| 1767 // Patch the saved entry sp. | 2006 // Patch the saved entry sp. |
| 1768 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp); | 2007 movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp); |
| 1769 } | 2008 } |
| 1770 | 2009 |
| 1771 | 2010 |
| 1772 void MacroAssembler::EnterExitFrame(int arg_stack_space) { | 2011 void MacroAssembler::EnterExitFrame(int arg_stack_space, bool save_doubles) { |
| 1773 EnterExitFramePrologue(true); | 2012 EnterExitFramePrologue(true); |
| 1774 | 2013 |
| 1775 // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, | 2014 // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, |
| 1776 // so it must be retained across the C-call. | 2015 // so it must be retained across the C-call. |
| 1777 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; | 2016 int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; |
| 1778 lea(r12, Operand(rbp, r14, times_pointer_size, offset)); | 2017 lea(r12, Operand(rbp, r14, times_pointer_size, offset)); |
| 1779 | 2018 |
| 1780 EnterExitFrameEpilogue(arg_stack_space); | 2019 EnterExitFrameEpilogue(arg_stack_space, save_doubles); |
| 1781 } | 2020 } |
| 1782 | 2021 |
| 1783 | 2022 |
| 1784 void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { | 2023 void MacroAssembler::EnterApiExitFrame(int arg_stack_space) { |
| 1785 EnterExitFramePrologue(false); | 2024 EnterExitFramePrologue(false); |
| 1786 EnterExitFrameEpilogue(arg_stack_space); | 2025 EnterExitFrameEpilogue(arg_stack_space, false); |
| 1787 } | 2026 } |
| 1788 | 2027 |
| 1789 | 2028 |
| 1790 void MacroAssembler::LeaveExitFrame() { | 2029 void MacroAssembler::LeaveExitFrame(bool save_doubles) { |
| 1791 // Registers: | 2030 // Registers: |
| 1792 // r12 : argv | 2031 // r12 : argv |
| 1793 | 2032 if (save_doubles) { |
| 2033 int offset = -2 * kPointerSize; |
| 2034 for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) { |
| 2035 XMMRegister reg = XMMRegister::FromAllocationIndex(i); |
| 2036 movsd(reg, Operand(rbp, offset - ((i + 1) * kDoubleSize))); |
| 2037 } |
| 2038 } |
| 1794 // Get the return address from the stack and restore the frame pointer. | 2039 // Get the return address from the stack and restore the frame pointer. |
| 1795 movq(rcx, Operand(rbp, 1 * kPointerSize)); | 2040 movq(rcx, Operand(rbp, 1 * kPointerSize)); |
| 1796 movq(rbp, Operand(rbp, 0 * kPointerSize)); | 2041 movq(rbp, Operand(rbp, 0 * kPointerSize)); |
| 1797 | 2042 |
| 1798 // Pop everything up to and including the arguments and the receiver | 2043 // Drop everything up to and including the arguments and the receiver |
| 1799 // from the caller stack. | 2044 // from the caller stack. |
| 1800 lea(rsp, Operand(r12, 1 * kPointerSize)); | 2045 lea(rsp, Operand(r12, 1 * kPointerSize)); |
| 1801 | 2046 |
| 1802 // Push the return address to get ready to return. | 2047 // Push the return address to get ready to return. |
| 1803 push(rcx); | 2048 push(rcx); |
| 1804 | 2049 |
| 1805 LeaveExitFrameEpilogue(); | 2050 LeaveExitFrameEpilogue(); |
| 1806 } | 2051 } |
| 1807 | 2052 |
| 1808 | 2053 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1976 | 2221 |
| 1977 // Load address of new object into result. | 2222 // Load address of new object into result. |
| 1978 LoadAllocationTopHelper(result, scratch, flags); | 2223 LoadAllocationTopHelper(result, scratch, flags); |
| 1979 | 2224 |
| 1980 // Calculate new top and bail out if new space is exhausted. | 2225 // Calculate new top and bail out if new space is exhausted. |
| 1981 ExternalReference new_space_allocation_limit = | 2226 ExternalReference new_space_allocation_limit = |
| 1982 ExternalReference::new_space_allocation_limit_address(); | 2227 ExternalReference::new_space_allocation_limit_address(); |
| 1983 | 2228 |
| 1984 Register top_reg = result_end.is_valid() ? result_end : result; | 2229 Register top_reg = result_end.is_valid() ? result_end : result; |
| 1985 | 2230 |
| 1986 if (top_reg.is(result)) { | 2231 if (!top_reg.is(result)) { |
| 1987 addq(top_reg, Immediate(object_size)); | 2232 movq(top_reg, result); |
| 1988 } else { | |
| 1989 lea(top_reg, Operand(result, object_size)); | |
| 1990 } | 2233 } |
| 2234 addq(top_reg, Immediate(object_size)); |
| 2235 j(carry, gc_required); |
| 1991 movq(kScratchRegister, new_space_allocation_limit); | 2236 movq(kScratchRegister, new_space_allocation_limit); |
| 1992 cmpq(top_reg, Operand(kScratchRegister, 0)); | 2237 cmpq(top_reg, Operand(kScratchRegister, 0)); |
| 1993 j(above, gc_required); | 2238 j(above, gc_required); |
| 1994 | 2239 |
| 1995 // Update allocation top. | 2240 // Update allocation top. |
| 1996 UpdateAllocationTopHelper(top_reg, scratch); | 2241 UpdateAllocationTopHelper(top_reg, scratch); |
| 1997 | 2242 |
| 1998 if (top_reg.is(result)) { | 2243 if (top_reg.is(result)) { |
| 1999 if ((flags & TAG_OBJECT) != 0) { | 2244 if ((flags & TAG_OBJECT) != 0) { |
| 2000 subq(result, Immediate(object_size - kHeapObjectTag)); | 2245 subq(result, Immediate(object_size - kHeapObjectTag)); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2030 return; | 2275 return; |
| 2031 } | 2276 } |
| 2032 ASSERT(!result.is(result_end)); | 2277 ASSERT(!result.is(result_end)); |
| 2033 | 2278 |
| 2034 // Load address of new object into result. | 2279 // Load address of new object into result. |
| 2035 LoadAllocationTopHelper(result, scratch, flags); | 2280 LoadAllocationTopHelper(result, scratch, flags); |
| 2036 | 2281 |
| 2037 // Calculate new top and bail out if new space is exhausted. | 2282 // Calculate new top and bail out if new space is exhausted. |
| 2038 ExternalReference new_space_allocation_limit = | 2283 ExternalReference new_space_allocation_limit = |
| 2039 ExternalReference::new_space_allocation_limit_address(); | 2284 ExternalReference::new_space_allocation_limit_address(); |
| 2040 lea(result_end, Operand(result, element_count, element_size, header_size)); | 2285 |
| 2286 // We assume that element_count*element_size + header_size does not |
| 2287 // overflow. |
| 2288 lea(result_end, Operand(element_count, element_size, header_size)); |
| 2289 addq(result_end, result); |
| 2290 j(carry, gc_required); |
| 2041 movq(kScratchRegister, new_space_allocation_limit); | 2291 movq(kScratchRegister, new_space_allocation_limit); |
| 2042 cmpq(result_end, Operand(kScratchRegister, 0)); | 2292 cmpq(result_end, Operand(kScratchRegister, 0)); |
| 2043 j(above, gc_required); | 2293 j(above, gc_required); |
| 2044 | 2294 |
| 2045 // Update allocation top. | 2295 // Update allocation top. |
| 2046 UpdateAllocationTopHelper(result_end, scratch); | 2296 UpdateAllocationTopHelper(result_end, scratch); |
| 2047 | 2297 |
| 2048 // Tag the result if requested. | 2298 // Tag the result if requested. |
| 2049 if ((flags & TAG_OBJECT) != 0) { | 2299 if ((flags & TAG_OBJECT) != 0) { |
| 2050 addq(result, Immediate(kHeapObjectTag)); | 2300 addq(result, Immediate(kHeapObjectTag)); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2076 // Load address of new object into result. | 2326 // Load address of new object into result. |
| 2077 LoadAllocationTopHelper(result, scratch, flags); | 2327 LoadAllocationTopHelper(result, scratch, flags); |
| 2078 | 2328 |
| 2079 // Calculate new top and bail out if new space is exhausted. | 2329 // Calculate new top and bail out if new space is exhausted. |
| 2080 ExternalReference new_space_allocation_limit = | 2330 ExternalReference new_space_allocation_limit = |
| 2081 ExternalReference::new_space_allocation_limit_address(); | 2331 ExternalReference::new_space_allocation_limit_address(); |
| 2082 if (!object_size.is(result_end)) { | 2332 if (!object_size.is(result_end)) { |
| 2083 movq(result_end, object_size); | 2333 movq(result_end, object_size); |
| 2084 } | 2334 } |
| 2085 addq(result_end, result); | 2335 addq(result_end, result); |
| 2336 j(carry, gc_required); |
| 2086 movq(kScratchRegister, new_space_allocation_limit); | 2337 movq(kScratchRegister, new_space_allocation_limit); |
| 2087 cmpq(result_end, Operand(kScratchRegister, 0)); | 2338 cmpq(result_end, Operand(kScratchRegister, 0)); |
| 2088 j(above, gc_required); | 2339 j(above, gc_required); |
| 2089 | 2340 |
| 2090 // Update allocation top. | 2341 // Update allocation top. |
| 2091 UpdateAllocationTopHelper(result_end, scratch); | 2342 UpdateAllocationTopHelper(result_end, scratch); |
| 2092 | 2343 |
| 2093 // Tag the result if requested. | 2344 // Tag the result if requested. |
| 2094 if ((flags & TAG_OBJECT) != 0) { | 2345 if ((flags & TAG_OBJECT) != 0) { |
| 2095 addq(result, Immediate(kHeapObjectTag)); | 2346 addq(result, Immediate(kHeapObjectTag)); |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2357 CPU::FlushICache(address_, size_); | 2608 CPU::FlushICache(address_, size_); |
| 2358 | 2609 |
| 2359 // Check that the code was patched as expected. | 2610 // Check that the code was patched as expected. |
| 2360 ASSERT(masm_.pc_ == address_ + size_); | 2611 ASSERT(masm_.pc_ == address_ + size_); |
| 2361 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2612 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 2362 } | 2613 } |
| 2363 | 2614 |
| 2364 } } // namespace v8::internal | 2615 } } // namespace v8::internal |
| 2365 | 2616 |
| 2366 #endif // V8_TARGET_ARCH_X64 | 2617 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |