| /* | |
| * Copyright (c) 2020, 2025, 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 "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); | |
| BasicType bt = java_lang_Class::as_BasicType(type_oop); | |
| basic_type[bt_idx++] = bt; | |
| oop reg_oop = arg_moves_oop->obj_at(i); | |
| if (reg_oop != nullptr) { | |
| input_regs.push(ForeignGlobals::parse_vmstorage(reg_oop)); | |
| } | |
| 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))); | |
| } | |
| RuntimeStub* stub = DowncallLinker::make_downcall_stub(basic_type, pslots, ret_bt, abi, | |
| input_regs, output_regs, | |
| needs_return_buffer, captured_state_mask, | |
| needs_transition); | |
| if (stub == nullptr) { | |
| return 0; | |
| } | |
| return (jlong) stub->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->ExceptionCheck(), | |
| "register jdk.internal.foreign.abi.NativeEntryPoint natives"); | |
| JNI_END |