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 2526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2537 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 2537 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); |
2538 } | 2538 } |
2539 | 2539 |
2540 #endif // ENABLE_DEBUGGER_SUPPORT | 2540 #endif // ENABLE_DEBUGGER_SUPPORT |
2541 | 2541 |
2542 | 2542 |
2543 // --------------------------------------------------------------------------- | 2543 // --------------------------------------------------------------------------- |
2544 // Exception handling. | 2544 // Exception handling. |
2545 | 2545 |
2546 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 2546 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
2547 HandlerType type) { | 2547 HandlerType type, |
| 2548 int handler_index) { |
2548 // Adjust this code if not the case. | 2549 // Adjust this code if not the case. |
2549 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 2550 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
2550 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 2551 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); |
2551 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | 2552 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
2552 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | 2553 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
2553 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | 2554 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
2554 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | 2555 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
2555 | 2556 |
2556 // The return address is passed in register ra. | 2557 // For the JSEntry handler, we must preserve a0-a3 and s0. |
| 2558 // t1-t3 are available. We will build up the handler from the bottom by |
| 2559 // pushing on the stack. First compute the state. |
| 2560 unsigned state = StackHandler::OffsetField::encode(handler_index); |
2557 if (try_location == IN_JAVASCRIPT) { | 2561 if (try_location == IN_JAVASCRIPT) { |
2558 if (type == TRY_CATCH_HANDLER) { | 2562 state |= (type == TRY_CATCH_HANDLER) |
2559 li(t0, Operand(StackHandler::TRY_CATCH)); | 2563 ? StackHandler::KindField::encode(StackHandler::TRY_CATCH) |
2560 } else { | 2564 : StackHandler::KindField::encode(StackHandler::TRY_FINALLY); |
2561 li(t0, Operand(StackHandler::TRY_FINALLY)); | 2565 } else { |
2562 } | 2566 ASSERT(try_location == IN_JS_ENTRY); |
2563 // Save the current handler as the next handler. | 2567 state |= StackHandler::KindField::encode(StackHandler::ENTRY); |
2564 li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | 2568 } |
2565 lw(t1, MemOperand(t2)); | |
2566 | 2569 |
2567 addiu(sp, sp, -StackHandlerConstants::kSize); | 2570 // Set up the code object (t1) and the state (t2) for pushing. |
2568 sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); | 2571 li(t1, Operand(CodeObject())); |
2569 sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset)); | 2572 li(t2, Operand(state)); |
2570 sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); | |
2571 sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); | |
2572 sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); | |
2573 | 2573 |
2574 // Link this handler as the new current one. | 2574 // Push the frame pointer, context, state, and code object. |
2575 sw(sp, MemOperand(t2)); | 2575 if (try_location == IN_JAVASCRIPT) { |
| 2576 MultiPush(t1.bit() | t2.bit() | cp.bit() | fp.bit()); |
| 2577 } else { |
| 2578 ASSERT_EQ(Smi::FromInt(0), 0); |
| 2579 // The second zero_reg indicates no context. |
| 2580 // The first zero_reg is the NULL frame pointer. |
| 2581 // The operands are reversed to match the order of MultiPush/Pop. |
| 2582 Push(zero_reg, zero_reg, t2, t1); |
| 2583 } |
2576 | 2584 |
2577 } else { | 2585 // Link the current handler as the next handler. |
2578 // Must preserve a0-a3, and s0 (argv). | 2586 li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); |
2579 ASSERT(try_location == IN_JS_ENTRY); | 2587 lw(t1, MemOperand(t2)); |
2580 // The frame pointer does not point to a JS frame so we save NULL | 2588 push(t1); |
2581 // for fp. We expect the code throwing an exception to check fp | 2589 // Set this new handler as the current one. |
2582 // before dereferencing it to restore the context. | 2590 sw(sp, MemOperand(t2)); |
2583 li(t0, Operand(StackHandler::ENTRY)); | |
2584 | |
2585 // Save the current handler as the next handler. | |
2586 li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | |
2587 lw(t1, MemOperand(t2)); | |
2588 | |
2589 ASSERT(Smi::FromInt(0) == 0); // Used for no context. | |
2590 | |
2591 addiu(sp, sp, -StackHandlerConstants::kSize); | |
2592 sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); | |
2593 sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset)); | |
2594 sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset)); | |
2595 sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); | |
2596 sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); | |
2597 | |
2598 // Link this handler as the new current one. | |
2599 sw(sp, MemOperand(t2)); | |
2600 } | |
2601 } | 2591 } |
2602 | 2592 |
2603 | 2593 |
2604 void MacroAssembler::PopTryHandler() { | 2594 void MacroAssembler::PopTryHandler() { |
2605 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 2595 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2606 pop(a1); | 2596 pop(a1); |
2607 Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 2597 Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
2608 li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | 2598 li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); |
2609 sw(a1, MemOperand(at)); | 2599 sw(a1, MemOperand(at)); |
2610 } | 2600 } |
2611 | 2601 |
2612 | 2602 |
| 2603 void MacroAssembler::JumpToHandlerEntry() { |
| 2604 // Compute the handler entry address and jump to it. The handler table is |
| 2605 // a fixed array of (smi-tagged) code offsets. |
| 2606 // v0 = exception, a1 = code object, a2 = state. |
| 2607 lw(a3, FieldMemOperand(a1, Code::kHandlerTableOffset)); // Handler table. |
| 2608 Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 2609 srl(a2, a2, StackHandler::kKindWidth); // Handler index. |
| 2610 sll(a2, a2, kPointerSizeLog2); |
| 2611 Addu(a2, a3, a2); |
| 2612 lw(a2, MemOperand(a2)); // Smi-tagged offset. |
| 2613 Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start. |
| 2614 sra(t9, a2, kSmiTagSize); |
| 2615 Addu(t9, t9, a1); |
| 2616 Jump(t9); // Jump. |
| 2617 } |
| 2618 |
| 2619 |
2613 void MacroAssembler::Throw(Register value) { | 2620 void MacroAssembler::Throw(Register value) { |
2614 // v0 is expected to hold the exception. | 2621 // Adjust this code if not the case. |
| 2622 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
| 2623 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 2624 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
| 2625 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
| 2626 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
| 2627 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
| 2628 |
| 2629 // The exception is expected in v0. |
2615 Move(v0, value); | 2630 Move(v0, value); |
2616 | 2631 |
2617 // Adjust this code if not the case. | 2632 // Drop the stack pointer to the top of the top handler. |
2618 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | |
2619 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2620 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | |
2621 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | |
2622 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | |
2623 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | |
2624 | |
2625 // Drop the sp to the top of the handler. | |
2626 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, | 2633 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, |
2627 isolate()))); | 2634 isolate()))); |
2628 lw(sp, MemOperand(a3)); | 2635 lw(sp, MemOperand(a3)); |
2629 | 2636 |
2630 // Restore the next handler. | 2637 // Restore the next handler. |
2631 pop(a2); | 2638 pop(a2); |
2632 sw(a2, MemOperand(a3)); | 2639 sw(a2, MemOperand(a3)); |
2633 | 2640 |
2634 // Restore context and frame pointer, discard state (a3). | 2641 // Get the code object (a1) and state (a2). Restore the context and frame |
2635 MultiPop(a3.bit() | cp.bit() | fp.bit()); | 2642 // pointer. |
| 2643 MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit()); |
2636 | 2644 |
2637 // If the handler is a JS frame, restore the context to the frame. | 2645 // If the handler is a JS frame, restore the context to the frame. |
2638 // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any | 2646 // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp |
2639 // of them. | 2647 // or cp. |
2640 Label done; | 2648 Label done; |
2641 Branch(&done, eq, fp, Operand(zero_reg)); | 2649 Branch(&done, eq, cp, Operand(zero_reg)); |
2642 sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2650 sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2643 bind(&done); | 2651 bind(&done); |
2644 | 2652 |
2645 #ifdef DEBUG | 2653 JumpToHandlerEntry(); |
2646 // When emitting debug_code, set ra as return address for the jump. | |
2647 // 5 instructions: add: 1, pop: 2, jump: 2. | |
2648 const int kOffsetRaInstructions = 5; | |
2649 Label find_ra; | |
2650 | |
2651 if (emit_debug_code()) { | |
2652 // Compute ra for the Jump(t9). | |
2653 const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; | |
2654 | |
2655 // This branch-and-link sequence is needed to get the current PC on mips, | |
2656 // saved to the ra register. Then adjusted for instruction count. | |
2657 bal(&find_ra); // bal exposes branch-delay. | |
2658 nop(); // Branch delay slot nop. | |
2659 bind(&find_ra); | |
2660 addiu(ra, ra, kOffsetRaBytes); | |
2661 } | |
2662 #endif | |
2663 | |
2664 pop(t9); // 2 instructions: lw, add sp. | |
2665 Jump(t9); // 2 instructions: jr, nop (in delay slot). | |
2666 | |
2667 if (emit_debug_code()) { | |
2668 // Make sure that the expected number of instructions were generated. | |
2669 ASSERT_EQ(kOffsetRaInstructions, | |
2670 InstructionsGeneratedSince(&find_ra)); | |
2671 } | |
2672 } | 2654 } |
2673 | 2655 |
2674 | 2656 |
2675 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 2657 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
2676 Register value) { | 2658 Register value) { |
2677 // Adjust this code if not the case. | 2659 // Adjust this code if not the case. |
2678 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 2660 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
2679 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 2661 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); |
2680 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | 2662 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
2681 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | 2663 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
2682 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | 2664 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
2683 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | 2665 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
2684 | 2666 |
2685 // The exception is expected in v0. | 2667 // The exception is expected in v0. |
2686 if (type == OUT_OF_MEMORY) { | 2668 if (type == OUT_OF_MEMORY) { |
2687 // Set external caught exception to false. | 2669 // Set external caught exception to false. |
2688 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, | 2670 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, |
2689 isolate()); | 2671 isolate()); |
2690 li(a0, Operand(false, RelocInfo::NONE)); | 2672 li(a0, Operand(false, RelocInfo::NONE)); |
2691 li(a2, Operand(external_caught)); | 2673 li(a2, Operand(external_caught)); |
2692 sw(a0, MemOperand(a2)); | 2674 sw(a0, MemOperand(a2)); |
2693 | 2675 |
2694 // Set pending exception and v0 to out of memory exception. | 2676 // Set pending exception and v0 to out of memory exception. |
2695 Failure* out_of_memory = Failure::OutOfMemoryException(); | 2677 Failure* out_of_memory = Failure::OutOfMemoryException(); |
2696 li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 2678 li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
2697 li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 2679 li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
2698 isolate()))); | 2680 isolate()))); |
2699 sw(v0, MemOperand(a2)); | 2681 sw(v0, MemOperand(a2)); |
2700 } else if (!value.is(v0)) { | 2682 } else if (!value.is(v0)) { |
2701 mov(v0, value); | 2683 mov(v0, value); |
2702 } | 2684 } |
2703 | 2685 |
2704 // Drop the stack pointer to the top of the top stack handler. | 2686 // Drop the stack pointer to the top of the top stack handler. |
2705 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); | 2687 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); |
2706 lw(sp, MemOperand(a3)); | 2688 lw(sp, MemOperand(a3)); |
2707 | 2689 |
2708 // Unwind the handlers until the top ENTRY handler is found. | 2690 // Unwind the handlers until the ENTRY handler is found. |
2709 Label fetch_next, check_kind; | 2691 Label fetch_next, check_kind; |
2710 jmp(&check_kind); | 2692 jmp(&check_kind); |
2711 bind(&fetch_next); | 2693 bind(&fetch_next); |
2712 lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset)); | 2694 lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset)); |
2713 | 2695 |
2714 bind(&check_kind); | 2696 bind(&check_kind); |
| 2697 STATIC_ASSERT(StackHandler::ENTRY == 0); |
2715 lw(a2, MemOperand(sp, StackHandlerConstants::kStateOffset)); | 2698 lw(a2, MemOperand(sp, StackHandlerConstants::kStateOffset)); |
2716 Branch(&fetch_next, ne, a2, Operand(StackHandler::ENTRY)); | 2699 And(a2, a2, Operand(StackHandler::KindField::kMask)); |
| 2700 Branch(&fetch_next, ne, a2, Operand(zero_reg)); |
2717 | 2701 |
2718 // Set the top handler address to next handler past the top ENTRY handler. | 2702 // Set the top handler address to next handler past the top ENTRY handler. |
2719 pop(a2); | 2703 pop(a2); |
2720 sw(a2, MemOperand(a3)); | 2704 sw(a2, MemOperand(a3)); |
2721 | 2705 |
2722 // Clear the context and frame pointer (0 was saved in the handler), and | 2706 // Get the code object (a1) and state (a2). Clear the context and frame |
2723 // discard the state (a2). | 2707 // pointer (0 was saved in the handler). |
2724 MultiPop(a2.bit() | cp.bit() | fp.bit()); | 2708 MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit()); |
2725 | 2709 |
2726 pop(t9); // 2 instructions: lw, add sp. | 2710 JumpToHandlerEntry(); |
2727 Jump(t9); // 2 instructions: jr, nop (in delay slot). | |
2728 } | 2711 } |
2729 | 2712 |
2730 | 2713 |
2731 void MacroAssembler::AllocateInNewSpace(int object_size, | 2714 void MacroAssembler::AllocateInNewSpace(int object_size, |
2732 Register result, | 2715 Register result, |
2733 Register scratch1, | 2716 Register scratch1, |
2734 Register scratch2, | 2717 Register scratch2, |
2735 Label* gc_required, | 2718 Label* gc_required, |
2736 AllocationFlags flags) { | 2719 AllocationFlags flags) { |
2737 if (!FLAG_inline_new) { | 2720 if (!FLAG_inline_new) { |
(...skipping 2293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5031 opcode == BGTZL); | 5014 opcode == BGTZL); |
5032 opcode = (cond == eq) ? BEQ : BNE; | 5015 opcode = (cond == eq) ? BEQ : BNE; |
5033 instr = (instr & ~kOpcodeMask) | opcode; | 5016 instr = (instr & ~kOpcodeMask) | opcode; |
5034 masm_.emit(instr); | 5017 masm_.emit(instr); |
5035 } | 5018 } |
5036 | 5019 |
5037 | 5020 |
5038 } } // namespace v8::internal | 5021 } } // namespace v8::internal |
5039 | 5022 |
5040 #endif // V8_TARGET_ARCH_MIPS | 5023 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |