< prev index next >

src/hotspot/share/prims/universalUpcallHandler.cpp

Print this page

 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

 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 #include "utilities/globalDefinitions.hpp"
 35 
 36 #define FOREIGN_ABI "jdk/internal/foreign/abi/"
 37 
 38 extern struct JavaVM_ main_vm;
 39 
 40 // When an upcall is invoked from a thread that is not attached to the VM, we need to attach it,
 41 // and then to detach it at some point later. Detaching a thread as soon as the upcall completes
 42 // is suboptimal, as the same thread could later upcall to Java again, at which point the VM would
 43 // create multiple Java views of the same native thread. For this reason, we use thread local storage
 44 // to keep track of the fact that we have attached a native thread to the VM. When the thread local
 45 // storage is destroyed (which happens when the native threads is terminated), we check if the
 46 // storage has an attached thread and, if so, we detach it from the VM.
 47 struct UpcallContext {
 48   Thread* attachedThread;
 49 
 50   ~UpcallContext() {
 51     if (attachedThread != NULL) {
 52       JavaVM_ *vm = (JavaVM *)(&main_vm);
 53       vm->functions->DetachCurrentThread(vm);
 54     }
 55   }
 56 };
 57 


 58 
 59 APPROVED_CPP_THREAD_LOCAL UpcallContext threadContext;

 60 
 61 JavaThread* ProgrammableUpcallHandler::maybe_attach_and_get_thread() {
 62   JavaThread* thread = JavaThread::current_or_null();
 63   if (thread == nullptr) {
 64     JavaVM_ *vm = (JavaVM *)(&main_vm);
 65     JNIEnv* p_env = nullptr; // unused
 66     jint result = vm->functions->AttachCurrentThreadAsDaemon(vm, (void**) &p_env, nullptr);
 67     guarantee(result == JNI_OK, "Could not attach thread for upcall. JNI error code: %d", result);

 68     thread = JavaThread::current();
 69     threadContext.attachedThread = thread;
 70     assert(!thread->has_last_Java_frame(), "newly-attached thread not expected to have last Java frame");


 71   }
 72   return thread;
 73 }
 74 
 75 void ProgrammableUpcallHandler::detach_current_thread() {
 76   JavaVM_ *vm = (JavaVM *)(&main_vm);
 77   vm->functions->DetachCurrentThread(vm);
 78 }
 79 
 80 // modelled after JavaCallWrapper::JavaCallWrapper
 81 JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* context) {
 82   JavaThread* thread = maybe_attach_and_get_thread();
 83   context->thread = thread;
 84 
 85   assert(thread->can_call_java(), "must be able to call Java");
 86 
 87   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java,
 88   // since it can potentially block.
 89   context->new_handles = JNIHandleBlock::allocate_block(thread);
 90 
 91   // clear any pending exception in thread (native calls start with no exception pending)
 92   thread->clear_pending_exception();
 93 
 94   // After this, we are officially in Java Code. This needs to be done before we change any of the thread local
 95   // info, since we cannot find oops before the new information is set up completely.
 96   ThreadStateTransition::transition_from_native(thread, _thread_in_Java, true /* check_asyncs */);
 97 
 98   context->old_handles = thread->active_handles();
 99 
100   // For the profiler, the last_Java_frame information in thread must always be in
101   // legal state. We have no last Java frame if last_Java_sp == NULL so
102   // the valid transition is to clear _last_Java_sp and then reset the rest of
103   // the (platform specific) state.
104 
105   context->jfa.copy(thread->frame_anchor());
106   thread->frame_anchor()->clear();
107 
108   debug_only(thread->inc_java_call_counter());
109   thread->set_active_handles(context->new_handles);     // install new handle block and reset Java frame linkage
110 


111   return thread;
112 }
113 
114 // modelled after JavaCallWrapper::~JavaCallWrapper
115 void ProgrammableUpcallHandler::on_exit(OptimizedEntryBlob::FrameData* context) {
116   JavaThread* thread = context->thread;
117   assert(thread == JavaThread::current(), "must still be the same thread");
118 


119   // restore previous handle block
120   thread->set_active_handles(context->old_handles);
121 
122   thread->frame_anchor()->zap();
123 
124   debug_only(thread->dec_java_call_counter());
125 
126   // Old thread-local info. has been restored. We are now back in native code.
127   ThreadStateTransition::transition_from_java(thread, _thread_in_native);
128 
129   thread->frame_anchor()->copy(&context->jfa);
130 
131   // Release handles after we are marked as being in native code again, since this
132   // operation might block
133   JNIHandleBlock::release_block(context->new_handles, thread);
134 
135   assert(!thread->has_pending_exception(), "Upcall can not throw an exception");







































136 }
137 
138 void ProgrammableUpcallHandler::handle_uncaught_exception(oop exception) {
139   ResourceMark rm;
140   // Based on CATCH macro
141   tty->print_cr("Uncaught exception:");
142   exception->print();
143   ShouldNotReachHere();
144 }
145 
146 JVM_ENTRY(jlong, PUH_AllocateOptimizedUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobject abi, jobject conv,
147                                                  jboolean needs_return_buffer, jlong ret_buf_size))
148   ResourceMark rm(THREAD);




149   Handle mh_h(THREAD, JNIHandles::resolve(mh));
150   jobject mh_j = JNIHandles::make_global(mh_h);
151 
152   oop lform = java_lang_invoke_MethodHandle::form(mh_h());
153   oop vmentry = java_lang_invoke_LambdaForm::vmentry(lform);
154   Method* entry = java_lang_invoke_MemberName::vmtarget(vmentry);
155   const methodHandle mh_entry(THREAD, entry);
156 
157   assert(entry->method_holder()->is_initialized(), "no clinit barrier");
158   CompilationPolicy::compile_if_required(mh_entry, CHECK_0);
159 
160   assert(entry->is_static(), "static only");
161   // Fill in the signature array, for the calling-convention call.
162   const int total_out_args = entry->size_of_parameters();
163   assert(total_out_args > 0, "receiver arg");
164 
165   BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_out_args);
166   BasicType ret_type;
167   {
168     int i = 0;
169     SignatureStream ss(entry->signature());
170     for (; !ss.at_return_type(); ss.next()) {
171       out_sig_bt[i++] = ss.type();  // Collect remaining bits of signature
172       if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
173         out_sig_bt[i++] = T_VOID;   // Longs & doubles take 2 Java slots
174     }
175     assert(i == total_out_args, "");
176     ret_type = ss.type();
177   }
178   // skip receiver
179   BasicType* in_sig_bt = out_sig_bt + 1;
180   int total_in_args = total_out_args - 1;
181 
182   return (jlong) ProgrammableUpcallHandler::generate_optimized_upcall_stub(
183     mh_j, entry, in_sig_bt, total_in_args, out_sig_bt, total_out_args, ret_type, abi, conv, needs_return_buffer, checked_cast<int>(ret_buf_size));
184 JVM_END
185 
186 #define CC (char*)  /*cast a literal from (const char*)*/
187 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
188 
189 static JNINativeMethod PUH_methods[] = {
190   {CC "allocateOptimizedUpcallStub", CC "(" "Ljava/lang/invoke/MethodHandle;" "L" FOREIGN_ABI "ABIDescriptor;" "L" FOREIGN_ABI "ProgrammableUpcallHandler$CallRegs;" "ZJ)J", FN_PTR(PUH_AllocateOptimizedUpcallStub)},


191 };
192 
193 /**
194  * This one function is exported, used by NativeLookup.
195  */
196 JNI_ENTRY(void, JVM_RegisterProgrammableUpcallHandlerMethods(JNIEnv *env, jclass PUH_class))
197   ThreadToNativeFromVM ttnfv(thread);
198   int status = env->RegisterNatives(PUH_class, PUH_methods, sizeof(PUH_methods)/sizeof(JNINativeMethod));
199   guarantee(status == JNI_OK && !env->ExceptionOccurred(),
200             "register jdk.internal.foreign.abi.ProgrammableUpcallHandler natives");
201 JNI_END
< prev index next >