| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 | 478 |
| 479 void MacroAssembler::PopSafepointRegistersAndDoubles() { | 479 void MacroAssembler::PopSafepointRegistersAndDoubles() { |
| 480 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) { | 480 for (int i = 0; i < DwVfpRegister::kNumAllocatableRegisters; i++) { |
| 481 vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize); | 481 vldr(DwVfpRegister::FromAllocationIndex(i), sp, i * kDoubleSize); |
| 482 } | 482 } |
| 483 add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters * | 483 add(sp, sp, Operand(DwVfpRegister::kNumAllocatableRegisters * |
| 484 kDoubleSize)); | 484 kDoubleSize)); |
| 485 PopSafepointRegisters(); | 485 PopSafepointRegisters(); |
| 486 } | 486 } |
| 487 | 487 |
| 488 void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register reg) { |
| 489 str(reg, SafepointRegistersAndDoublesSlot(reg)); |
| 490 } |
| 491 |
| 492 |
| 488 void MacroAssembler::StoreToSafepointRegisterSlot(Register reg) { | 493 void MacroAssembler::StoreToSafepointRegisterSlot(Register reg) { |
| 489 str(reg, SafepointRegisterSlot(reg)); | 494 str(reg, SafepointRegisterSlot(reg)); |
| 490 } | 495 } |
| 491 | 496 |
| 492 | 497 |
| 498 void MacroAssembler::LoadFromSafepointRegisterSlot(Register reg) { |
| 499 ldr(reg, SafepointRegisterSlot(reg)); |
| 500 } |
| 501 |
| 502 |
| 493 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { | 503 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { |
| 494 // The registers are pushed starting with the highest encoding, | 504 // The registers are pushed starting with the highest encoding, |
| 495 // which means that lowest encodings are closest to the stack pointer. | 505 // which means that lowest encodings are closest to the stack pointer. |
| 496 ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters); | 506 ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters); |
| 497 return reg_code; | 507 return reg_code; |
| 498 } | 508 } |
| 499 | 509 |
| 500 | 510 |
| 501 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { | 511 MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { |
| 502 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); | 512 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); |
| 503 } | 513 } |
| 504 | 514 |
| 505 | 515 |
| 516 MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { |
| 517 // General purpose registers are pushed last on the stack. |
| 518 int doubles_size = DwVfpRegister::kNumAllocatableRegisters * kDoubleSize; |
| 519 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; |
| 520 return MemOperand(sp, doubles_size + register_offset); |
| 521 } |
| 522 |
| 523 |
| 506 void MacroAssembler::Ldrd(Register dst1, Register dst2, | 524 void MacroAssembler::Ldrd(Register dst1, Register dst2, |
| 507 const MemOperand& src, Condition cond) { | 525 const MemOperand& src, Condition cond) { |
| 508 ASSERT(src.rm().is(no_reg)); | 526 ASSERT(src.rm().is(no_reg)); |
| 509 ASSERT(!dst1.is(lr)); // r14. | 527 ASSERT(!dst1.is(lr)); // r14. |
| 510 ASSERT_EQ(0, dst1.code() % 2); | 528 ASSERT_EQ(0, dst1.code() % 2); |
| 511 ASSERT_EQ(dst1.code() + 1, dst2.code()); | 529 ASSERT_EQ(dst1.code() + 1, dst2.code()); |
| 512 | 530 |
| 513 // Generate two ldr instructions if ldrd is not available. | 531 // Generate two ldr instructions if ldrd is not available. |
| 514 if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) { | 532 if (Isolate::Current()->cpu_features()->IsSupported(ARMv7)) { |
| 515 CpuFeatures::Scope scope(ARMv7); | 533 CpuFeatures::Scope scope(ARMv7); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 // r1: preserved | 625 // r1: preserved |
| 608 // r2: preserved | 626 // r2: preserved |
| 609 | 627 |
| 610 // Drop the execution stack down to the frame pointer and restore | 628 // Drop the execution stack down to the frame pointer and restore |
| 611 // the caller frame pointer and return address. | 629 // the caller frame pointer and return address. |
| 612 mov(sp, fp); | 630 mov(sp, fp); |
| 613 ldm(ia_w, sp, fp.bit() | lr.bit()); | 631 ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 614 } | 632 } |
| 615 | 633 |
| 616 | 634 |
| 617 void MacroAssembler::EnterExitFrame(bool save_doubles) { | 635 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) { |
| 618 // Compute the argv pointer in a callee-saved register. | |
| 619 add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); | |
| 620 sub(r6, r6, Operand(kPointerSize)); | |
| 621 | |
| 622 // Setup the frame structure on the stack. | 636 // Setup the frame structure on the stack. |
| 623 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); | 637 ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement); |
| 624 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); | 638 ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset); |
| 625 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); | 639 ASSERT_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset); |
| 626 Push(lr, fp); | 640 Push(lr, fp); |
| 627 mov(fp, Operand(sp)); // Setup new frame pointer. | 641 mov(fp, Operand(sp)); // Setup new frame pointer. |
| 628 // Reserve room for saved entry sp and code object. | 642 // Reserve room for saved entry sp and code object. |
| 629 sub(sp, sp, Operand(2 * kPointerSize)); | 643 sub(sp, sp, Operand(2 * kPointerSize)); |
| 630 if (FLAG_debug_code) { | 644 if (FLAG_debug_code) { |
| 631 mov(ip, Operand(0)); | 645 mov(ip, Operand(0)); |
| 632 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 646 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 633 } | 647 } |
| 634 mov(ip, Operand(CodeObject())); | 648 mov(ip, Operand(CodeObject())); |
| 635 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); | 649 str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset)); |
| 636 | 650 |
| 637 // Save the frame pointer and the context in top. | 651 // Save the frame pointer and the context in top. |
| 638 mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address))); | 652 mov(ip, Operand(ExternalReference(Isolate::k_c_entry_fp_address))); |
| 639 str(fp, MemOperand(ip)); | 653 str(fp, MemOperand(ip)); |
| 640 mov(ip, Operand(ExternalReference(Isolate::k_context_address))); | 654 mov(ip, Operand(ExternalReference(Isolate::k_context_address))); |
| 641 str(cp, MemOperand(ip)); | 655 str(cp, MemOperand(ip)); |
| 642 | 656 |
| 643 // Setup argc and the builtin function in callee-saved registers. | |
| 644 mov(r4, Operand(r0)); | |
| 645 mov(r5, Operand(r1)); | |
| 646 | |
| 647 // Optionally save all double registers. | 657 // Optionally save all double registers. |
| 648 if (save_doubles) { | 658 if (save_doubles) { |
| 649 sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize)); | 659 sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize)); |
| 650 const int offset = -2 * kPointerSize; | 660 const int offset = -2 * kPointerSize; |
| 651 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { | 661 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { |
| 652 DwVfpRegister reg = DwVfpRegister::from_code(i); | 662 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 653 vstr(reg, fp, offset - ((i + 1) * kDoubleSize)); | 663 vstr(reg, fp, offset - ((i + 1) * kDoubleSize)); |
| 654 } | 664 } |
| 655 // Note that d0 will be accessible at | 665 // Note that d0 will be accessible at |
| 656 // fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize, | 666 // fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize, |
| 657 // since the sp slot and code slot were pushed after the fp. | 667 // since the sp slot and code slot were pushed after the fp. |
| 658 } | 668 } |
| 659 | 669 |
| 660 // Reserve place for the return address and align the frame preparing for | 670 // Reserve place for the return address and stack space and align the frame |
| 661 // calling the runtime function. | 671 // preparing for calling the runtime function. |
| 662 const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); | 672 const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); |
| 663 sub(sp, sp, Operand(kPointerSize)); | 673 sub(sp, sp, Operand((stack_space + 1) * kPointerSize)); |
| 664 if (frame_alignment > 0) { | 674 if (frame_alignment > 0) { |
| 665 ASSERT(IsPowerOf2(frame_alignment)); | 675 ASSERT(IsPowerOf2(frame_alignment)); |
| 666 and_(sp, sp, Operand(-frame_alignment)); | 676 and_(sp, sp, Operand(-frame_alignment)); |
| 667 } | 677 } |
| 668 | 678 |
| 669 // Set the exit frame sp value to point just before the return address | 679 // Set the exit frame sp value to point just before the return address |
| 670 // location. | 680 // location. |
| 671 add(ip, sp, Operand(kPointerSize)); | 681 add(ip, sp, Operand(kPointerSize)); |
| 672 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 682 str(ip, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 673 } | 683 } |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1134 ldr(ip, MemOperand(topaddr)); | 1144 ldr(ip, MemOperand(topaddr)); |
| 1135 cmp(result, ip); | 1145 cmp(result, ip); |
| 1136 Check(eq, "Unexpected allocation top"); | 1146 Check(eq, "Unexpected allocation top"); |
| 1137 } | 1147 } |
| 1138 // Load allocation limit into ip. Result already contains allocation top. | 1148 // Load allocation limit into ip. Result already contains allocation top. |
| 1139 ldr(ip, MemOperand(topaddr, limit - top)); | 1149 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1140 } | 1150 } |
| 1141 | 1151 |
| 1142 // Calculate new top and bail out if new space is exhausted. Use result | 1152 // Calculate new top and bail out if new space is exhausted. Use result |
| 1143 // to calculate the new top. | 1153 // to calculate the new top. |
| 1144 add(scratch2, result, Operand(obj_size_reg)); | 1154 add(scratch2, result, Operand(obj_size_reg), SetCC); |
| 1155 b(cs, gc_required); |
| 1145 cmp(scratch2, Operand(ip)); | 1156 cmp(scratch2, Operand(ip)); |
| 1146 b(hi, gc_required); | 1157 b(hi, gc_required); |
| 1147 str(scratch2, MemOperand(topaddr)); | 1158 str(scratch2, MemOperand(topaddr)); |
| 1148 | 1159 |
| 1149 // Tag object if requested. | 1160 // Tag object if requested. |
| 1150 if ((flags & TAG_OBJECT) != 0) { | 1161 if ((flags & TAG_OBJECT) != 0) { |
| 1151 add(result, result, Operand(kHeapObjectTag)); | 1162 add(result, result, Operand(kHeapObjectTag)); |
| 1152 } | 1163 } |
| 1153 } | 1164 } |
| 1154 | 1165 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 Check(eq, "Unexpected allocation top"); | 1224 Check(eq, "Unexpected allocation top"); |
| 1214 } | 1225 } |
| 1215 // Load allocation limit into ip. Result already contains allocation top. | 1226 // Load allocation limit into ip. Result already contains allocation top. |
| 1216 ldr(ip, MemOperand(topaddr, limit - top)); | 1227 ldr(ip, MemOperand(topaddr, limit - top)); |
| 1217 } | 1228 } |
| 1218 | 1229 |
| 1219 // Calculate new top and bail out if new space is exhausted. Use result | 1230 // Calculate new top and bail out if new space is exhausted. Use result |
| 1220 // to calculate the new top. Object size may be in words so a shift is | 1231 // to calculate the new top. Object size may be in words so a shift is |
| 1221 // required to get the number of bytes. | 1232 // required to get the number of bytes. |
| 1222 if ((flags & SIZE_IN_WORDS) != 0) { | 1233 if ((flags & SIZE_IN_WORDS) != 0) { |
| 1223 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2)); | 1234 add(scratch2, result, Operand(object_size, LSL, kPointerSizeLog2), SetCC); |
| 1224 } else { | 1235 } else { |
| 1225 add(scratch2, result, Operand(object_size)); | 1236 add(scratch2, result, Operand(object_size), SetCC); |
| 1226 } | 1237 } |
| 1238 b(cs, gc_required); |
| 1227 cmp(scratch2, Operand(ip)); | 1239 cmp(scratch2, Operand(ip)); |
| 1228 b(hi, gc_required); | 1240 b(hi, gc_required); |
| 1229 | 1241 |
| 1230 // Update allocation top. result temporarily holds the new top. | 1242 // Update allocation top. result temporarily holds the new top. |
| 1231 if (FLAG_debug_code) { | 1243 if (FLAG_debug_code) { |
| 1232 tst(scratch2, Operand(kObjectAlignmentMask)); | 1244 tst(scratch2, Operand(kObjectAlignmentMask)); |
| 1233 Check(eq, "Unaligned allocation in new space"); | 1245 Check(eq, "Unaligned allocation in new space"); |
| 1234 } | 1246 } |
| 1235 str(scratch2, MemOperand(topaddr)); | 1247 str(scratch2, MemOperand(topaddr)); |
| 1236 | 1248 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 // in initial map. | 1463 // in initial map. |
| 1452 bind(&non_instance); | 1464 bind(&non_instance); |
| 1453 ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); | 1465 ldr(result, FieldMemOperand(result, Map::kConstructorOffset)); |
| 1454 | 1466 |
| 1455 // All done. | 1467 // All done. |
| 1456 bind(&done); | 1468 bind(&done); |
| 1457 } | 1469 } |
| 1458 | 1470 |
| 1459 | 1471 |
| 1460 void MacroAssembler::CallStub(CodeStub* stub, Condition cond) { | 1472 void MacroAssembler::CallStub(CodeStub* stub, Condition cond) { |
| 1461 ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs | 1473 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. |
| 1462 Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond); | 1474 Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond); |
| 1463 } | 1475 } |
| 1464 | 1476 |
| 1465 | 1477 |
| 1466 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { | 1478 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) { |
| 1467 ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs | 1479 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. |
| 1468 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); | 1480 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); |
| 1469 } | 1481 } |
| 1470 | 1482 |
| 1471 | 1483 |
| 1484 MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, Condition cond) { |
| 1485 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. |
| 1486 Object* result; |
| 1487 { MaybeObject* maybe_result = stub->TryGetCode(); |
| 1488 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 1489 } |
| 1490 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond); |
| 1491 return result; |
| 1492 } |
| 1493 |
| 1494 |
| 1495 static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { |
| 1496 return ref0.address() - ref1.address(); |
| 1497 } |
| 1498 |
| 1499 |
| 1500 MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( |
| 1501 ApiFunction* function, int stack_space) { |
| 1502 ExternalReference next_address = |
| 1503 ExternalReference::handle_scope_next_address(); |
| 1504 const int kNextOffset = 0; |
| 1505 const int kLimitOffset = AddressOffset( |
| 1506 ExternalReference::handle_scope_limit_address(), |
| 1507 next_address); |
| 1508 const int kLevelOffset = AddressOffset( |
| 1509 ExternalReference::handle_scope_level_address(), |
| 1510 next_address); |
| 1511 |
| 1512 // Allocate HandleScope in callee-save registers. |
| 1513 mov(r7, Operand(next_address)); |
| 1514 ldr(r4, MemOperand(r7, kNextOffset)); |
| 1515 ldr(r5, MemOperand(r7, kLimitOffset)); |
| 1516 ldr(r6, MemOperand(r7, kLevelOffset)); |
| 1517 add(r6, r6, Operand(1)); |
| 1518 str(r6, MemOperand(r7, kLevelOffset)); |
| 1519 |
| 1520 // Native call returns to the DirectCEntry stub which redirects to the |
| 1521 // return address pushed on stack (could have moved after GC). |
| 1522 // DirectCEntry stub itself is generated early and never moves. |
| 1523 DirectCEntryStub stub; |
| 1524 stub.GenerateCall(this, function); |
| 1525 |
| 1526 Label promote_scheduled_exception; |
| 1527 Label delete_allocated_handles; |
| 1528 Label leave_exit_frame; |
| 1529 |
| 1530 // If result is non-zero, dereference to get the result value |
| 1531 // otherwise set it to undefined. |
| 1532 cmp(r0, Operand(0)); |
| 1533 LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); |
| 1534 ldr(r0, MemOperand(r0), ne); |
| 1535 |
| 1536 // No more valid handles (the result handle was the last one). Restore |
| 1537 // previous handle scope. |
| 1538 str(r4, MemOperand(r7, kNextOffset)); |
| 1539 if (FLAG_debug_code) { |
| 1540 ldr(r1, MemOperand(r7, kLevelOffset)); |
| 1541 cmp(r1, r6); |
| 1542 Check(eq, "Unexpected level after return from api call"); |
| 1543 } |
| 1544 sub(r6, r6, Operand(1)); |
| 1545 str(r6, MemOperand(r7, kLevelOffset)); |
| 1546 ldr(ip, MemOperand(r7, kLimitOffset)); |
| 1547 cmp(r5, ip); |
| 1548 b(ne, &delete_allocated_handles); |
| 1549 |
| 1550 // Check if the function scheduled an exception. |
| 1551 bind(&leave_exit_frame); |
| 1552 LoadRoot(r4, Heap::kTheHoleValueRootIndex); |
| 1553 mov(ip, Operand(ExternalReference::scheduled_exception_address())); |
| 1554 ldr(r5, MemOperand(ip)); |
| 1555 cmp(r4, r5); |
| 1556 b(ne, &promote_scheduled_exception); |
| 1557 |
| 1558 // LeaveExitFrame expects unwind space to be in r4. |
| 1559 mov(r4, Operand(stack_space)); |
| 1560 LeaveExitFrame(false); |
| 1561 |
| 1562 bind(&promote_scheduled_exception); |
| 1563 MaybeObject* result = TryTailCallExternalReference( |
| 1564 ExternalReference(Runtime::kPromoteScheduledException), 0, 1); |
| 1565 if (result->IsFailure()) { |
| 1566 return result; |
| 1567 } |
| 1568 |
| 1569 // HandleScope limit has changed. Delete allocated extensions. |
| 1570 bind(&delete_allocated_handles); |
| 1571 str(r5, MemOperand(r7, kLimitOffset)); |
| 1572 mov(r4, r0); |
| 1573 PrepareCallCFunction(0, r5); |
| 1574 CallCFunction(ExternalReference::delete_handle_scope_extensions(), 0); |
| 1575 mov(r0, r4); |
| 1576 jmp(&leave_exit_frame); |
| 1577 |
| 1578 return result; |
| 1579 } |
| 1580 |
| 1581 |
| 1472 void MacroAssembler::IllegalOperation(int num_arguments) { | 1582 void MacroAssembler::IllegalOperation(int num_arguments) { |
| 1473 if (num_arguments > 0) { | 1583 if (num_arguments > 0) { |
| 1474 add(sp, sp, Operand(num_arguments * kPointerSize)); | 1584 add(sp, sp, Operand(num_arguments * kPointerSize)); |
| 1475 } | 1585 } |
| 1476 LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 1586 LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 1477 } | 1587 } |
| 1478 | 1588 |
| 1479 | 1589 |
| 1480 void MacroAssembler::IndexFromHash(Register hash, Register index) { | 1590 void MacroAssembler::IndexFromHash(Register hash, Register index) { |
| 1481 // If the hash field contains an array index pick it out. The assert checks | 1591 // If the hash field contains an array index pick it out. The assert checks |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1553 } | 1663 } |
| 1554 | 1664 |
| 1555 | 1665 |
| 1556 // Tries to get a signed int32 out of a double precision floating point heap | 1666 // Tries to get a signed int32 out of a double precision floating point heap |
| 1557 // number. Rounds towards 0. Branch to 'not_int32' if the double is out of the | 1667 // number. Rounds towards 0. Branch to 'not_int32' if the double is out of the |
| 1558 // 32bits signed integer range. | 1668 // 32bits signed integer range. |
| 1559 void MacroAssembler::ConvertToInt32(Register source, | 1669 void MacroAssembler::ConvertToInt32(Register source, |
| 1560 Register dest, | 1670 Register dest, |
| 1561 Register scratch, | 1671 Register scratch, |
| 1562 Register scratch2, | 1672 Register scratch2, |
| 1673 DwVfpRegister double_scratch, |
| 1563 Label *not_int32) { | 1674 Label *not_int32) { |
| 1564 if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) { | 1675 if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) { |
| 1565 CpuFeatures::Scope scope(VFP3); | 1676 CpuFeatures::Scope scope(VFP3); |
| 1566 sub(scratch, source, Operand(kHeapObjectTag)); | 1677 sub(scratch, source, Operand(kHeapObjectTag)); |
| 1567 vldr(d0, scratch, HeapNumber::kValueOffset); | 1678 vldr(double_scratch, scratch, HeapNumber::kValueOffset); |
| 1568 vcvt_s32_f64(s0, d0); | 1679 vcvt_s32_f64(double_scratch.low(), double_scratch); |
| 1569 vmov(dest, s0); | 1680 vmov(dest, double_scratch.low()); |
| 1570 // Signed vcvt instruction will saturate to the minimum (0x80000000) or | 1681 // Signed vcvt instruction will saturate to the minimum (0x80000000) or |
| 1571 // maximun (0x7fffffff) signed 32bits integer when the double is out of | 1682 // maximun (0x7fffffff) signed 32bits integer when the double is out of |
| 1572 // range. When substracting one, the minimum signed integer becomes the | 1683 // range. When substracting one, the minimum signed integer becomes the |
| 1573 // maximun signed integer. | 1684 // maximun signed integer. |
| 1574 sub(scratch, dest, Operand(1)); | 1685 sub(scratch, dest, Operand(1)); |
| 1575 cmp(scratch, Operand(LONG_MAX - 1)); | 1686 cmp(scratch, Operand(LONG_MAX - 1)); |
| 1576 // If equal then dest was LONG_MAX, if greater dest was LONG_MIN. | 1687 // If equal then dest was LONG_MAX, if greater dest was LONG_MIN. |
| 1577 b(ge, not_int32); | 1688 b(ge, not_int32); |
| 1578 } else { | 1689 } else { |
| 1579 // This code is faster for doubles that are in the ranges -0x7fffffff to | 1690 // This code is faster for doubles that are in the ranges -0x7fffffff to |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 int result_size) { | 1827 int result_size) { |
| 1717 // TODO(1236192): Most runtime routines don't need the number of | 1828 // TODO(1236192): Most runtime routines don't need the number of |
| 1718 // arguments passed in because it is constant. At some point we | 1829 // arguments passed in because it is constant. At some point we |
| 1719 // should remove this need and make the runtime routine entry code | 1830 // should remove this need and make the runtime routine entry code |
| 1720 // smarter. | 1831 // smarter. |
| 1721 mov(r0, Operand(num_arguments)); | 1832 mov(r0, Operand(num_arguments)); |
| 1722 JumpToExternalReference(ext); | 1833 JumpToExternalReference(ext); |
| 1723 } | 1834 } |
| 1724 | 1835 |
| 1725 | 1836 |
| 1837 MaybeObject* MacroAssembler::TryTailCallExternalReference( |
| 1838 const ExternalReference& ext, int num_arguments, int result_size) { |
| 1839 // TODO(1236192): Most runtime routines don't need the number of |
| 1840 // arguments passed in because it is constant. At some point we |
| 1841 // should remove this need and make the runtime routine entry code |
| 1842 // smarter. |
| 1843 mov(r0, Operand(num_arguments)); |
| 1844 return TryJumpToExternalReference(ext); |
| 1845 } |
| 1846 |
| 1847 |
| 1726 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, | 1848 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, |
| 1727 int num_arguments, | 1849 int num_arguments, |
| 1728 int result_size) { | 1850 int result_size) { |
| 1729 TailCallExternalReference(ExternalReference(fid), num_arguments, result_size); | 1851 TailCallExternalReference(ExternalReference(fid), num_arguments, result_size); |
| 1730 } | 1852 } |
| 1731 | 1853 |
| 1732 | 1854 |
| 1733 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { | 1855 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) { |
| 1734 #if defined(__thumb__) | 1856 #if defined(__thumb__) |
| 1735 // Thumb mode builtin. | 1857 // Thumb mode builtin. |
| 1736 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); | 1858 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); |
| 1737 #endif | 1859 #endif |
| 1738 mov(r1, Operand(builtin)); | 1860 mov(r1, Operand(builtin)); |
| 1739 CEntryStub stub(1); | 1861 CEntryStub stub(1); |
| 1740 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); | 1862 Jump(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 1741 } | 1863 } |
| 1742 | 1864 |
| 1743 | 1865 |
| 1866 MaybeObject* MacroAssembler::TryJumpToExternalReference( |
| 1867 const ExternalReference& builtin) { |
| 1868 #if defined(__thumb__) |
| 1869 // Thumb mode builtin. |
| 1870 ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1); |
| 1871 #endif |
| 1872 mov(r1, Operand(builtin)); |
| 1873 CEntryStub stub(1); |
| 1874 return TryTailCallStub(&stub); |
| 1875 } |
| 1876 |
| 1877 |
| 1744 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, | 1878 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
| 1745 InvokeJSFlags flags, | 1879 InvokeJSFlags flags, |
| 1746 PostCallGenerator* post_call_generator) { | 1880 PostCallGenerator* post_call_generator) { |
| 1747 GetBuiltinEntry(r2, id); | 1881 GetBuiltinEntry(r2, id); |
| 1748 if (flags == CALL_JS) { | 1882 if (flags == CALL_JS) { |
| 1749 Call(r2); | 1883 Call(r2); |
| 1750 if (post_call_generator != NULL) post_call_generator->Generate(); | 1884 if (post_call_generator != NULL) post_call_generator->Generate(); |
| 1751 } else { | 1885 } else { |
| 1752 ASSERT(flags == JUMP_JS); | 1886 ASSERT(flags == JUMP_JS); |
| 1753 Jump(r2); | 1887 Jump(r2); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1931 Label ok, fail; | 2065 Label ok, fail; |
| 1932 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); | 2066 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); |
| 1933 b(&ok); | 2067 b(&ok); |
| 1934 bind(&fail); | 2068 bind(&fail); |
| 1935 Abort("Global functions must have initial map"); | 2069 Abort("Global functions must have initial map"); |
| 1936 bind(&ok); | 2070 bind(&ok); |
| 1937 } | 2071 } |
| 1938 } | 2072 } |
| 1939 | 2073 |
| 1940 | 2074 |
| 2075 void MacroAssembler::JumpIfNotPowerOfTwoOrZero( |
| 2076 Register reg, |
| 2077 Register scratch, |
| 2078 Label* not_power_of_two_or_zero) { |
| 2079 sub(scratch, reg, Operand(1), SetCC); |
| 2080 b(mi, not_power_of_two_or_zero); |
| 2081 tst(scratch, reg); |
| 2082 b(ne, not_power_of_two_or_zero); |
| 2083 } |
| 2084 |
| 2085 |
| 1941 void MacroAssembler::JumpIfNotBothSmi(Register reg1, | 2086 void MacroAssembler::JumpIfNotBothSmi(Register reg1, |
| 1942 Register reg2, | 2087 Register reg2, |
| 1943 Label* on_not_both_smi) { | 2088 Label* on_not_both_smi) { |
| 1944 STATIC_ASSERT(kSmiTag == 0); | 2089 STATIC_ASSERT(kSmiTag == 0); |
| 1945 tst(reg1, Operand(kSmiTagMask)); | 2090 tst(reg1, Operand(kSmiTagMask)); |
| 1946 tst(reg2, Operand(kSmiTagMask), eq); | 2091 tst(reg2, Operand(kSmiTagMask), eq); |
| 1947 b(ne, on_not_both_smi); | 2092 b(ne, on_not_both_smi); |
| 1948 } | 2093 } |
| 1949 | 2094 |
| 1950 | 2095 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1965 } | 2110 } |
| 1966 | 2111 |
| 1967 | 2112 |
| 1968 void MacroAssembler::AbortIfNotSmi(Register object) { | 2113 void MacroAssembler::AbortIfNotSmi(Register object) { |
| 1969 STATIC_ASSERT(kSmiTag == 0); | 2114 STATIC_ASSERT(kSmiTag == 0); |
| 1970 tst(object, Operand(kSmiTagMask)); | 2115 tst(object, Operand(kSmiTagMask)); |
| 1971 Assert(eq, "Operand is not smi"); | 2116 Assert(eq, "Operand is not smi"); |
| 1972 } | 2117 } |
| 1973 | 2118 |
| 1974 | 2119 |
| 2120 void MacroAssembler::AbortIfNotRootValue(Register src, |
| 2121 Heap::RootListIndex root_value_index, |
| 2122 const char* message) { |
| 2123 ASSERT(!src.is(ip)); |
| 2124 LoadRoot(ip, root_value_index); |
| 2125 cmp(src, ip); |
| 2126 Assert(eq, message); |
| 2127 } |
| 2128 |
| 2129 |
| 1975 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 2130 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
| 1976 Register heap_number_map, | 2131 Register heap_number_map, |
| 1977 Register scratch, | 2132 Register scratch, |
| 1978 Label* on_not_heap_number) { | 2133 Label* on_not_heap_number) { |
| 1979 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 2134 ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1980 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2135 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 1981 cmp(scratch, heap_number_map); | 2136 cmp(scratch, heap_number_map); |
| 1982 b(ne, on_not_heap_number); | 2137 b(ne, on_not_heap_number); |
| 1983 } | 2138 } |
| 1984 | 2139 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2079 for (int i = 0; i < field_count; i++) { | 2234 for (int i = 0; i < field_count; i++) { |
| 2080 ldr(tmp, FieldMemOperand(src, i * kPointerSize)); | 2235 ldr(tmp, FieldMemOperand(src, i * kPointerSize)); |
| 2081 str(tmp, FieldMemOperand(dst, i * kPointerSize)); | 2236 str(tmp, FieldMemOperand(dst, i * kPointerSize)); |
| 2082 } | 2237 } |
| 2083 } | 2238 } |
| 2084 | 2239 |
| 2085 | 2240 |
| 2086 void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. | 2241 void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. |
| 2087 Register source, // Input. | 2242 Register source, // Input. |
| 2088 Register scratch) { | 2243 Register scratch) { |
| 2089 ASSERT(!zeros.is(source) || !source.is(zeros)); | 2244 ASSERT(!zeros.is(source) || !source.is(scratch)); |
| 2090 ASSERT(!zeros.is(scratch)); | 2245 ASSERT(!zeros.is(scratch)); |
| 2091 ASSERT(!scratch.is(ip)); | 2246 ASSERT(!scratch.is(ip)); |
| 2092 ASSERT(!source.is(ip)); | 2247 ASSERT(!source.is(ip)); |
| 2093 ASSERT(!zeros.is(ip)); | 2248 ASSERT(!zeros.is(ip)); |
| 2094 #ifdef CAN_USE_ARMV5_INSTRUCTIONS | 2249 #ifdef CAN_USE_ARMV5_INSTRUCTIONS |
| 2095 clz(zeros, source); // This instruction is only supported after ARM5. | 2250 clz(zeros, source); // This instruction is only supported after ARM5. |
| 2096 #else | 2251 #else |
| 2097 mov(zeros, Operand(0, RelocInfo::NONE)); | 2252 mov(zeros, Operand(0, RelocInfo::NONE)); |
| 2098 Move(scratch, source); | 2253 Move(scratch, source); |
| 2099 // Top 16. | 2254 // Top 16. |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2293 | 2448 |
| 2294 void CodePatcher::Emit(Address addr) { | 2449 void CodePatcher::Emit(Address addr) { |
| 2295 masm()->emit(reinterpret_cast<Instr>(addr)); | 2450 masm()->emit(reinterpret_cast<Instr>(addr)); |
| 2296 } | 2451 } |
| 2297 #endif // ENABLE_DEBUGGER_SUPPORT | 2452 #endif // ENABLE_DEBUGGER_SUPPORT |
| 2298 | 2453 |
| 2299 | 2454 |
| 2300 } } // namespace v8::internal | 2455 } } // namespace v8::internal |
| 2301 | 2456 |
| 2302 #endif // V8_TARGET_ARCH_ARM | 2457 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |