| /* |
| * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "precompiled.hpp" |
| #include "runtime/interfaceSupport.inline.hpp" |
| #include "classfile/javaClasses.inline.hpp" |
| #include "code/codeCache.hpp" |
| #include "code/vmreg.hpp" |
| #include "logging/logStream.hpp" |
| #include "memory/resourceArea.hpp" |
| #include "oops/typeArrayOop.inline.hpp" |
| #include "oops/oopCast.inline.hpp" |
| #include "prims/foreignGlobals.inline.hpp" |
| #include "prims/downcallLinker.hpp" |
| #include "runtime/jniHandles.inline.hpp" |
| |
| JNI_ENTRY(jlong, NEP_makeDowncallStub(JNIEnv* env, jclass _unused, jobject method_type, jobject jabi, |
| jobjectArray arg_moves, jobjectArray ret_moves, |
| jboolean needs_return_buffer, jint captured_state_mask, |
| jboolean needs_transition)) |
| ResourceMark rm; |
| const ABIDescriptor abi = ForeignGlobals::parse_abi_descriptor(jabi); |
| |
| oop type = JNIHandles::resolve(method_type); |
| objArrayOop arg_moves_oop = oop_cast<objArrayOop>(JNIHandles::resolve(arg_moves)); |
| objArrayOop ret_moves_oop = oop_cast<objArrayOop>(JNIHandles::resolve(ret_moves)); |
| int pcount = java_lang_invoke_MethodType::ptype_count(type); |
| int pslots = java_lang_invoke_MethodType::ptype_slot_count(type); |
| BasicType* basic_type = NEW_RESOURCE_ARRAY(BasicType, pslots); |
| |
| GrowableArray<VMStorage> input_regs(pcount); |
| for (int i = 0, bt_idx = 0; i < pcount; i++) { |
| oop type_oop = java_lang_invoke_MethodType::ptype(type, i); |
| assert(java_lang_Class::is_primitive(type_oop), "Only primitives expected"); |
| BasicType bt = java_lang_Class::primitive_type(type_oop); |
| basic_type[bt_idx++] = bt; |
| input_regs.push(ForeignGlobals::parse_vmstorage(arg_moves_oop->obj_at(i))); |
| |
| if (bt == BasicType::T_DOUBLE || bt == BasicType::T_LONG) { |
| basic_type[bt_idx++] = T_VOID; |
| // we only need these in the basic type |
| // NativeCallingConvention ignores them, but they are needed |
| // for JavaCallingConvention |
| } |
| } |
| |
| |
| jint outs = ret_moves_oop->length(); |
| GrowableArray<VMStorage> output_regs(outs); |
| oop type_oop = java_lang_invoke_MethodType::rtype(type); |
| BasicType ret_bt = java_lang_Class::primitive_type(type_oop); |
| for (int i = 0; i < outs; i++) { |
| // note that we don't care about long/double upper halfs here: |
| // we are NOT moving Java values, we are moving register-sized values |
| output_regs.push(ForeignGlobals::parse_vmstorage(ret_moves_oop->obj_at(i))); |
| } |
| |
| return (jlong) DowncallLinker::make_downcall_stub(basic_type, pslots, ret_bt, abi, |
| input_regs, output_regs, |
| needs_return_buffer, captured_state_mask, |
| needs_transition)->code_begin(); |
| JNI_END |
| |
| JNI_ENTRY(jboolean, NEP_freeDowncallStub(JNIEnv* env, jclass _unused, jlong invoker)) |
| // safe to call without code cache lock, because stub is always alive |
| CodeBlob* cb = CodeCache::find_blob((char*) invoker); |
| if (cb == nullptr) { |
| return false; |
| } |
| RuntimeStub::free(cb->as_runtime_stub()); |
| return true; |
| JNI_END |
| |
| #define CC (char*) /*cast a literal from (const char*)*/ |
| #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) |
| #define METHOD_TYPE "Ljava/lang/invoke/MethodType;" |
| #define ABI_DESC "Ljdk/internal/foreign/abi/ABIDescriptor;" |
| #define VM_STORAGE_ARR "[Ljdk/internal/foreign/abi/VMStorage;" |
| |
| static JNINativeMethod NEP_methods[] = { |
| {CC "makeDowncallStub", CC "(" METHOD_TYPE ABI_DESC VM_STORAGE_ARR VM_STORAGE_ARR "ZIZ)J", FN_PTR(NEP_makeDowncallStub)}, |
| {CC "freeDowncallStub0", CC "(J)Z", FN_PTR(NEP_freeDowncallStub)}, |
| }; |
| |
| #undef METHOD_TYPE |
| #undef ABI_DESC |
| #undef VM_STORAGE_ARR |
| |
| JNI_ENTRY(void, JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass NEP_class)) |
| ThreadToNativeFromVM ttnfv(thread); |
| int status = env->RegisterNatives(NEP_class, NEP_methods, sizeof(NEP_methods)/sizeof(JNINativeMethod)); |
| guarantee(status == JNI_OK && !env->ExceptionOccurred(), |
| "register jdk.internal.foreign.abi.NativeEntryPoint natives"); |
| JNI_END |