diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index dd1af02cda..5e5bc4b819 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -3856,7 +3856,7 @@ void CEntryStub::Generate(MacroAssembler* masm) { void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { - Label invoke, exit; + Label invoke, handler_entry, exit; Isolate* isolate = masm->isolate(); // Registers: @@ -3933,14 +3933,15 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { __ bind(&cont); __ push(t0); - // Call a faked try-block that does the invoke. - __ bal(&invoke); // bal exposes branch delay slot. - __ nop(); // Branch delay slot nop. - - // Caught exception: Store result (exception) in the pending - // exception field in the JSEnv and return a failure sentinel. - // Coming in here the fp will be invalid because the PushTryHandler below - // sets it to 0 to signal the existence of the JSEntry frame. + // Jump to a faked try block that does the invoke, with a faked catch + // block that sets the pending exception. + __ jmp(&invoke); + __ bind(&handler_entry); + handler_offset_ = handler_entry.pos(); + // Caught exception: Store result (exception) in the pending exception + // field in the JSEnv and return a failure sentinel. Coming in here the + // fp will be invalid because the PushTryHandler below sets it to 0 to + // signal the existence of the JSEntry frame. __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress, isolate))); __ sw(v0, MemOperand(t0)); // We come back from 'invoke'. result is in v0. @@ -3948,9 +3949,10 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { __ b(&exit); // b exposes branch delay slot. __ nop(); // Branch delay slot nop. - // Invoke: Link this frame into the handler chain. + // Invoke: Link this frame into the handler chain. There's only one + // handler block in this code object, so its index is 0. __ bind(&invoke); - __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); + __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER, 0); // If an exception not caught by another handler occurs, this handler // returns control to the code after the bal(&invoke) above, which // restores all kCalleeSaved registers (including cp and fp) to their @@ -5103,7 +5105,7 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { } -void CallFunctionStub::FinishCode(Code* code) { +void CallFunctionStub::FinishCode(Handle code) { code->set_has_function_cache(false); } diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h index f45ad2b213..e0954d837e 100644 --- a/src/mips/code-stubs-mips.h +++ b/src/mips/code-stubs-mips.h @@ -137,7 +137,7 @@ class UnaryOpStub: public CodeStub { return UnaryOpIC::ToState(operand_type_); } - virtual void FinishCode(Code* code) { + virtual void FinishCode(Handle code) { code->set_unary_op_type(operand_type_); } }; @@ -236,7 +236,7 @@ class BinaryOpStub: public CodeStub { return BinaryOpIC::ToState(operands_type_); } - virtual void FinishCode(Code* code) { + virtual void FinishCode(Handle code) { code->set_binary_op_type(operands_type_); code->set_binary_op_result_type(result_type_); } diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h index a2ebce6829..ba6a230cee 100644 --- a/src/mips/frames-mips.h +++ b/src/mips/frames-mips.h @@ -154,13 +154,13 @@ static const int kSafepointRegisterStackIndexMap[kNumRegs] = { class StackHandlerConstants : public AllStatic { public: - static const int kNextOffset = 0 * kPointerSize; - static const int kStateOffset = 1 * kPointerSize; - static const int kContextOffset = 2 * kPointerSize; - static const int kFPOffset = 3 * kPointerSize; - static const int kPCOffset = 4 * kPointerSize; + static const int kNextOffset = 0 * kPointerSize; + static const int kCodeOffset = 1 * kPointerSize; + static const int kStateOffset = 2 * kPointerSize; + static const int kContextOffset = 3 * kPointerSize; + static const int kFPOffset = 4 * kPointerSize; - static const int kSize = kPCOffset + kPointerSize; + static const int kSize = kFPOffset + kPointerSize; }; diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index a4b87664bb..77ef41ce28 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -137,6 +137,8 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { ASSERT(info_ == NULL); info_ = info; scope_ = info->scope(); + handler_table_ = + isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index fb93208bf5..c1161d73dd 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -2544,60 +2544,50 @@ void MacroAssembler::DebugBreak() { // Exception handling. void MacroAssembler::PushTryHandler(CodeLocation try_location, - HandlerType type) { + HandlerType type, + int handler_index) { // Adjust this code if not the case. STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); - // The return address is passed in register ra. + // For the JSEntry handler, we must preserve a0-a3 and s0. + // t1-t3 are available. We will build up the handler from the bottom by + // pushing on the stack. First compute the state. + unsigned state = StackHandler::OffsetField::encode(handler_index); if (try_location == IN_JAVASCRIPT) { - if (type == TRY_CATCH_HANDLER) { - li(t0, Operand(StackHandler::TRY_CATCH)); - } else { - li(t0, Operand(StackHandler::TRY_FINALLY)); - } - // Save the current handler as the next handler. - li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); - lw(t1, MemOperand(t2)); - - addiu(sp, sp, -StackHandlerConstants::kSize); - sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); - sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset)); - sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); - sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); - sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); - - // Link this handler as the new current one. - sw(sp, MemOperand(t2)); - + state |= (type == TRY_CATCH_HANDLER) + ? StackHandler::KindField::encode(StackHandler::TRY_CATCH) + : StackHandler::KindField::encode(StackHandler::TRY_FINALLY); } else { - // Must preserve a0-a3, and s0 (argv). ASSERT(try_location == IN_JS_ENTRY); - // The frame pointer does not point to a JS frame so we save NULL - // for fp. We expect the code throwing an exception to check fp - // before dereferencing it to restore the context. - li(t0, Operand(StackHandler::ENTRY)); - - // Save the current handler as the next handler. - li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); - lw(t1, MemOperand(t2)); - - ASSERT(Smi::FromInt(0) == 0); // Used for no context. - - addiu(sp, sp, -StackHandlerConstants::kSize); - sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); - sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset)); - sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset)); - sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); - sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); - - // Link this handler as the new current one. - sw(sp, MemOperand(t2)); + state |= StackHandler::KindField::encode(StackHandler::ENTRY); } + + // Set up the code object (t1) and the state (t2) for pushing. + li(t1, Operand(CodeObject())); + li(t2, Operand(state)); + + // Push the frame pointer, context, state, and code object. + if (try_location == IN_JAVASCRIPT) { + MultiPush(t1.bit() | t2.bit() | cp.bit() | fp.bit()); + } else { + ASSERT_EQ(Smi::FromInt(0), 0); + // The second zero_reg indicates no context. + // The first zero_reg is the NULL frame pointer. + // The operands are reversed to match the order of MultiPush/Pop. + Push(zero_reg, zero_reg, t2, t1); + } + + // Link the current handler as the next handler. + li(t2, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); + lw(t1, MemOperand(t2)); + push(t1); + // Set this new handler as the current one. + sw(sp, MemOperand(t2)); } @@ -2610,19 +2600,36 @@ void MacroAssembler::PopTryHandler() { } -void MacroAssembler::Throw(Register value) { - // v0 is expected to hold the exception. - Move(v0, value); +void MacroAssembler::JumpToHandlerEntry() { + // Compute the handler entry address and jump to it. The handler table is + // a fixed array of (smi-tagged) code offsets. + // v0 = exception, a1 = code object, a2 = state. + lw(a3, FieldMemOperand(a1, Code::kHandlerTableOffset)); // Handler table. + Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); + srl(a2, a2, StackHandler::kKindWidth); // Handler index. + sll(a2, a2, kPointerSizeLog2); + Addu(a2, a3, a2); + lw(a2, MemOperand(a2)); // Smi-tagged offset. + Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start. + sra(t9, a2, kSmiTagSize); + Addu(t9, t9, a1); + Jump(t9); // Jump. +} + +void MacroAssembler::Throw(Register value) { // Adjust this code if not the case. STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); + STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); - // Drop the sp to the top of the handler. + // The exception is expected in v0. + Move(v0, value); + + // Drop the stack pointer to the top of the top handler. li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); lw(sp, MemOperand(a3)); @@ -2631,44 +2638,19 @@ void MacroAssembler::Throw(Register value) { pop(a2); sw(a2, MemOperand(a3)); - // Restore context and frame pointer, discard state (a3). - MultiPop(a3.bit() | cp.bit() | fp.bit()); + // Get the code object (a1) and state (a2). Restore the context and frame + // pointer. + MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit()); // If the handler is a JS frame, restore the context to the frame. - // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any - // of them. + // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp + // or cp. Label done; - Branch(&done, eq, fp, Operand(zero_reg)); + Branch(&done, eq, cp, Operand(zero_reg)); sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); bind(&done); -#ifdef DEBUG - // When emitting debug_code, set ra as return address for the jump. - // 5 instructions: add: 1, pop: 2, jump: 2. - const int kOffsetRaInstructions = 5; - Label find_ra; - - if (emit_debug_code()) { - // Compute ra for the Jump(t9). - const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; - - // This branch-and-link sequence is needed to get the current PC on mips, - // saved to the ra register. Then adjusted for instruction count. - bal(&find_ra); // bal exposes branch-delay. - nop(); // Branch delay slot nop. - bind(&find_ra); - addiu(ra, ra, kOffsetRaBytes); - } -#endif - - pop(t9); // 2 instructions: lw, add sp. - Jump(t9); // 2 instructions: jr, nop (in delay slot). - - if (emit_debug_code()) { - // Make sure that the expected number of instructions were generated. - ASSERT_EQ(kOffsetRaInstructions, - InstructionsGeneratedSince(&find_ra)); - } + JumpToHandlerEntry(); } @@ -2677,10 +2659,10 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, // Adjust this code if not the case. STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); - STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); + STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); // The exception is expected in v0. if (type == OUT_OF_MEMORY) { @@ -2705,26 +2687,27 @@ void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate()))); lw(sp, MemOperand(a3)); - // Unwind the handlers until the top ENTRY handler is found. + // Unwind the handlers until the ENTRY handler is found. Label fetch_next, check_kind; jmp(&check_kind); bind(&fetch_next); lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset)); bind(&check_kind); + STATIC_ASSERT(StackHandler::ENTRY == 0); lw(a2, MemOperand(sp, StackHandlerConstants::kStateOffset)); - Branch(&fetch_next, ne, a2, Operand(StackHandler::ENTRY)); + And(a2, a2, Operand(StackHandler::KindField::kMask)); + Branch(&fetch_next, ne, a2, Operand(zero_reg)); // Set the top handler address to next handler past the top ENTRY handler. pop(a2); sw(a2, MemOperand(a3)); - // Clear the context and frame pointer (0 was saved in the handler), and - // discard the state (a2). - MultiPop(a2.bit() | cp.bit() | fp.bit()); + // Get the code object (a1) and state (a2). Clear the context and frame + // pointer (0 was saved in the handler). + MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit()); - pop(t9); // 2 instructions: lw, add sp. - Jump(t9); // 2 instructions: jr, nop (in delay slot). + JumpToHandlerEntry(); } diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index b9bd2f3a91..5ff1c2d97b 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -843,9 +843,9 @@ class MacroAssembler: public Assembler { // Exception handling. // Push a new try handler and link into try handler chain. - // The return address must be passed in register ra. - // Clobber t0, t1, t2. - void PushTryHandler(CodeLocation try_location, HandlerType type); + void PushTryHandler(CodeLocation try_location, + HandlerType type, + int handler_index); // Unlink the stack handler on top of the stack from the try handler chain. // Must preserve the result register. @@ -1381,6 +1381,10 @@ class MacroAssembler: public Assembler { Register bitmap_reg, Register mask_reg); + // Helper for throwing exceptions. Compute a handler address and jump to + // it. See the implementation for register usage. + void JumpToHandlerEntry(); + // Compute memory operands for safepoint stack slots. static int SafepointRegisterStackIndex(int reg_code); MemOperand SafepointRegisterSlot(Register reg);