1 /*
  2  * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
  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 it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 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 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 #include "precompiled.hpp"
 25 #include "classfile/javaClasses.hpp"
 26 #include "classfile/symbolTable.hpp"
 27 #include "classfile/systemDictionary.hpp"
 28 #include "compiler/compilationPolicy.hpp"
 29 #include "memory/resourceArea.hpp"
 30 #include "prims/universalUpcallHandler.hpp"
 31 #include "runtime/interfaceSupport.inline.hpp"
 32 #include "runtime/javaCalls.hpp"
 33 #include "runtime/jniHandles.inline.hpp"
 34 
 35 #define FOREIGN_ABI "jdk/internal/foreign/abi/"
 36 
 37 extern struct JavaVM_ main_vm;
 38 
 39 void ProgrammableUpcallHandler::upcall_helper(JavaThread* thread, jobject rec, address buff) {
 40   JavaThread* THREAD = thread; // For exception macros.
 41   ThreadInVMfromNative tiv(THREAD);
 42   const UpcallMethod& upcall_method = instance().upcall_method;
 43 
 44   ResourceMark rm(THREAD);
 45   JavaValue result(T_VOID);
 46   JavaCallArguments args(2); // long = 2 slots
 47 
 48   args.push_jobject(rec);
 49   args.push_long((jlong) buff);
 50 
 51   JavaCalls::call_static(&result, upcall_method.klass, upcall_method.name, upcall_method.sig, &args, CATCH);
 52 }
 53 
 54 JavaThread* ProgrammableUpcallHandler::maybe_attach_and_get_thread(bool* should_detach) {
 55   JavaThread* thread = JavaThread::current_or_null();
 56   if (thread == nullptr) {
 57     JavaVM_ *vm = (JavaVM *)(&main_vm);
 58     JNIEnv* p_env = nullptr; // unused
 59     jint result = vm->functions->AttachCurrentThread(vm, (void**) &p_env, nullptr);
 60     guarantee(result == JNI_OK, "Could not attach thread for upcall. JNI error code: %d", result);
 61     *should_detach = true;
 62     thread = JavaThread::current();
 63     assert(!thread->has_last_Java_frame(), "newly-attached thread not expected to have last Java frame");
 64   } else {
 65     *should_detach = false;
 66   }
 67   return thread;
 68 }
 69 
 70 void ProgrammableUpcallHandler::detach_current_thread() {
 71   JavaVM_ *vm = (JavaVM *)(&main_vm);
 72   vm->functions->DetachCurrentThread(vm);
 73 }
 74 
 75 // modelled after JavaCallWrapper::JavaCallWrapper
 76 JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* context) {
 77   JavaThread* thread = maybe_attach_and_get_thread(&context->should_detach);
 78   context->thread = thread;
 79 
 80   assert(thread->can_call_java(), "must be able to call Java");
 81 
 82   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java,
 83   // since it can potentially block.
 84   context->new_handles = JNIHandleBlock::allocate_block(thread);
 85 
 86   // clear any pending exception in thread (native calls start with no exception pending)
 87   thread->clear_pending_exception();
 88 
 89   // After this, we are officially in Java Code. This needs to be done before we change any of the thread local
 90   // info, since we cannot find oops before the new information is set up completely.
 91   ThreadStateTransition::transition_from_native(thread, _thread_in_Java, true /* check_asyncs */);
 92 
 93   context->old_handles = thread->active_handles();
 94 
 95   // For the profiler, the last_Java_frame information in thread must always be in
 96   // legal state. We have no last Java frame if last_Java_sp == NULL so
 97   // the valid transition is to clear _last_Java_sp and then reset the rest of
 98   // the (platform specific) state.
 99 
