Path: blob/master/src/hotspot/cpu/zero/stubGenerator_zero.cpp
40931 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright 2007, 2008, 2010, 2015 Red Hat, Inc.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "asm/assembler.inline.hpp"27#include "interpreter/interpreter.hpp"28#include "nativeInst_zero.hpp"29#include "oops/instanceOop.hpp"30#include "oops/method.hpp"31#include "oops/objArrayKlass.hpp"32#include "oops/oop.inline.hpp"33#include "prims/methodHandles.hpp"34#include "runtime/frame.inline.hpp"35#include "runtime/handles.inline.hpp"36#include "runtime/sharedRuntime.hpp"37#include "runtime/stubCodeGenerator.hpp"38#include "runtime/stubRoutines.hpp"39#include "runtime/thread.inline.hpp"40#include "stack_zero.inline.hpp"41#ifdef COMPILER242#include "opto/runtime.hpp"43#endif4445// For SafeFetch we need POSIX tls and setjmp46#include <setjmp.h>47#include <pthread.h>48static pthread_key_t g_jmpbuf_key;4950// return the currently active jump buffer for this thread51// - if there is any, NULL otherwise. Called from52// zero signal handlers.53extern sigjmp_buf* get_jmp_buf_for_continuation() {54return (sigjmp_buf*) pthread_getspecific(g_jmpbuf_key);55}5657// Declaration and definition of StubGenerator (no .hpp file).58// For a more detailed description of the stub routine structure59// see the comment in stubRoutines.hpp6061class StubGenerator: public StubCodeGenerator {62private:63// The call stub is used to call Java from C64static void call_stub(65JavaCallWrapper *call_wrapper,66intptr_t* result,67BasicType result_type,68Method* method,69address entry_point,70intptr_t* parameters,71int parameter_words,72TRAPS) {73JavaThread *thread = THREAD;74ZeroStack *stack = thread->zero_stack();7576// Make sure we have no pending exceptions77assert(!HAS_PENDING_EXCEPTION, "call_stub called with pending exception");7879// Set up the stack if necessary80bool stack_needs_teardown = false;81if (stack->needs_setup()) {82size_t zero_stack_size = stack->suggest_size(thread);83stack->setup(alloca(zero_stack_size), zero_stack_size);84stack_needs_teardown = true;85}8687// Allocate and initialize our frame88EntryFrame *frame =89EntryFrame::build(parameters, parameter_words, call_wrapper, THREAD);9091if (!HAS_PENDING_EXCEPTION) {92// Push the frame93thread->push_zero_frame(frame);9495// Make the call96Interpreter::invoke_method(method, entry_point, THREAD);9798// Store the result99if (!HAS_PENDING_EXCEPTION) {100switch (result_type) {101case T_INT:102*(jint *) result = *(jint *) stack->sp();103break;104case T_LONG:105*(jlong *) result = *(jlong *) stack->sp();106break;107case T_FLOAT:108*(jfloat *) result = *(jfloat *) stack->sp();109break;110case T_DOUBLE:111*(jdouble *) result = *(jdouble *) stack->sp();112break;113case T_OBJECT:114*(oop *) result = *(oop *) stack->sp();115break;116default:117ShouldNotReachHere();118}119}120121// Unwind the frame122thread->pop_zero_frame();123}124125// Tear down the stack if necessary126if (stack_needs_teardown)127stack->teardown();128}129130// These stubs get called from some dumb test routine.131// I'll write them properly when they're called from132// something that's actually doing something.133static void fake_arraycopy_stub(address src, address dst, int count) {134assert(count == 0, "huh?");135}136137void generate_arraycopy_stubs() {138// Call the conjoint generation methods immediately after139// the disjoint ones so that short branches from the former140// to the latter can be generated.141StubRoutines::_jbyte_disjoint_arraycopy = (address) fake_arraycopy_stub;142StubRoutines::_jbyte_arraycopy = (address) fake_arraycopy_stub;143144StubRoutines::_jshort_disjoint_arraycopy = (address) fake_arraycopy_stub;145StubRoutines::_jshort_arraycopy = (address) fake_arraycopy_stub;146147StubRoutines::_jint_disjoint_arraycopy = (address) fake_arraycopy_stub;148StubRoutines::_jint_arraycopy = (address) fake_arraycopy_stub;149150StubRoutines::_jlong_disjoint_arraycopy = (address) fake_arraycopy_stub;151StubRoutines::_jlong_arraycopy = (address) fake_arraycopy_stub;152153StubRoutines::_oop_disjoint_arraycopy = ShouldNotCallThisStub();154StubRoutines::_oop_arraycopy = ShouldNotCallThisStub();155156StubRoutines::_checkcast_arraycopy = ShouldNotCallThisStub();157StubRoutines::_generic_arraycopy = ShouldNotCallThisStub();158159// Shared code tests for "NULL" to discover the stub is not generated.160StubRoutines::_unsafe_arraycopy = NULL;161162// We don't generate specialized code for HeapWord-aligned source163// arrays, so just use the code we've already generated164StubRoutines::_arrayof_jbyte_disjoint_arraycopy =165StubRoutines::_jbyte_disjoint_arraycopy;166StubRoutines::_arrayof_jbyte_arraycopy =167StubRoutines::_jbyte_arraycopy;168169StubRoutines::_arrayof_jshort_disjoint_arraycopy =170StubRoutines::_jshort_disjoint_arraycopy;171StubRoutines::_arrayof_jshort_arraycopy =172StubRoutines::_jshort_arraycopy;173174StubRoutines::_arrayof_jint_disjoint_arraycopy =175StubRoutines::_jint_disjoint_arraycopy;176StubRoutines::_arrayof_jint_arraycopy =177StubRoutines::_jint_arraycopy;178179StubRoutines::_arrayof_jlong_disjoint_arraycopy =180StubRoutines::_jlong_disjoint_arraycopy;181StubRoutines::_arrayof_jlong_arraycopy =182StubRoutines::_jlong_arraycopy;183184StubRoutines::_arrayof_oop_disjoint_arraycopy =185StubRoutines::_oop_disjoint_arraycopy;186StubRoutines::_arrayof_oop_arraycopy =187StubRoutines::_oop_arraycopy;188}189190static int SafeFetch32(int *adr, int errValue) {191192// set up a jump buffer; anchor the pointer to the jump buffer in tls; then193// do the pointer access. If pointer is invalid, we crash; in signal194// handler, we retrieve pointer to jmp buffer from tls, and jump back.195//196// Note: the jump buffer itself - which can get pretty large depending on197// the architecture - lives on the stack and that is fine, because we will198// not rewind the stack: either we crash, in which case signal handler199// frame is below us, or we don't crash, in which case it does not matter.200sigjmp_buf jb;201if (sigsetjmp(jb, 1)) {202// we crashed. clean up tls and return default value.203pthread_setspecific(g_jmpbuf_key, NULL);204return errValue;205} else {206// preparation phase207pthread_setspecific(g_jmpbuf_key, &jb);208}209210int value = errValue;211value = *adr;212213// all went well. clean tls.214pthread_setspecific(g_jmpbuf_key, NULL);215216return value;217}218219static intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) {220221sigjmp_buf jb;222if (sigsetjmp(jb, 1)) {223// we crashed. clean up tls and return default value.224pthread_setspecific(g_jmpbuf_key, NULL);225return errValue;226} else {227// preparation phase228pthread_setspecific(g_jmpbuf_key, &jb);229}230231intptr_t value = errValue;232value = *adr;233234// all went well. clean tls.235pthread_setspecific(g_jmpbuf_key, NULL);236237return value;238239}240241void generate_initial() {242// Generates all stubs and initializes the entry points243244// entry points that exist in all platforms Note: This is code245// that could be shared among different platforms - however the246// benefit seems to be smaller than the disadvantage of having a247// much more complicated generator structure. See also comment in248// stubRoutines.hpp.249250StubRoutines::_forward_exception_entry = ShouldNotCallThisStub();251StubRoutines::_call_stub_entry = (address) call_stub;252StubRoutines::_catch_exception_entry = ShouldNotCallThisStub();253254// atomic calls255StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub();256StubRoutines::_atomic_xchg_long_entry = ShouldNotCallThisStub();257StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub();258StubRoutines::_atomic_cmpxchg_byte_entry = ShouldNotCallThisStub();259StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub();260StubRoutines::_atomic_add_entry = ShouldNotCallThisStub();261StubRoutines::_atomic_add_long_entry = ShouldNotCallThisStub();262StubRoutines::_fence_entry = ShouldNotCallThisStub();263}264265void generate_all() {266// Generates all stubs and initializes the entry points267268// These entry points require SharedInfo::stack0 to be set up in269// non-core builds and need to be relocatable, so they each270// fabricate a RuntimeStub internally.271StubRoutines::_throw_AbstractMethodError_entry =272ShouldNotCallThisStub();273274StubRoutines::_throw_NullPointerException_at_call_entry =275ShouldNotCallThisStub();276277StubRoutines::_throw_StackOverflowError_entry =278ShouldNotCallThisStub();279280// support for verify_oop (must happen after universe_init)281StubRoutines::_verify_oop_subroutine_entry =282ShouldNotCallThisStub();283284// arraycopy stubs used by compilers285generate_arraycopy_stubs();286287// Safefetch stubs.288pthread_key_create(&g_jmpbuf_key, NULL);289StubRoutines::_safefetch32_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetch32);290StubRoutines::_safefetch32_fault_pc = NULL;291StubRoutines::_safefetch32_continuation_pc = NULL;292293StubRoutines::_safefetchN_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetchN);294StubRoutines::_safefetchN_fault_pc = NULL;295StubRoutines::_safefetchN_continuation_pc = NULL;296}297298public:299StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {300if (all) {301generate_all();302} else {303generate_initial();304}305}306};307308void StubGenerator_generate(CodeBuffer* code, bool all) {309StubGenerator g(code, all);310}311312EntryFrame *EntryFrame::build(const intptr_t* parameters,313int parameter_words,314JavaCallWrapper* call_wrapper,315TRAPS) {316317ZeroStack *stack = THREAD->zero_stack();318stack->overflow_check(header_words + parameter_words, CHECK_NULL);319320stack->push(0); // next_frame, filled in later321intptr_t *fp = stack->sp();322assert(fp - stack->sp() == next_frame_off, "should be");323324stack->push(ENTRY_FRAME);325assert(fp - stack->sp() == frame_type_off, "should be");326327stack->push((intptr_t) call_wrapper);328assert(fp - stack->sp() == call_wrapper_off, "should be");329330for (int i = 0; i < parameter_words; i++)331stack->push(parameters[i]);332333return (EntryFrame *) fp;334}335336337