aoqi@1: /* aoqi@1: * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. aoqi@1: * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. aoqi@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@1: * aoqi@1: * This code is free software; you can redistribute it and/or modify it aoqi@1: * under the terms of the GNU General Public License version 2 only, as aoqi@1: * published by the Free Software Foundation. aoqi@1: * aoqi@1: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@1: * version 2 for more details (a copy is included in the LICENSE file that aoqi@1: * accompanied this code). aoqi@1: * aoqi@1: * You should have received a copy of the GNU General Public License version aoqi@1: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@1: * aoqi@1: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@1: * or visit www.oracle.com if you need additional information or have any aoqi@1: * questions. aoqi@1: * aoqi@1: */ aoqi@1: aoqi@1: #include "precompiled.hpp" aoqi@1: #ifdef COMPILER2 aoqi@1: #include "asm/macroAssembler.hpp" aoqi@1: #include "asm/macroAssembler.inline.hpp" aoqi@1: #include "classfile/systemDictionary.hpp" aoqi@1: #include "code/vmreg.hpp" aoqi@1: #include "interpreter/interpreter.hpp" aoqi@1: #include "opto/runtime.hpp" aoqi@1: #include "runtime/interfaceSupport.hpp" aoqi@1: #include "runtime/sharedRuntime.hpp" aoqi@1: #include "runtime/stubRoutines.hpp" aoqi@1: #include "runtime/vframeArray.hpp" aoqi@1: #include "utilities/globalDefinitions.hpp" aoqi@1: #include "vmreg_mips.inline.hpp" aoqi@1: #endif aoqi@1: aoqi@1: #define __ masm-> aoqi@1: aoqi@1: //-------------- generate_exception_blob ----------- aoqi@1: // creates _exception_blob. aoqi@1: // The exception blob is jumped to from a compiled method. aoqi@1: // (see emit_exception_handler in sparc.ad file) aoqi@1: // aoqi@1: // Given an exception pc at a call we call into the runtime for the aoqi@1: // handler in this method. This handler might merely restore state aoqi@1: // (i.e. callee save registers) unwind the frame and jump to the aoqi@1: // exception handler for the nmethod if there is no Java level handler aoqi@1: // for the nmethod. aoqi@1: // aoqi@1: // This code is entered with a jump, and left with a jump. aoqi@1: // aoqi@1: // Arguments: aoqi@1: // V0: exception oop aoqi@1: // V1: exception pc aoqi@1: // aoqi@1: // Results: aoqi@1: // A0: exception oop aoqi@1: // A1: exception pc in caller or ??? aoqi@1: // jumps to: exception handler of caller aoqi@1: // aoqi@1: // Note: the exception pc MUST be at a call (precise debug information) aoqi@1: // aoqi@1: // 2012/9/14 Jin: [stubGenerator_mips.cpp] generate_forward_exception() aoqi@1: // |- V0, V1 are created aoqi@1: // |- T9 <= SharedRuntime::exception_handler_for_return_address aoqi@1: // `- jr T9 aoqi@1: // `- the caller's exception_handler aoqi@1: // `- jr OptoRuntime::exception_blob aoqi@1: // `- here aoqi@1: // aoqi@1: void OptoRuntime::generate_exception_blob() { aoqi@1: // Capture info about frame layout aoqi@1: enum layout { aoqi@1: fp_off, aoqi@1: return_off, // slot for return address aoqi@1: framesize aoqi@1: }; aoqi@1: aoqi@1: // allocate space for the code aoqi@1: ResourceMark rm; aoqi@1: // setup code generation tools aoqi@1: CodeBuffer buffer("exception_blob", 5120, 5120); aoqi@1: MacroAssembler* masm = new MacroAssembler(&buffer); aoqi@1: aoqi@1: // OopMapSet *oop_maps = new OopMapSet(); aoqi@1: aoqi@1: address start = __ pc(); aoqi@1: aoqi@1: __ daddiu(SP, SP, -1 * framesize * wordSize); // Prolog! aoqi@1: aoqi@1: /* 2012/9.27 Jin: this frame will be treated as the original caller method. aoqi@1: * So, the return pc should be filled with the original exception pc. aoqi@1: * ref: X86's implementation aoqi@1: */ aoqi@1: __ sd(V1, SP, return_off *wordSize); // return address aoqi@1: __ sd(FP, SP, fp_off *wordSize); // EBP aoqi@1: aoqi@1: // Save callee saved registers. None for UseSSE=0, aoqi@1: // floats-only for UseSSE=1, and doubles for UseSSE=2. aoqi@1: aoqi@1: __ daddiu(FP, SP, fp_off * wordSize); aoqi@1: aoqi@1: // Store exception in Thread object. We cannot pass any arguments to the aoqi@1: // handle_exception call, since we do not want to make any assumption aoqi@1: // about the size of the frame where the exception happened in. aoqi@1: Register thread = TREG; aoqi@1: aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@1: aoqi@1: __ sd(V0, Address(thread, JavaThread::exception_oop_offset())); aoqi@1: __ sd(V1, Address(thread, JavaThread::exception_pc_offset())); aoqi@1: aoqi@1: // This call does all the hard work. It checks if an exception handler aoqi@1: // exists in the method. aoqi@1: // If so, it returns the handler address. aoqi@1: // If not, it prepares for stack-unwinding, restoring the callee-save aoqi@1: // registers of the frame being removed. aoqi@1: __ set_last_Java_frame(thread, NOREG, NOREG, NULL); aoqi@1: aoqi@1: __ move(AT, -(StackAlignmentInBytes)); aoqi@1: __ andr(SP, SP, AT); // Fix stack alignment as required by ABI aoqi@1: aoqi@1: __ relocate(relocInfo::internal_pc_type); aoqi@1: aoqi@1: { aoqi@1: long save_pc = (long)__ pc() + 24 + NativeCall::return_address_offset; aoqi@1: __ li48(AT, save_pc); aoqi@1: } aoqi@1: __ sd(AT, thread, in_bytes(JavaThread::last_Java_pc_offset())); aoqi@1: aoqi@1: __ move(A0, thread); aoqi@1: __ li48(T9, (long)OptoRuntime::handle_exception_C); aoqi@1: __ jalr(T9); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // Set an oopmap for the call site aoqi@1: OopMapSet *oop_maps = new OopMapSet(); aoqi@1: OopMap* map = new OopMap( framesize, 0 ); aoqi@1: aoqi@1: oop_maps->add_gc_map( __ offset(), map); aoqi@1: aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@1: __ reset_last_Java_frame(thread, true, true); aoqi@1: aoqi@1: // Pop self-frame. aoqi@1: __ leave(); // Epilog! aoqi@1: aoqi@1: // rax,: exception handler for given aoqi@1: aoqi@1: // We have a handler in rax, (could be deopt blob) aoqi@1: // rdx - throwing pc, deopt blob will need it. aoqi@1: /* FIXME: rdx? */ aoqi@1: aoqi@1: // rcx contains handler address aoqi@1: __ move(T9, V0); aoqi@1: aoqi@1: #ifndef OPT_THREAD aoqi@1: __ get_thread(thread); aoqi@1: #endif aoqi@1: // Get the exception aoqi@1: __ ld(A0, Address(thread, JavaThread::exception_oop_offset())); aoqi@1: // Get the exception pc in case we are deoptimized aoqi@1: __ ld(A1, Address(thread, JavaThread::exception_pc_offset())); aoqi@1: #ifdef ASSERT aoqi@1: __ sd(R0, Address(thread, JavaThread::exception_handler_pc_offset())); aoqi@1: __ sd(R0, Address(thread, JavaThread::exception_pc_offset())); aoqi@1: #endif aoqi@1: // Clear the exception oop so GC no longer processes it as a root. aoqi@1: __ sd(R0, Address(thread, JavaThread::exception_oop_offset())); aoqi@1: aoqi@1: /* 2014/5/12 Jin: Fix seg fault when running: aoqi@1: * Eclipse + Plugin + Debug As aoqi@1: * This is the only condition where C2 calls SharedRuntime::generate_deopt_blob() aoqi@1: * aoqi@1: * Ref: http://10.2.5.21:8000/projects/java/wiki/Jgj-log-2014-5-12_ aoqi@1: */ aoqi@1: __ move(V0, A0); aoqi@1: __ move(V1, A1); aoqi@1: aoqi@1: // rax,: exception oop aoqi@1: // rcx: exception handler aoqi@1: // rdx: exception pc aoqi@1: __ jr(T9); aoqi@1: __ delayed()->nop(); aoqi@1: aoqi@1: // make sure all code is generated aoqi@1: masm->flush(); aoqi@1: aoqi@1: _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize); aoqi@1: }