100   context->jfa.copy(thread->frame_anchor());
101   thread->frame_anchor()->clear();
102 
103   debug_only(thread->inc_java_call_counter());
104   thread->set_active_handles(context->new_handles);     // install new handle block and reset Java frame linkage
105 
106   MACOS_AARCH64_ONLY(thread->enable_wx(WXExec));
107 
108   return thread;
109 }
110 
111 // modelled after JavaCallWrapper::~JavaCallWrapper
112 void ProgrammableUpcallHandler::on_exit(OptimizedEntryBlob::FrameData* context) {
113   JavaThread* thread = context->thread;
114   assert(thread == JavaThread::current(), "must still be the same thread");
115 
116   MACOS_AARCH64_ONLY(thread->enable_wx(WXWrite));
117 
118   // restore previous handle block
119   thread->set_active_handles(context->old_handles);
120 
121   thread->frame_anchor()->zap();
122 
123   debug_only(thread->dec_java_call_counter());
124 
125   // Old thread-local info. has been restored. We are now back in native code.
126   ThreadStateTransition::transition_from_java(thread, _thread_in_native);
127 
128   thread->frame_anchor()->copy(&context->jfa);
129 
130   // Release handles after we are marked as being in native code again, since this
131   // operation might block
132   JNIHandleBlock::release_block(context->new_handles, thread);
133 
134   assert(!thread->has_pending_exception(), "Upcall can not throw an exception");
135 
136   if (context->should_detach) {
137     detach_current_thread();
138   }
139 }
140 
141 void ProgrammableUpcallHandler::attach_thread_and_do_upcall(jobject rec, address buff) {
142   bool should_detach = false;
143   JavaThread* thread = maybe_attach_and_get_thread(&should_detach);
144 
145   {
146     MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
147     upcall_helper(thread, rec, buff);
148   }
149 
150   if (should_detach) {
151     detach_current_thread();
152   }
153 }
154 
155 const ProgrammableUpcallHandler& ProgrammableUpcallHandler::instance() {
156   static ProgrammableUpcallHandler handler;
157   return handler;
158 }
159 
160 ProgrammableUpcallHandler::ProgrammableUpcallHandler() {
161   JavaThread* THREAD = JavaThread::current(); // For exception macros.
162   ResourceMark rm(THREAD);
163   Symbol* sym = SymbolTable::new_symbol(FOREIGN_ABI "ProgrammableUpcallHandler");
164   Klass* k = SystemDictionary::resolve_or_null(sym, Handle(), Handle(), CATCH);
165   k->initialize(CATCH);
166 
167   upcall_method.klass = k;
168   upcall_method.name = SymbolTable::new_symbol("invoke");
169   upcall_method.sig = SymbolTable::new_symbol("(Ljava/lang/invoke/MethodHandle;J)V");
170 
171   assert(upcall_method.klass->lookup_method(upcall_method.name, upcall_method.sig) != nullptr,
172     "Could not find upcall method: %s.%s%s", upcall_method.klass->external_name(),
173     upcall_method.name->as_C_string(), upcall_method.sig->as_C_string());
174 }
175 
176 void ProgrammableUpcallHandler::handle_uncaught_exception(oop exception) {
177   ResourceMark rm;
178   // Based on CATCH macro
179   tty->print_cr("Uncaught exception:");
180   exception->print();
181   ShouldNotReachHere();
182 }
183 
184 JVM_ENTRY(jlong, PUH_AllocateUpcallStub(JNIEnv *env, jclass unused, jobject rec, jobject abi, jobject buffer_layout))
185   Handle receiver(THREAD, JNIHandles::resolve(rec));
186   jobject global_rec = JNIHandles::make_global(receiver);
187   return (jlong) ProgrammableUpcallHandler::generate_upcall_stub(global_rec, abi, buffer_layout);
188 JNI_END
189 
190 JVM_ENTRY(jlong, PUH_AllocateOptimizedUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobject abi, jobject conv))
191   Handle mh_h(THREAD, JNIHandles::resolve(mh));
192   jobject mh_j = JNIHandles::make_global(mh_h);
193 
194   oop lform = java_lang_invoke_MethodHandle::form(mh_h());
195   oop vmentry = java_lang_invoke_LambdaForm::vmentry(lform);
196   Method* entry = java_lang_invoke_MemberName::vmtarget(vmentry);
197   const methodHandle mh_entry(THREAD, entry);
198 
199   assert(entry->method_holder()->is_initialized(), "no clinit barrier");
200   CompilationPolicy::compile_if_required(mh_entry, CHECK_0);
201 
202   return (jlong) ProgrammableUpcallHandler::generate_optimized_upcall_stub(mh_j, entry, abi, conv);
203 JVM_END
204 
205 JVM_ENTRY(jboolean, PUH_SupportsOptimizedUpcalls(JNIEnv *env, jclass unused))
206   return (jboolean) ProgrammableUpcallHandler::supports_optimized_upcalls();
207 JVM_END
208 
209 #define CC (char*)  /*cast a literal from (const char*)*/
210 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
211 
212 static JNINativeMethod PUH_methods[] = {
213   {CC "allocateUpcallStub", CC "(" "Ljava/lang/invoke/MethodHandle;" "L" FOREIGN_ABI "ABIDescriptor;" "L" FOREIGN_ABI "BufferLayout;" ")J", FN_PTR(PUH_AllocateUpcallStub)},
214   {CC "allocateOptimizedUpcallStub", CC "(" "Ljava/lang/invoke/MethodHandle;" "L" FOREIGN_ABI "ABIDescriptor;" "L" FOREIGN_ABI "ProgrammableUpcallHandler$CallRegs;" ")J", FN_PTR(PUH_AllocateOptimizedUpcallStub)},
215   {CC "supportsOptimizedUpcalls", CC "()Z", FN_PTR(PUH_SupportsOptimizedUpcalls)},
216 };
217 
218 /**
219  * This one function is exported, used by NativeLookup.
220  */
221 JNI_ENTRY(void, JVM_RegisterProgrammableUpcallHandlerMethods(JNIEnv *env, jclass PUH_class))
222   ThreadToNativeFromVM ttnfv(thread);
223   int status = env->RegisterNatives(PUH_class, PUH_methods, sizeof(PUH_methods)/sizeof(JNINativeMethod));
224   guarantee(status == JNI_OK && !env->ExceptionOccurred(),
225             "register jdk.internal.foreign.abi.ProgrammableUpcallHandler natives");
226 JNI_END