0N/A/*
2539N/A * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
1879N/A#include "precompiled.hpp"
1879N/A#ifdef COMPILER2
1879N/A#include "asm/assembler.hpp"
1879N/A#include "assembler_x86.inline.hpp"
1879N/A#include "classfile/systemDictionary.hpp"
1879N/A#include "code/vmreg.hpp"
1879N/A#include "interpreter/interpreter.hpp"
1879N/A#include "nativeInst_x86.hpp"
1879N/A#include "opto/runtime.hpp"
1879N/A#include "runtime/interfaceSupport.hpp"
1879N/A#include "runtime/sharedRuntime.hpp"
1879N/A#include "runtime/stubRoutines.hpp"
1879N/A#include "runtime/vframeArray.hpp"
1879N/A#include "utilities/globalDefinitions.hpp"
1879N/A#include "vmreg_x86.inline.hpp"
1879N/A#endif
0N/A
0N/A
0N/A#define __ masm->
0N/A
0N/A//------------------------------generate_exception_blob---------------------------
0N/A// creates exception blob at the end
0N/A// Using exception blob, this code is jumped from a compiled method.
0N/A//
0N/A// Given an exception pc at a call we call into the runtime for the
0N/A// handler in this method. This handler might merely restore state
0N/A// (i.e. callee save registers) unwind the frame and jump to the
0N/A// exception handler for the nmethod if there is no Java level handler
0N/A// for the nmethod.
0N/A//
0N/A// This code is entered with a jmp.
0N/A//
0N/A// Arguments:
1135N/A// rax: exception oop
0N/A// rdx: exception pc
0N/A//
0N/A// Results:
1135N/A// rax: exception oop
0N/A// rdx: exception pc in caller or ???
0N/A// destination: exception handler of caller
0N/A//
0N/A// Note: the exception pc MUST be at a call (precise debug information)
0N/A// Only register rax, rdx, rcx are not callee saved.
0N/A//
0N/A
0N/Avoid OptoRuntime::generate_exception_blob() {
0N/A
0N/A // Capture info about frame layout
0N/A enum layout {
0N/A thread_off, // last_java_sp
0N/A // The frame sender code expects that rbp will be in the "natural" place and
0N/A // will override any oopMap setting for it. We must therefore force the layout
0N/A // so that it agrees with the frame sender code.
0N/A rbp_off,
0N/A return_off, // slot for return address
0N/A framesize
0N/A };
0N/A
0N/A // allocate space for the code
0N/A ResourceMark rm;
0N/A // setup code generation tools
0N/A CodeBuffer buffer("exception_blob", 512, 512);
0N/A MacroAssembler* masm = new MacroAssembler(&buffer);
0N/A
0N/A OopMapSet *oop_maps = new OopMapSet();
0N/A
0N/A address start = __ pc();
0N/A
304N/A __ push(rdx);
304N/A __ subptr(rsp, return_off * wordSize); // Prolog!
0N/A
0N/A // rbp, location is implicitly known
304N/A __ movptr(Address(rsp,rbp_off *wordSize), rbp);
0N/A
0N/A // Store exception in Thread object. We cannot pass any arguments to the
0N/A // handle_exception call, since we do not want to make any assumption
0N/A // about the size of the frame where the exception happened in.
0N/A __ get_thread(rcx);
304N/A __ movptr(Address(rcx, JavaThread::exception_oop_offset()), rax);
304N/A __ movptr(Address(rcx, JavaThread::exception_pc_offset()), rdx);
0N/A
0N/A // This call does all the hard work. It checks if an exception handler
0N/A // exists in the method.
0N/A // If so, it returns the handler address.
0N/A // If not, it prepares for stack-unwinding, restoring the callee-save
0N/A // registers of the frame being removed.
0N/A //
304N/A __ movptr(Address(rsp, thread_off * wordSize), rcx); // Thread is first argument
0N/A __ set_last_Java_frame(rcx, noreg, noreg, NULL);
0N/A
0N/A __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)));
0N/A
0N/A // No registers to map, rbp is known implicitly
0N/A oop_maps->add_gc_map( __ pc() - start, new OopMap( framesize, 0 ));
0N/A __ get_thread(rcx);
0N/A __ reset_last_Java_frame(rcx, false, false);
0N/A
0N/A // Restore callee-saved registers
304N/A __ movptr(rbp, Address(rsp, rbp_off * wordSize));
0N/A
304N/A __ addptr(rsp, return_off * wordSize); // Epilog!
304N/A __ pop(rdx); // Exception pc
0N/A
1135N/A // rax: exception handler for given <exception oop/exception pc>
0N/A
1368N/A // Restore SP from BP if the exception PC is a MethodHandle call site.
1368N/A __ cmpl(Address(rcx, JavaThread::is_method_handle_return_offset()), 0);
1487N/A __ cmovptr(Assembler::notEqual, rsp, rbp_mh_SP_save);
0N/A
0N/A // We have a handler in rax, (could be deopt blob)
0N/A // rdx - throwing pc, deopt blob will need it.
0N/A
304N/A __ push(rax);
0N/A
0N/A // Get the exception
304N/A __ movptr(rax, Address(rcx, JavaThread::exception_oop_offset()));
0N/A // Get the exception pc in case we are deoptimized
304N/A __ movptr(rdx, Address(rcx, JavaThread::exception_pc_offset()));
0N/A#ifdef ASSERT
512N/A __ movptr(Address(rcx, JavaThread::exception_handler_pc_offset()), NULL_WORD);
512N/A __ movptr(Address(rcx, JavaThread::exception_pc_offset()), NULL_WORD);
0N/A#endif
0N/A // Clear the exception oop so GC no longer processes it as a root.
512N/A __ movptr(Address(rcx, JavaThread::exception_oop_offset()), NULL_WORD);
0N/A
304N/A __ pop(rcx);
0N/A
1135N/A // rax: exception oop
0N/A // rcx: exception handler
0N/A // rdx: exception pc
0N/A __ jmp (rcx);
0N/A
0N/A // -------------
0N/A // make sure all code is generated
0N/A masm->flush();
0N/A
0N/A _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize);
0N/A}