| /* |
| * Copyright (c) 1999, 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 "classfile/stringTable.hpp" |
| #include "classfile/symbolTable.hpp" |
| #include "classfile/systemDictionary.hpp" |
| #include "code/codeCache.hpp" |
| #include "compiler/compilerOracle.hpp" |
| #include "compiler/compileTask.hpp" |
| #include "jvm_io.h" |
| #include "memory/oopFactory.hpp" |
| #include "memory/resourceArea.hpp" |
| #include "memory/universe.hpp" |
| #include "oops/objArrayKlass.hpp" |
| #include "oops/typeArrayOop.inline.hpp" |
| #include "prims/jvmtiExport.hpp" |
| #include "runtime/deoptimization.hpp" |
| #include "runtime/jniHandles.inline.hpp" |
| #include "runtime/javaCalls.hpp" |
| #include "runtime/thread.inline.hpp" |
| #include "runtime/os.hpp" |
| #include "jvmci/jniAccessMark.inline.hpp" |
| #include "jvmci/jvmciCompiler.hpp" |
| #include "jvmci/jvmciRuntime.hpp" |
| |
| jbyte* JVMCIEnv::_serialized_saved_properties = nullptr; |
| int JVMCIEnv::_serialized_saved_properties_len = 0; |
| |
| JVMCICompileState::JVMCICompileState(CompileTask* task, JVMCICompiler* compiler): |
| _task(task), |
| _compiler(compiler), |
| _retryable(true), |
| _failure_reason(nullptr), |
| _failure_reason_on_C_heap(false) { |
| // Get Jvmti capabilities under lock to get consistent values. |
| MutexLocker mu(JvmtiThreadState_lock); |
| _jvmti_redefinition_count = JvmtiExport::redefinition_count(); |
| _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint() ? 1 : 0; |
| _jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables() ? 1 : 0; |
| _jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions() ? 1 : 0; |
| _jvmti_can_pop_frame = JvmtiExport::can_pop_frame() ? 1 : 0; |
| _target_method_is_old = _task != nullptr && _task->method()->is_old(); |
| if (task->is_blocking()) { |
| task->set_blocking_jvmci_compile_state(this); |
| } |
| } |
| |
| void JVMCICompileState::set_failure(bool retryable, const char* reason, bool reason_on_C_heap) { |
| if (_failure_reason != nullptr && _failure_reason_on_C_heap) { |
| os::free((void*) _failure_reason); |
| } |
| _failure_reason = reason; |
| _failure_reason_on_C_heap = reason_on_C_heap; |
| _retryable = retryable; |
| } |
| |
| void JVMCICompileState::notify_libjvmci_oome() { |
| const char* msg = "Out of memory initializing libjvmci or attaching it to the current thread"; |
| set_failure(true, msg); |
| _compiler->on_upcall(msg); |
| } |
| |
| // Update global JVMCI compilation ticks after 512 thread-local JVMCI compilation ticks. |
| // This mitigates the overhead of the atomic operation used for the global update. |
| #define THREAD_TICKS_PER_GLOBAL_TICKS (2 << 9) |
| #define THREAD_TICKS_PER_GLOBAL_TICKS_MASK (THREAD_TICKS_PER_GLOBAL_TICKS - 1) |
| |
| void JVMCICompileState::inc_compilation_ticks() { |
| if ((++_compilation_ticks & THREAD_TICKS_PER_GLOBAL_TICKS_MASK) == 0) { |
| _compiler->inc_global_compilation_ticks(); |
| } |
| } |
| |
| bool JVMCICompileState::jvmti_state_changed() const { |
| // Some classes were redefined |
| if (jvmti_redefinition_count() != JvmtiExport::redefinition_count()) { |
| return true; |
| } |
| if (!jvmti_can_access_local_variables() && |
| JvmtiExport::can_access_local_variables()) { |
| return true; |
| } |
| if (!jvmti_can_hotswap_or_post_breakpoint() && |
| JvmtiExport::can_hotswap_or_post_breakpoint()) { |
| return true; |
| } |
| if (!jvmti_can_post_on_exceptions() && |
| JvmtiExport::can_post_on_exceptions()) { |
| return true; |
| } |
| if (!jvmti_can_pop_frame() && |
| JvmtiExport::can_pop_frame()) { |
| return true; |
| } |
| return false; |
| } |
| |
| jbyte* JVMCIEnv::get_serialized_saved_properties(int& props_len, TRAPS) { |
| jbyte* props = _serialized_saved_properties; |
| if (props == nullptr) { |
| // load VMSupport |
| Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport(); |
| Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK_NULL); |
| |
| InstanceKlass* ik = InstanceKlass::cast(k); |
| if (ik->should_be_initialized()) { |
| ik->initialize(CHECK_NULL); |
| } |
| |
| // invoke the serializeSavedPropertiesToByteArray method |
| JavaValue result(T_OBJECT); |
| JavaCallArguments args; |
| |
| Symbol* signature = vmSymbols::void_byte_array_signature(); |
| JavaCalls::call_static(&result, |
| ik, |
| vmSymbols::serializeSavedPropertiesToByteArray_name(), |
| signature, |
| &args, |
| CHECK_NULL); |
| |
| oop res = result.get_oop(); |
| assert(res->is_typeArray(), "must be"); |
| assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be"); |
| typeArrayOop ba = typeArrayOop(res); |
| props_len = ba->length(); |
| |
| // Copy serialized saved properties from HotSpot object into C heap |
| props = NEW_C_HEAP_ARRAY(jbyte, props_len, mtJVMCI); |
| memcpy(props, ba->byte_at_addr(0), props_len); |
| |
| _serialized_saved_properties_len = props_len; |
| _serialized_saved_properties = props; |
| } else { |
| props_len = _serialized_saved_properties_len; |
| } |
| return props; |
| } |
| |
| void JVMCIEnv::copy_saved_properties(jbyte* properties, int properties_len, JVMCI_TRAPS) { |
| assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image"); |
| JavaThread* thread = JavaThread::current(); // For exception macros. |
| |
| // Copy native buffer into shared library object |
| JVMCIPrimitiveArray buf = new_byteArray(properties_len, this); |
| if (has_pending_exception()) { |
| _runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties"); |
| } |
| copy_bytes_from(properties, buf, 0, properties_len); |
| if (has_pending_exception()) { |
| _runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties"); |
| } |
| |
| // Initialize saved properties in shared library |
| jclass servicesClass = JNIJVMCI::Services::clazz(); |
| jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method(); |
| bool exception = false; |
| { |
| JNIAccessMark jni(this, thread); |
| jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject()); |
| exception = jni()->ExceptionCheck(); |
| } |
| if (exception) { |
| _runtime->fatal_exception(JVMCIENV, "Error calling jdk.vm.ci.services.Services.initializeSavedProperties"); |
| } |
| } |
| |
| void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, bool jni_enomem_is_fatal) { |
| assert(thread != nullptr, "npe"); |
| _env = nullptr; |
| _pop_frame_on_close = false; |
| _detach_on_close = false; |
| if (!UseJVMCINativeLibrary) { |
| // In HotSpot mode, JNI isn't used at all. |
| _runtime = JVMCI::java_runtime(); |
| _is_hotspot = true; |
| return; |
| } |
| |
| if (parent_env != nullptr) { |
| // If the parent JNI environment is non-null then figure out whether it |
| // is a HotSpot or shared library JNIEnv and set the state appropriately. |
| _is_hotspot = thread->jni_environment() == parent_env; |
| if (_is_hotspot) { |
| // Select the Java runtime |
| _runtime = JVMCI::java_runtime(); |
| return; |
| } |
| _runtime = thread->libjvmci_runtime(); |
| assert(_runtime != nullptr, "npe"); |
| _env = parent_env; |
| return; |
| } |
| |
| // Running in JVMCI shared library mode so ensure the shared library |
| // is loaded and initialized and get a shared library JNIEnv |
| _is_hotspot = false; |
| |
| _runtime = JVMCI::compiler_runtime(thread); |
| int create_JavaVM_err = JNI_OK; |
| _env = _runtime->init_shared_library_javavm(&create_JavaVM_err); |
| if (_env != nullptr) { |
| // Creating the JVMCI shared library VM also attaches the current thread |
| _detach_on_close = true; |
| } else if (create_JavaVM_err != JNI_OK) { |
| if (!jni_enomem_is_fatal && create_JavaVM_err == JNI_ENOMEM) { |
| _jni_enomem = true; |
| return; |
| } else { |
| fatal("JNI_CreateJavaVM failed with return value %d", create_JavaVM_err); |
| } |
| } else { |
| _runtime->GetEnv(thread, (void**)&parent_env, JNI_VERSION_1_2); |
| if (parent_env != nullptr) { |
| // Even though there's a parent JNI env, there's no guarantee |
| // it was opened by a JVMCIEnv scope and thus may not have |
| // pushed a local JNI frame. As such, we use a new JNI local |
| // frame in this scope to ensure local JNI refs are collected |
| // in a timely manner after leaving this scope. |
| _env = parent_env; |
| } else { |
| ResourceMark rm; // Thread name is resource allocated |
| JavaVMAttachArgs attach_args; |
| attach_args.version = JNI_VERSION_1_2; |
| attach_args.name = const_cast<char*>(thread->name()); |
| attach_args.group = nullptr; |
| jint attach_result = _runtime->AttachCurrentThread(thread, (void**) &_env, &attach_args); |
| if (attach_result == JNI_OK) { |
| _detach_on_close = true; |
| } else if (!jni_enomem_is_fatal && attach_result == JNI_ENOMEM) { |
| _env = nullptr; |
| _jni_enomem = true; |
| return; |
| } else { |
| fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name); |
| } |
| } |
| } |
| |
| assert(_env != nullptr, "missing env"); |
| assert(_throw_to_caller == false, "must be"); |
| |
| JNIAccessMark jni(this, thread); |
| jint result = _env->PushLocalFrame(32); |
| if (result != JNI_OK) { |
| char message[256]; |
| jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line); |
| JVMCIRuntime::fatal_exception(this, message); |
| } |
| _pop_frame_on_close = true; |
| } |
| |
| JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line): |
| _throw_to_caller(false), _file(file), _line(line), _jni_enomem(false), _compile_state(compile_state) { |
| // In case of JNI_ENOMEM, there's a good chance a subsequent attempt to create libjvmci or attach to it |
| // might succeed. Other errors most likely indicate a non-recoverable error in the JVMCI runtime. |
| bool jni_enomem_is_fatal = false; |
| init_env_mode_runtime(thread, nullptr, jni_enomem_is_fatal); |
| if (_jni_enomem) { |
| compile_state->set_failure(true, "Out of memory while attaching JVMCI compiler to current thread"); |
| } |
| } |
| |
| JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): |
| _throw_to_caller(false), _file(file), _line(line), _jni_enomem(false), _compile_state(nullptr) { |
| init_env_mode_runtime(thread, nullptr); |
| } |
| |
| JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line): |
| _throw_to_caller(true), _file(file), _line(line), _jni_enomem(false), _compile_state(nullptr) { |
| init_env_mode_runtime(thread, parent_env); |
| assert(_env == nullptr || parent_env == _env, "mismatched JNIEnvironment"); |
| } |
| |
| void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fatal, const char* file, int line) { |
| _compile_state = nullptr; |
| _throw_to_caller = false; |
| _file = file; |
| _line = line; |
| _jni_enomem = false; |
| if (is_hotspot) { |
| _env = nullptr; |
| _pop_frame_on_close = false; |
| _detach_on_close = false; |
| _is_hotspot = true; |
| _runtime = JVMCI::java_runtime(); |
| } else { |
| init_env_mode_runtime(thread, nullptr, jni_enomem_is_fatal); |
| } |
| } |
| |
| // Prints a pending exception (if any) and its stack trace to st. |
| // Also partially logs the stack trace to the JVMCI event log. |
| void JVMCIEnv::describe_pending_exception(outputStream* st) { |
| ResourceMark rm; |
| char* stack_trace = nullptr; |
| if (pending_exception_as_string(nullptr, (const char**) &stack_trace)) { |
| st->print_raw_cr(stack_trace); |
| |
| // Use up to half the lines of the JVMCI event log to |
| // show the stack trace. |
| char* cursor = stack_trace; |
| int line = 0; |
| const int max_lines = LogEventsBufferEntries / 2; |
| char* last_line = nullptr; |
| while (*cursor != '\0') { |
| char* eol = strchr(cursor, '\n'); |
| if (eol == nullptr) { |
| if (line == max_lines - 1) { |
| last_line = cursor; |
| } else if (line < max_lines) { |
| JVMCI_event_1("%s", cursor); |
| } |
| cursor = cursor + strlen(cursor); |
| } else { |
| *eol = '\0'; |
| if (line == max_lines - 1) { |
| last_line = cursor; |
| } else if (line < max_lines) { |
| JVMCI_event_1("%s", cursor); |
| } |
| cursor = eol + 1; |
| } |
| line++; |
| } |
| if (last_line != nullptr) { |
| if (line > max_lines) { |
| JVMCI_event_1("%s [elided %d more stack trace lines]", last_line, line - max_lines); |
| } else { |
| JVMCI_event_1("%s", last_line); |
| } |
| } |
| } |
| } |
| |
| bool JVMCIEnv::pending_exception_as_string(const char** to_string, const char** stack_trace) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| JVMCIObject to_string_obj; |
| JVMCIObject stack_trace_obj; |
| bool had_nested_exception = false; |
| if (!is_hotspot()) { |
| JNIAccessMark jni(this, THREAD); |
| jthrowable ex = jni()->ExceptionOccurred(); |
| if (ex != nullptr) { |
| jni()->ExceptionClear(); |
| jobjectArray pair = (jobjectArray) jni()->CallStaticObjectMethod( |
| JNIJVMCI::HotSpotJVMCIRuntime::clazz(), |
| JNIJVMCI::HotSpotJVMCIRuntime::exceptionToString_method(), |
| ex, to_string != nullptr, stack_trace != nullptr); |
| if (jni()->ExceptionCheck()) { |
| // As last resort, dump nested exception |
| jni()->ExceptionDescribe(); |
| had_nested_exception = true; |
| } else { |
| guarantee(pair != nullptr, "pair is null"); |
| int len = jni()->GetArrayLength(pair); |
| guarantee(len == 2, "bad len is %d", len); |
| if (to_string != nullptr) { |
| to_string_obj = JVMCIObject::create(jni()->GetObjectArrayElement(pair, 0), false); |
| } |
| if (stack_trace != nullptr) { |
| stack_trace_obj = JVMCIObject::create(jni()->GetObjectArrayElement(pair, 1), false); |
| } |
| } |
| } else { |
| return false; |
| } |
| } else { |
| if (HAS_PENDING_EXCEPTION) { |
| Handle exception(THREAD, PENDING_EXCEPTION); |
| CLEAR_PENDING_EXCEPTION; |
| JavaCallArguments jargs; |
| jargs.push_oop(exception); |
| jargs.push_int(to_string != nullptr); |
| jargs.push_int(stack_trace != nullptr); |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_static(&result, |
| HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), |
| vmSymbols::exceptionToString_name(), |
| vmSymbols::exceptionToString_signature(), &jargs, THREAD); |
| if (HAS_PENDING_EXCEPTION) { |
| Handle nested_exception(THREAD, PENDING_EXCEPTION); |
| CLEAR_PENDING_EXCEPTION; |
| java_lang_Throwable::print_stack_trace(nested_exception, tty); |
| // Clear and ignore any exceptions raised during printing |
| CLEAR_PENDING_EXCEPTION; |
| had_nested_exception = true; |
| } else { |
| oop pair = result.get_oop(); |
| guarantee(pair->is_objArray(), "must be"); |
| objArrayOop pair_arr = objArrayOop(pair); |
| int len = pair_arr->length(); |
| guarantee(len == 2, "bad len is %d", len); |
| if (to_string != nullptr) { |
| to_string_obj = HotSpotJVMCI::wrap(pair_arr->obj_at(0)); |
| } |
| if (stack_trace != nullptr) { |
| stack_trace_obj = HotSpotJVMCI::wrap(pair_arr->obj_at(1)); |
| } |
| } |
| } else { |
| return false; |
| } |
| } |
| if (had_nested_exception) { |
| if (to_string != nullptr) { |
| *to_string = "nested exception occurred converting exception to string"; |
| } |
| if (stack_trace != nullptr) { |
| *stack_trace = "nested exception occurred converting exception stack to string"; |
| } |
| } else { |
| if (to_string_obj.is_non_null()) { |
| *to_string = as_utf8_string(to_string_obj); |
| } |
| if (stack_trace_obj.is_non_null()) { |
| *stack_trace = as_utf8_string(stack_trace_obj); |
| } |
| } |
| return true; |
| } |
| |
| |
| // Shared code for translating an exception from HotSpot to libjvmci or vice versa. |
| class ExceptionTranslation: public StackObj { |
| protected: |
| enum DecodeFormat { |
| _encoded_ok = 0, // exception was successfully encoded into buffer |
| _buffer_alloc_fail = 1, // native memory for buffer could not be allocated |
| _encode_oome_fail = 2, // OutOfMemoryError thrown during encoding |
| _encode_fail = 3 // some other problem occured during encoding. If buffer != 0, |
| // buffer contains a `struct { u4 len; char[len] desc}` |
| // describing the problem |
| }; |
| |
| JVMCIEnv* _from_env; // Source of translation. Can be null. |
| JVMCIEnv* _to_env; // Destination of translation. Never null. |
| |
| ExceptionTranslation(JVMCIEnv* from_env, JVMCIEnv* to_env) : _from_env(from_env), _to_env(to_env) {} |
| |
| // Encodes the exception in `_from_env` into `buffer`. |
| // Where N is the number of bytes needed for the encoding, returns N if N <= `buffer_size` |
| // and the encoding was written to `buffer` otherwise returns -N. |
| virtual int encode(JavaThread* THREAD, jlong buffer, int buffer_size) = 0; |
| |
| // Decodes the exception in `buffer` in `_to_env` and throws it. |
| virtual void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) = 0; |
| |
| public: |
| void doit(JavaThread* THREAD) { |
| int buffer_size = 2048; |
| while (true) { |
| ResourceMark rm; |
| jlong buffer = (jlong) NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jbyte, buffer_size); |
| if (buffer == 0L) { |
| JVMCI_event_1("error translating exception: translation buffer allocation failed"); |
| decode(THREAD, _buffer_alloc_fail, 0L); |
| return; |
| } |
| int res = encode(THREAD, buffer, buffer_size); |
| if (_to_env->has_pending_exception()) { |
| // Propagate pending exception |
| return; |
| } |
| if (res < 0) { |
| int required_buffer_size = -res; |
| if (required_buffer_size > buffer_size) { |
| buffer_size = required_buffer_size; |
| } |
| } else { |
| decode(THREAD, _encoded_ok, buffer); |
| if (!_to_env->has_pending_exception()) { |
| _to_env->throw_InternalError("decodeAndThrowThrowable should have thrown an exception"); |
| } |
| return; |
| } |
| } |
| } |
| }; |
| |
| // Translates an exception on the HotSpot heap to an exception on the shared library heap. |
| class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation { |
| private: |
| const Handle& _throwable; |
| |
| bool handle_pending_exception(JavaThread* THREAD, jlong buffer, int buffer_size) { |
| if (HAS_PENDING_EXCEPTION) { |
| Handle throwable = Handle(THREAD, PENDING_EXCEPTION); |
| Symbol *ex_name = throwable->klass()->name(); |
| CLEAR_PENDING_EXCEPTION; |
| if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) { |
| JVMCI_event_1("error translating exception: OutOfMemoryError"); |
| decode(THREAD, _encode_oome_fail, 0L); |
| } else { |
| char* char_buffer = (char*) buffer + 4; |
| stringStream st(char_buffer, (size_t) buffer_size - 4); |
| java_lang_Throwable::print_stack_trace(throwable, &st); |
| u4 len = (u4) st.size(); |
| *((u4*) buffer) = len; |
| JVMCI_event_1("error translating exception: %s", char_buffer); |
| decode(THREAD, _encode_fail, buffer); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| int encode(JavaThread* THREAD, jlong buffer, int buffer_size) { |
| Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, THREAD); |
| if (handle_pending_exception(THREAD, buffer, buffer_size)) { |
| return 0; |
| } |
| JavaCallArguments jargs; |
| jargs.push_oop(_throwable); |
| jargs.push_long(buffer); |
| jargs.push_int(buffer_size); |
| JavaValue result(T_INT); |
| JavaCalls::call_static(&result, |
| vmSupport, |
| vmSymbols::encodeThrowable_name(), |
| vmSymbols::encodeThrowable_signature(), &jargs, THREAD); |
| if (handle_pending_exception(THREAD, buffer, buffer_size)) { |
| return 0; |
| } |
| return result.get_jint(); |
| } |
| |
| void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { |
| JNIAccessMark jni(_to_env, THREAD); |
| jni()->CallStaticVoidMethod(JNIJVMCI::VMSupport::clazz(), |
| JNIJVMCI::VMSupport::decodeAndThrowThrowable_method(), |
| format, buffer, false); |
| } |
| public: |
| HotSpotToSharedLibraryExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, const Handle& throwable) : |
| ExceptionTranslation(hotspot_env, jni_env), _throwable(throwable) {} |
| }; |
| |
| // Translates an exception on the shared library heap to an exception on the HotSpot heap. |
| class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation { |
| private: |
| jthrowable _throwable; |
| |
| int encode(JavaThread* THREAD, jlong buffer, int buffer_size) { |
| JNIAccessMark jni(_from_env, THREAD); |
| int res = jni()->CallStaticIntMethod(JNIJVMCI::VMSupport::clazz(), |
| JNIJVMCI::VMSupport::encodeThrowable_method(), |
| _throwable, buffer, buffer_size); |
| if (jni()->ExceptionCheck()) { |
| // Cannot get name of exception thrown as that can raise another exception. |
| jni()->ExceptionClear(); |
| JVMCI_event_1("error translating exception: unknown error"); |
| decode(THREAD, _encode_fail, 0L); |
| return 0; |
| } |
| return res; |
| } |
| |
| void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { |
| Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, CHECK); |
| JavaCallArguments jargs; |
| jargs.push_int(format); |
| jargs.push_long(buffer); |
| jargs.push_int(true); |
| JavaValue result(T_VOID); |
| JavaCalls::call_static(&result, |
| vmSupport, |
| vmSymbols::decodeAndThrowThrowable_name(), |
| vmSymbols::decodeAndThrowThrowable_signature(), &jargs, THREAD); |
| } |
| public: |
| SharedLibraryToHotSpotExceptionTranslation(JVMCIEnv* hotspot_env, JVMCIEnv* jni_env, jthrowable throwable) : |
| ExceptionTranslation(jni_env, hotspot_env), _throwable(throwable) {} |
| }; |
| |
| void JVMCIEnv::translate_to_jni_exception(JavaThread* THREAD, const Handle& throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) { |
| HotSpotToSharedLibraryExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD); |
| } |
| |
| void JVMCIEnv::translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) { |
| SharedLibraryToHotSpotExceptionTranslation(hotspot_env, jni_env, throwable).doit(THREAD); |
| } |
| |
| jboolean JVMCIEnv::transfer_pending_exception_to_jni(JavaThread* THREAD, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env) { |
| if (HAS_PENDING_EXCEPTION) { |
| Handle throwable = Handle(THREAD, PENDING_EXCEPTION); |
| CLEAR_PENDING_EXCEPTION; |
| translate_to_jni_exception(THREAD, throwable, hotspot_env, jni_env); |
| return true; |
| } |
| return false; |
| } |
| |
| jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer_env) { |
| if (is_hotspot()) { |
| return transfer_pending_exception_to_jni(THREAD, this, peer_env); |
| } |
| jthrowable ex = nullptr; |
| { |
| JNIAccessMark jni(this, THREAD); |
| ex = jni()->ExceptionOccurred(); |
| if (ex != nullptr) { |
| jni()->ExceptionClear(); |
| } |
| } |
| if (ex != nullptr) { |
| translate_from_jni_exception(THREAD, ex, peer_env, this); |
| return true; |
| } |
| return false; |
| } |
| |
| JVMCIEnv::~JVMCIEnv() { |
| if (_jni_enomem) { |
| return; |
| } |
| if (_throw_to_caller) { |
| if (is_hotspot()) { |
| // Nothing to do |
| } else { |
| Thread* thread = Thread::current(); |
| if (thread->is_Java_thread()) { |
| JavaThread* THREAD = JavaThread::cast(thread); // For exception macros. |
| if (HAS_PENDING_EXCEPTION) { |
| Handle throwable = Handle(THREAD, PENDING_EXCEPTION); |
| CLEAR_PENDING_EXCEPTION; |
| translate_to_jni_exception(THREAD, throwable, nullptr, this); |
| } |
| } |
| } |
| } else { |
| if (_pop_frame_on_close) { |
| // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope. |
| JNIAccessMark jni(this); |
| jni()->PopLocalFrame(nullptr); |
| } |
| |
| if (has_pending_exception()) { |
| char message[256]; |
| jio_snprintf(message, 256, "Uncaught exception exiting %s JVMCIEnv scope entered at %s:%d", |
| is_hotspot() ? "HotSpot" : "libjvmci", _file, _line); |
| JVMCIRuntime::fatal_exception(this, message); |
| } |
| |
| if (_detach_on_close) { |
| _runtime->DetachCurrentThread(JavaThread::current()); |
| } |
| } |
| } |
| |
| jboolean JVMCIEnv::has_pending_exception() { |
| if (is_hotspot()) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| return HAS_PENDING_EXCEPTION; |
| } else { |
| JNIAccessMark jni(this); |
| return jni()->ExceptionCheck(); |
| } |
| } |
| |
| void JVMCIEnv::clear_pending_exception() { |
| if (is_hotspot()) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| CLEAR_PENDING_EXCEPTION; |
| } else { |
| JNIAccessMark jni(this); |
| jni()->ExceptionClear(); |
| } |
| } |
| |
| int JVMCIEnv::get_length(JVMCIArray array) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(array)->length(); |
| } else { |
| JNIAccessMark jni(this); |
| return jni()->GetArrayLength(get_jarray(array)); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::get_object_at(JVMCIObjectArray array, int index) { |
| if (is_hotspot()) { |
| oop result = HotSpotJVMCI::resolve(array)->obj_at(index); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this); |
| jobject result = jni()->GetObjectArrayElement(get_jobjectArray(array), index); |
| return wrap(result); |
| } |
| } |
| |
| void JVMCIEnv::put_object_at(JVMCIObjectArray array, int index, JVMCIObject value) { |
| if (is_hotspot()) { |
| HotSpotJVMCI::resolve(array)->obj_at_put(index, HotSpotJVMCI::resolve(value)); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetObjectArrayElement(get_jobjectArray(array), index, get_jobject(value)); |
| } |
| } |
| |
| jboolean JVMCIEnv::get_bool_at(JVMCIPrimitiveArray array, int index) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(array)->bool_at(index); |
| } else { |
| JNIAccessMark jni(this); |
| jboolean result; |
| jni()->GetBooleanArrayRegion(array.as_jbooleanArray(), index, 1, &result); |
| return result; |
| } |
| } |
| void JVMCIEnv::put_bool_at(JVMCIPrimitiveArray array, int index, jboolean value) { |
| if (is_hotspot()) { |
| HotSpotJVMCI::resolve(array)->bool_at_put(index, value); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetBooleanArrayRegion(array.as_jbooleanArray(), index, 1, &value); |
| } |
| } |
| |
| jbyte JVMCIEnv::get_byte_at(JVMCIPrimitiveArray array, int index) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(array)->byte_at(index); |
| } else { |
| JNIAccessMark jni(this); |
| jbyte result; |
| jni()->GetByteArrayRegion(array.as_jbyteArray(), index, 1, &result); |
| return result; |
| } |
| } |
| void JVMCIEnv::put_byte_at(JVMCIPrimitiveArray array, int index, jbyte value) { |
| if (is_hotspot()) { |
| HotSpotJVMCI::resolve(array)->byte_at_put(index, value); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetByteArrayRegion(array.as_jbyteArray(), index, 1, &value); |
| } |
| } |
| |
| jint JVMCIEnv::get_int_at(JVMCIPrimitiveArray array, int index) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(array)->int_at(index); |
| } else { |
| JNIAccessMark jni(this); |
| jint result; |
| jni()->GetIntArrayRegion(array.as_jintArray(), index, 1, &result); |
| return result; |
| } |
| } |
| void JVMCIEnv::put_int_at(JVMCIPrimitiveArray array, int index, jint value) { |
| if (is_hotspot()) { |
| HotSpotJVMCI::resolve(array)->int_at_put(index, value); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetIntArrayRegion(array.as_jintArray(), index, 1, &value); |
| } |
| } |
| |
| jlong JVMCIEnv::get_long_at(JVMCIPrimitiveArray array, int index) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(array)->long_at(index); |
| } else { |
| JNIAccessMark jni(this); |
| jlong result; |
| jni()->GetLongArrayRegion(array.as_jlongArray(), index, 1, &result); |
| return result; |
| } |
| } |
| void JVMCIEnv::put_long_at(JVMCIPrimitiveArray array, int index, jlong value) { |
| if (is_hotspot()) { |
| HotSpotJVMCI::resolve(array)->long_at_put(index, value); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetLongArrayRegion(array.as_jlongArray(), index, 1, &value); |
| } |
| } |
| |
| void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length) { |
| if (length == 0) { |
| return; |
| } |
| if (is_hotspot()) { |
| memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), length); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, length, dest); |
| } |
| } |
| void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length) { |
| if (length == 0) { |
| return; |
| } |
| if (is_hotspot()) { |
| memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, length); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src); |
| } |
| } |
| |
| void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) { |
| if (length == 0) { |
| return; |
| } |
| if (is_hotspot()) { |
| memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong)); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->SetLongArrayRegion(dest.as_jlongArray(), offset, length, src); |
| } |
| } |
| |
| jboolean JVMCIEnv::is_boxing_object(BasicType type, JVMCIObject object) { |
| if (is_hotspot()) { |
| return java_lang_boxing_object::is_instance(HotSpotJVMCI::resolve(object), type); |
| } else { |
| JNIAccessMark jni(this); |
| return jni()->IsInstanceOf(get_jobject(object), JNIJVMCI::box_class(type)); |
| } |
| } |
| |
| // Get the primitive value from a Java boxing object. It's hard error to |
| // pass a non-primitive BasicType. |
| jvalue JVMCIEnv::get_boxed_value(BasicType type, JVMCIObject object) { |
| jvalue result; |
| if (is_hotspot()) { |
| if (java_lang_boxing_object::get_value(HotSpotJVMCI::resolve(object), &result) == T_ILLEGAL) { |
| ShouldNotReachHere(); |
| } |
| } else { |
| JNIAccessMark jni(this); |
| jfieldID field = JNIJVMCI::box_field(type); |
| switch (type) { |
| case T_BOOLEAN: result.z = jni()->GetBooleanField(get_jobject(object), field); break; |
| case T_BYTE: result.b = jni()->GetByteField(get_jobject(object), field); break; |
| case T_SHORT: result.s = jni()->GetShortField(get_jobject(object), field); break; |
| case T_CHAR: result.c = jni()->GetCharField(get_jobject(object), field); break; |
| case T_INT: result.i = jni()->GetIntField(get_jobject(object), field); break; |
| case T_LONG: result.j = jni()->GetLongField(get_jobject(object), field); break; |
| case T_FLOAT: result.f = jni()->GetFloatField(get_jobject(object), field); break; |
| case T_DOUBLE: result.d = jni()->GetDoubleField(get_jobject(object), field); break; |
| default: |
| ShouldNotReachHere(); |
| } |
| } |
| return result; |
| } |
| |
| // Return the BasicType of the object if it's a boxing object, otherwise return T_ILLEGAL. |
| BasicType JVMCIEnv::get_box_type(JVMCIObject object) { |
| if (is_hotspot()) { |
| return java_lang_boxing_object::basic_type(HotSpotJVMCI::resolve(object)); |
| } else { |
| JNIAccessMark jni(this); |
| jclass clazz = jni()->GetObjectClass(get_jobject(object)); |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_BOOLEAN))) return T_BOOLEAN; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_BYTE))) return T_BYTE; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_SHORT))) return T_SHORT; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_CHAR))) return T_CHAR; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_INT))) return T_INT; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_LONG))) return T_LONG; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_FLOAT))) return T_FLOAT; |
| if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_DOUBLE))) return T_DOUBLE; |
| return T_ILLEGAL; |
| } |
| } |
| |
| // Create a boxing object of the appropriate primitive type. |
| JVMCIObject JVMCIEnv::create_box(BasicType type, jvalue* value, JVMCI_TRAPS) { |
| switch (type) { |
| case T_BOOLEAN: |
| case T_BYTE: |
| case T_CHAR: |
| case T_SHORT: |
| case T_INT: |
| case T_LONG: |
| case T_FLOAT: |
| case T_DOUBLE: |
| break; |
| default: |
| JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject()); |
| } |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject())); |
| return HotSpotJVMCI::wrap(box); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject box = jni()->NewObjectA(JNIJVMCI::box_class(type), JNIJVMCI::box_constructor(type), value); |
| assert(box != nullptr, ""); |
| return wrap(box); |
| } |
| } |
| |
| const char* JVMCIEnv::as_utf8_string(JVMCIObject str) { |
| if (is_hotspot()) { |
| return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str)); |
| } else { |
| JNIAccessMark jni(this); |
| jstring jstr = str.as_jstring(); |
| int length = jni()->GetStringLength(jstr); |
| int utf8_length = jni()->GetStringUTFLength(jstr); |
| char* result = NEW_RESOURCE_ARRAY(char, utf8_length + 1); |
| jni()->GetStringUTFRegion(jstr, 0, length, result); |
| return result; |
| } |
| } |
| |
| #define DO_THROW(name) \ |
| void JVMCIEnv::throw_##name(const char* msg) { \ |
| if (is_hotspot()) { \ |
| JavaThread* THREAD = JavaThread::current(); \ |
| THROW_MSG(HotSpotJVMCI::name::symbol(), msg); \ |
| } else { \ |
| JNIAccessMark jni(this); \ |
| jni()->ThrowNew(JNIJVMCI::name::clazz(), msg); \ |
| } \ |
| } |
| |
| DO_THROW(InternalError) |
| DO_THROW(ArrayIndexOutOfBoundsException) |
| DO_THROW(IllegalStateException) |
| DO_THROW(NullPointerException) |
| DO_THROW(IllegalArgumentException) |
| DO_THROW(InvalidInstalledCodeException) |
| DO_THROW(UnsatisfiedLinkError) |
| DO_THROW(UnsupportedOperationException) |
| DO_THROW(OutOfMemoryError) |
| DO_THROW(ClassNotFoundException) |
| |
| #undef DO_THROW |
| |
| void JVMCIEnv::fthrow_error(const char* file, int line, const char* format, ...) { |
| const int max_msg_size = 1024; |
| va_list ap; |
| va_start(ap, format); |
| char msg[max_msg_size]; |
| os::vsnprintf(msg, max_msg_size, format, ap); |
| va_end(ap); |
| JavaThread* THREAD = JavaThread::current(); |
| if (is_hotspot()) { |
| Handle h_loader = Handle(); |
| Handle h_protection_domain = Handle(); |
| Exceptions::_throw_msg(THREAD, file, line, vmSymbols::jdk_vm_ci_common_JVMCIError(), msg, h_loader, h_protection_domain); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jni()->ThrowNew(JNIJVMCI::JVMCIError::clazz(), msg); |
| } |
| } |
| |
| jboolean JVMCIEnv::call_HotSpotJVMCIRuntime_isGCSupported (JVMCIObject runtime, jint gcIdentifier) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); |
| jargs.push_int(gcIdentifier); |
| JavaValue result(T_BOOLEAN); |
| JavaCalls::call_special(&result, |
| HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), |
| vmSymbols::isGCSupported_name(), |
| vmSymbols::int_bool_signature(), &jargs, CHECK_0); |
| return result.get_jboolean(); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jboolean result = jni()->CallNonvirtualBooleanMethod(runtime.as_jobject(), |
| JNIJVMCI::HotSpotJVMCIRuntime::clazz(), |
| JNIJVMCI::HotSpotJVMCIRuntime::isGCSupported_method(), |
| gcIdentifier); |
| if (jni()->ExceptionCheck()) { |
| return false; |
| } |
| return result; |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_compileMethod (JVMCIObject runtime, JVMCIObject method, int entry_bci, |
| jlong compile_state, int id) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(method))); |
| jargs.push_int(entry_bci); |
| jargs.push_long(compile_state); |
| jargs.push_int(id); |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_special(&result, |
| HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), |
| vmSymbols::compileMethod_name(), |
| vmSymbols::compileMethod_signature(), &jargs, CHECK_(JVMCIObject())); |
| return wrap(result.get_oop()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->CallNonvirtualObjectMethod(runtime.as_jobject(), |
| JNIJVMCI::HotSpotJVMCIRuntime::clazz(), |
| JNIJVMCI::HotSpotJVMCIRuntime::compileMethod_method(), |
| method.as_jobject(), entry_bci, compile_state, id); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| void JVMCIEnv::call_HotSpotJVMCIRuntime_bootstrapFinished (JVMCIObject runtime, JVMCIEnv* JVMCIENV) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); |
| JavaValue result(T_VOID); |
| JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::bootstrapFinished_name(), vmSymbols::void_method_signature(), &jargs, CHECK); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::bootstrapFinished_method()); |
| |
| } |
| } |
| |
| void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| HandleMark hm(THREAD); |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); |
| JavaValue result(T_VOID); |
| JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), &jargs, THREAD); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::shutdown_method()); |
| } |
| if (has_pending_exception()) { |
| // This should never happen as HotSpotJVMCIRuntime.shutdown() should |
| // handle all exceptions. |
| describe_pending_exception(tty); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_runtime (JVMCIEnv* JVMCIENV) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::runtime_name(), vmSymbols::runtime_signature(), &jargs, CHECK_(JVMCIObject())); |
| return wrap(result.get_oop()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::runtime_method()); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::call_JVMCI_getRuntime (JVMCIEnv* JVMCIENV) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_static(&result, HotSpotJVMCI::JVMCI::klass(), vmSymbols::getRuntime_name(), vmSymbols::getRuntime_signature(), &jargs, CHECK_(JVMCIObject())); |
| return wrap(result.get_oop()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::JVMCI::clazz(), JNIJVMCI::JVMCI::getRuntime_method()); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_getCompiler (JVMCIObject runtime, JVMCIEnv* JVMCIENV) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_virtual(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::getCompiler_name(), vmSymbols::getCompiler_signature(), &jargs, CHECK_(JVMCIObject())); |
| return wrap(result.get_oop()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->CallObjectMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::getCompiler_method()); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| void JVMCIEnv::call_HotSpotJVMCIRuntime_postTranslation(JVMCIObject object, JVMCIEnv* JVMCIENV) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(object))); |
| JavaValue result(T_VOID); |
| JavaCalls::call_static(&result, |
| HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), |
| vmSymbols::postTranslation_name(), |
| vmSymbols::object_void_signature(), &jargs, CHECK); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jni()->CallStaticVoidMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), |
| JNIJVMCI::HotSpotJVMCIRuntime::postTranslation_method(), |
| object.as_jobject()); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::call_JavaConstant_forPrimitive(jchar type_char, jlong value, JVMCI_TRAPS) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaCallArguments jargs; |
| jargs.push_int(type_char); |
| jargs.push_long(value); |
| JavaValue result(T_OBJECT); |
| JavaCalls::call_static(&result, |
| HotSpotJVMCI::JavaConstant::klass(), |
| vmSymbols::forPrimitive_name(), |
| vmSymbols::forPrimitive_signature(), &jargs, CHECK_(JVMCIObject())); |
| return wrap(result.get_oop()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(), |
| JNIJVMCI::JavaConstant::forPrimitive_method(), |
| type_char, value); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::get_jvmci_primitive_type(BasicType type) { |
| JVMCIObjectArray primitives = get_HotSpotResolvedPrimitiveType_primitives(); |
| JVMCIObject result = get_object_at(primitives, type); |
| return result; |
| } |
| |
| JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| Symbol* file_name_sym; |
| int line_number; |
| java_lang_StackTraceElement::decode(method, bci, file_name_sym, line_number, CHECK_(JVMCIObject())); |
| |
| Symbol* method_name_sym = method->name(); |
| InstanceKlass* holder = method->method_holder(); |
| const char* declaring_class_str = holder->external_name(); |
| |
| if (is_hotspot()) { |
| HotSpotJVMCI::StackTraceElement::klass()->initialize(CHECK_(JVMCIObject())); |
| oop objOop = HotSpotJVMCI::StackTraceElement::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| Handle obj = Handle(THREAD, objOop); |
| |
| oop declaring_class = StringTable::intern((char*) declaring_class_str, CHECK_(JVMCIObject())); |
| HotSpotJVMCI::StackTraceElement::set_declaringClass(this, obj(), declaring_class); |
| |
| oop method_name = StringTable::intern(method_name_sym, CHECK_(JVMCIObject())); |
| HotSpotJVMCI::StackTraceElement::set_methodName(this, obj(), method_name); |
| |
| if (file_name_sym != nullptr) { |
| oop file_name = StringTable::intern(file_name_sym, CHECK_(JVMCIObject())); |
| HotSpotJVMCI::StackTraceElement::set_fileName(this, obj(), file_name); |
| } |
| HotSpotJVMCI::StackTraceElement::set_lineNumber(this, obj(), line_number); |
| return wrap(obj()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject declaring_class = jni()->NewStringUTF(declaring_class_str); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| jobject method_name = jni()->NewStringUTF(method_name_sym->as_C_string()); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| jobject file_name = nullptr; |
| if (file_name_sym != nullptr) { |
| file_name = jni()->NewStringUTF(file_name_sym->as_C_string()); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| } |
| |
| jobject result = jni()->NewObject(JNIJVMCI::StackTraceElement::clazz(), |
| JNIJVMCI::StackTraceElement::constructor(), |
| declaring_class, method_name, file_name, line_number); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_HotSpotNmethod(const methodHandle& method, const char* name, jboolean isDefault, jlong compileId, JVMCI_TRAPS) { |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| |
| JVMCIObject methodObject = get_jvmci_method(method, JVMCI_CHECK_(JVMCIObject())); |
| |
| if (is_hotspot()) { |
| InstanceKlass* ik = InstanceKlass::cast(HotSpotJVMCI::HotSpotNmethod::klass()); |
| if (ik->should_be_initialized()) { |
| ik->initialize(CHECK_(JVMCIObject())); |
| } |
| oop obj = ik->allocate_instance(CHECK_(JVMCIObject())); |
| Handle obj_h(THREAD, obj); |
| Handle nameStr = java_lang_String::create_from_str(name, CHECK_(JVMCIObject())); |
| |
| // Call constructor |
| JavaCallArguments jargs; |
| jargs.push_oop(obj_h); |
| jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(methodObject))); |
| jargs.push_oop(nameStr); |
| jargs.push_int(isDefault); |
| jargs.push_long(compileId); |
| JavaValue result(T_VOID); |
| JavaCalls::call_special(&result, ik, |
| vmSymbols::object_initializer_name(), |
| vmSymbols::method_string_bool_long_signature(), |
| &jargs, CHECK_(JVMCIObject())); |
| return wrap(obj_h()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject nameStr = name == nullptr ? nullptr : jni()->NewStringUTF(name); |
| if (jni()->ExceptionCheck()) { |
| return JVMCIObject(); |
| } |
| |
| jobject result = jni()->NewObject(JNIJVMCI::HotSpotNmethod::clazz(), |
| JNIJVMCI::HotSpotNmethod::constructor(), |
| methodObject.as_jobject(), nameStr, isDefault); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::make_local(JVMCIObject object) { |
| if (object.is_null()) { |
| return JVMCIObject(); |
| } |
| if (is_hotspot()) { |
| return wrap(JNIHandles::make_local(HotSpotJVMCI::resolve(object))); |
| } else { |
| JNIAccessMark jni(this); |
| return wrap(jni()->NewLocalRef(object.as_jobject())); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::make_global(JVMCIObject object) { |
| if (object.is_null()) { |
| return JVMCIObject(); |
| } |
| if (is_hotspot()) { |
| return wrap(JNIHandles::make_global(Handle(Thread::current(), HotSpotJVMCI::resolve(object)))); |
| } else { |
| JNIAccessMark jni(this); |
| return wrap(jni()->NewGlobalRef(object.as_jobject())); |
| } |
| } |
| |
| void JVMCIEnv::destroy_local(JVMCIObject object) { |
| if (is_hotspot()) { |
| JNIHandles::destroy_local(object.as_jobject()); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->DeleteLocalRef(object.as_jobject()); |
| } |
| } |
| |
| void JVMCIEnv::destroy_global(JVMCIObject object) { |
| if (is_hotspot()) { |
| JNIHandles::destroy_global(object.as_jobject()); |
| } else { |
| JNIAccessMark jni(this); |
| jni()->DeleteGlobalRef(object.as_jobject()); |
| } |
| } |
| |
| const char* JVMCIEnv::klass_name(JVMCIObject object) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(object)->klass()->signature_name(); |
| } else { |
| JVMCIObject name; |
| { |
| JNIAccessMark jni(this); |
| jclass jcl = jni()->GetObjectClass(object.as_jobject()); |
| jobject result = jni()->CallObjectMethod(jcl, JNIJVMCI::Class_getName_method()); |
| name = JVMCIObject::create(result, is_hotspot()); |
| } |
| return as_utf8_string(name); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::get_jvmci_method(const methodHandle& method, JVMCI_TRAPS) { |
| JVMCIObject method_object; |
| if (method() == nullptr) { |
| return method_object; |
| } |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| JVMCIKlassHandle holder_klass(THREAD, method->method_holder()); |
| JVMCIObject holder = get_jvmci_type(holder_klass, JVMCI_CHECK_(JVMCIObject())); |
| |
| CompilerOracle::tag_blackhole_if_possible(method); |
| |
| jmetadata handle = _runtime->allocate_handle(method); |
| jboolean exception = false; |
| if (is_hotspot()) { |
| JavaValue result(T_OBJECT); |
| JavaCallArguments args; |
| args.push_long((jlong) handle); |
| args.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(holder))); |
| JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotResolvedJavaMethodImpl::klass(), |
| vmSymbols::fromMetaspace_name(), |
| vmSymbols::method_fromMetaspace_signature(), &args, THREAD); |
| if (HAS_PENDING_EXCEPTION) { |
| exception = true; |
| } else { |
| method_object = wrap(result.get_oop()); |
| } |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| method_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedJavaMethodImpl::clazz(), |
| JNIJVMCI::HotSpotResolvedJavaMethodImpl_fromMetaspace_method(), |
| (jlong) handle, holder.as_jobject())); |
| exception = jni()->ExceptionCheck(); |
| } |
| |
| if (exception) { |
| _runtime->release_handle(handle); |
| return JVMCIObject(); |
| } |
| |
| assert(asMethod(method_object) == method(), "must be"); |
| if (get_HotSpotResolvedJavaMethodImpl_methodHandle(method_object) != (jlong) handle) { |
| _runtime->release_handle(handle); |
| } |
| assert(!method_object.is_null(), "must be"); |
| return method_object; |
| } |
| |
| JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS) { |
| JVMCIObject type; |
| if (klass.is_null()) { |
| return type; |
| } |
| |
| guarantee(klass->is_klass(), "must be valid klass"); |
| guarantee(klass->is_loader_alive(), "klass must be alive"); |
| |
| jlong pointer = (jlong) klass(); |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| jboolean exception = false; |
| if (is_hotspot()) { |
| JavaValue result(T_OBJECT); |
| JavaCallArguments args; |
| args.push_long(pointer); |
| JavaCalls::call_static(&result, |
| HotSpotJVMCI::HotSpotResolvedObjectTypeImpl::klass(), |
| vmSymbols::fromMetaspace_name(), |
| vmSymbols::klass_fromMetaspace_signature(), &args, THREAD); |
| |
| if (HAS_PENDING_EXCEPTION) { |
| exception = true; |
| } else { |
| type = wrap(result.get_oop()); |
| } |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| |
| HandleMark hm(THREAD); |
| type = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedObjectTypeImpl::clazz(), |
| JNIJVMCI::HotSpotResolvedObjectTypeImpl_fromMetaspace_method(), |
| pointer)); |
| exception = jni()->ExceptionCheck(); |
| } |
| if (exception) { |
| return JVMCIObject(); |
| } |
| |
| assert(type.is_non_null(), "must have result"); |
| return type; |
| } |
| |
| JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMCI_TRAPS) { |
| JVMCIObject cp_object; |
| jmetadata handle = _runtime->allocate_handle(cp); |
| jboolean exception = false; |
| JavaThread* THREAD = JVMCI::compilation_tick(JavaThread::current()); // For exception macros. |
| if (is_hotspot()) { |
| JavaValue result(T_OBJECT); |
| JavaCallArguments args; |
| args.push_long((jlong) handle); |
| JavaCalls::call_static(&result, |
| HotSpotJVMCI::HotSpotConstantPool::klass(), |
| vmSymbols::fromMetaspace_name(), |
| vmSymbols::constantPool_fromMetaspace_signature(), &args, THREAD); |
| if (HAS_PENDING_EXCEPTION) { |
| exception = true; |
| } else { |
| cp_object = wrap(result.get_oop()); |
| } |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| cp_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotConstantPool::clazz(), |
| JNIJVMCI::HotSpotConstantPool_fromMetaspace_method(), |
| (jlong) handle)); |
| exception = jni()->ExceptionCheck(); |
| } |
| |
| if (exception) { |
| _runtime->release_handle(handle); |
| return JVMCIObject(); |
| } |
| |
| assert(!cp_object.is_null(), "must be"); |
| // Constant pools aren't cached so this is always a newly created object using the handle |
| assert(get_HotSpotConstantPool_constantPoolHandle(cp_object) == (jlong) handle, "must use same handle"); |
| return cp_object; |
| } |
| |
| JVMCIPrimitiveArray JVMCIEnv::new_booleanArray(int length, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| typeArrayOop result = oopFactory::new_boolArray(length, CHECK_(JVMCIObject())); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jbooleanArray result = jni()->NewBooleanArray(length); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| typeArrayOop result = oopFactory::new_byteArray(length, CHECK_(JVMCIObject())); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jbyteArray result = jni()->NewByteArray(length); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject())); |
| objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject())); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), nullptr); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| typeArrayOop result = oopFactory::new_intArray(length, CHECK_(JVMCIObject())); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jintArray result = jni()->NewIntArray(length); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIPrimitiveArray JVMCIEnv::new_longArray(int length, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| typeArrayOop result = oopFactory::new_longArray(length, CHECK_(JVMCIObject())); |
| return wrap(result); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jlongArray result = jni()->NewLongArray(length); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| HotSpotJVMCI::VMField::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::VMField::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| HotSpotJVMCI::VMField::set_name(this, obj, HotSpotJVMCI::resolve(name)); |
| HotSpotJVMCI::VMField::set_type(this, obj, HotSpotJVMCI::resolve(type)); |
| HotSpotJVMCI::VMField::set_offset(this, obj, offset); |
| HotSpotJVMCI::VMField::set_address(this, obj, address); |
| HotSpotJVMCI::VMField::set_value(this, obj, HotSpotJVMCI::resolve(value)); |
| return wrap(obj); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->NewObject(JNIJVMCI::VMField::clazz(), |
| JNIJVMCI::VMField::constructor(), |
| get_jobject(name), get_jobject(type), offset, address, get_jobject(value)); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| HotSpotJVMCI::VMFlag::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::VMFlag::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| HotSpotJVMCI::VMFlag::set_name(this, obj, HotSpotJVMCI::resolve(name)); |
| HotSpotJVMCI::VMFlag::set_type(this, obj, HotSpotJVMCI::resolve(type)); |
| HotSpotJVMCI::VMFlag::set_value(this, obj, HotSpotJVMCI::resolve(value)); |
| return wrap(obj); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->NewObject(JNIJVMCI::VMFlag::clazz(), |
| JNIJVMCI::VMFlag::constructor(), |
| get_jobject(name), get_jobject(type), get_jobject(value)); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| HotSpotJVMCI::VMIntrinsicMethod::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::VMIntrinsicMethod::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| HotSpotJVMCI::VMIntrinsicMethod::set_declaringClass(this, obj, HotSpotJVMCI::resolve(declaringClass)); |
| HotSpotJVMCI::VMIntrinsicMethod::set_name(this, obj, HotSpotJVMCI::resolve(name)); |
| HotSpotJVMCI::VMIntrinsicMethod::set_descriptor(this, obj, HotSpotJVMCI::resolve(descriptor)); |
| HotSpotJVMCI::VMIntrinsicMethod::set_id(this, obj, id); |
| return wrap(obj); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->NewObject(JNIJVMCI::VMIntrinsicMethod::clazz(), |
| JNIJVMCI::VMIntrinsicMethod::constructor(), |
| get_jobject(declaringClass), get_jobject(name), get_jobject(descriptor), id); |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_HotSpotStackFrameReference(JVMCI_TRAPS) { |
| if (is_hotspot()) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| return wrap(obj); |
| } else { |
| ShouldNotReachHere(); |
| return JVMCIObject(); |
| } |
| } |
| JVMCIObject JVMCIEnv::new_JVMCIError(JVMCI_TRAPS) { |
| if (is_hotspot()) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| HotSpotJVMCI::JVMCIError::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::JVMCIError::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| return wrap(obj); |
| } else { |
| ShouldNotReachHere(); |
| return JVMCIObject(); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::new_FieldInfo(FieldInfo* fieldinfo, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| HotSpotJVMCI::FieldInfo::klass()->initialize(CHECK_(JVMCIObject())); |
| oop obj = HotSpotJVMCI::FieldInfo::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| Handle obj_h(THREAD, obj); |
| HotSpotJVMCI::FieldInfo::set_nameIndex(JVMCIENV, obj_h(), (jint)fieldinfo->name_index()); |
| HotSpotJVMCI::FieldInfo::set_signatureIndex(JVMCIENV, obj_h(), (jint)fieldinfo->signature_index()); |
| HotSpotJVMCI::FieldInfo::set_offset(JVMCIENV, obj_h(), (jint)fieldinfo->offset()); |
| HotSpotJVMCI::FieldInfo::set_classfileFlags(JVMCIENV, obj_h(), (jint)fieldinfo->access_flags().as_int()); |
| HotSpotJVMCI::FieldInfo::set_internalFlags(JVMCIENV, obj_h(), (jint)fieldinfo->field_flags().as_uint()); |
| HotSpotJVMCI::FieldInfo::set_initializerIndex(JVMCIENV, obj_h(), (jint)fieldinfo->initializer_index()); |
| return wrap(obj_h()); |
| } else { |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->NewObject(JNIJVMCI::FieldInfo::clazz(), |
| JNIJVMCI::FieldInfo::constructor(), |
| (jint)fieldinfo->name_index(), |
| (jint)fieldinfo->signature_index(), |
| (jint)fieldinfo->offset(), |
| (jint)fieldinfo->access_flags().as_int(), |
| (jint)fieldinfo->field_flags().as_uint(), |
| (jint)fieldinfo->initializer_index()); |
| |
| return wrap(result); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont_register) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| Handle obj = Handle(THREAD, objOop); |
| if (obj.is_null()) { |
| return JVMCIObject(); |
| } |
| if (is_hotspot()) { |
| HotSpotJVMCI::DirectHotSpotObjectConstantImpl::klass()->initialize(CHECK_(JVMCIObject())); |
| oop constant = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::klass()->allocate_instance(CHECK_(JVMCIObject())); |
| HotSpotJVMCI::DirectHotSpotObjectConstantImpl::set_object(this, constant, obj()); |
| HotSpotJVMCI::HotSpotObjectConstantImpl::set_compressed(this, constant, compressed); |
| return wrap(constant); |
| } else { |
| jlong handle = make_oop_handle(obj); |
| JNIAccessMark jni(this, THREAD); |
| jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(), |
| JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(), |
| handle, compressed, dont_register); |
| return wrap(result); |
| } |
| } |
| |
| |
| Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) { |
| if (constant.is_null()) { |
| return Handle(); |
| } |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type"); |
| oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant)); |
| return Handle(THREAD, obj); |
| } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) { |
| jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); |
| if (object_handle == 0L) { |
| JVMCI_THROW_MSG_(NullPointerException, "Foreign object reference has been cleared", Handle()); |
| } |
| oop result = resolve_oop_handle(object_handle); |
| if (result == nullptr) { |
| JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly null", Handle()); |
| } |
| return Handle(THREAD, result); |
| } else { |
| JVMCI_THROW_MSG_(IllegalArgumentException, "DirectHotSpotObjectConstantImpl shouldn't reach JVMCI in SVM mode", Handle()); |
| } |
| } |
| |
| JVMCIObject JVMCIEnv::wrap(jobject object) { |
| return JVMCIObject::create(object, is_hotspot()); |
| } |
| |
| jlong JVMCIEnv::make_oop_handle(const Handle& obj) { |
| assert(!obj.is_null(), "should only create handle for non-null oops"); |
| return _runtime->make_oop_handle(obj); |
| } |
| |
| oop JVMCIEnv::resolve_oop_handle(jlong oopHandle) { |
| assert(oopHandle != 0, "should be a valid handle"); |
| oop obj = NativeAccess<>::oop_load(reinterpret_cast<oop*>(oopHandle)); |
| if (obj != nullptr) { |
| guarantee(oopDesc::is_oop_or_null(obj), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj)); |
| } |
| return obj; |
| } |
| |
| JVMCIObject JVMCIEnv::create_string(const char* str, JVMCI_TRAPS) { |
| JavaThread* THREAD = JavaThread::current(); // For exception macros. |
| if (is_hotspot()) { |
| Handle result = java_lang_String::create_from_str(str, CHECK_(JVMCIObject())); |
| return HotSpotJVMCI::wrap(result()); |
| } else { |
| jobject result; |
| jboolean exception = false; |
| { |
| JNIAccessMark jni(this, THREAD); |
| result = jni()->NewStringUTF(str); |
| exception = jni()->ExceptionCheck(); |
| } |
| return wrap(result); |
| } |
| } |
| |
| bool JVMCIEnv::equals(JVMCIObject a, JVMCIObject b) { |
| if (is_hotspot()) { |
| return HotSpotJVMCI::resolve(a) == HotSpotJVMCI::resolve(b); |
| } else { |
| JNIAccessMark jni(this); |
| return jni()->IsSameObject(a.as_jobject(), b.as_jobject()) != 0; |
| } |
| } |
| |
| BasicType JVMCIEnv::typeCharToBasicType(jchar ch, JVMCI_TRAPS) { |
| switch(ch) { |
| case 'Z': return T_BOOLEAN; |
| case 'B': return T_BYTE; |
| case 'S': return T_SHORT; |
| case 'C': return T_CHAR; |
| case 'I': return T_INT; |
| case 'F': return T_FLOAT; |
| case 'J': return T_LONG; |
| case 'D': return T_DOUBLE; |
| case 'A': return T_OBJECT; |
| case '-': return T_ILLEGAL; |
| default: |
| JVMCI_ERROR_(T_ILLEGAL, "unexpected type char: %c", ch); |
| } |
| } |
| |
| BasicType JVMCIEnv::kindToBasicType(JVMCIObject kind, JVMCI_TRAPS) { |
| if (kind.is_null()) { |
| JVMCI_THROW_(NullPointerException, T_ILLEGAL); |
| } |
| jchar ch = get_JavaKind_typeChar(kind); |
| BasicType bt = typeCharToBasicType(ch, JVMCI_CHECK_(T_ILLEGAL)); |
| return bt; |
| } |
| |
| void JVMCIEnv::initialize_installed_code(JVMCIObject installed_code, CodeBlob* cb, JVMCI_TRAPS) { |
| // Ensure that all updates to the InstalledCode fields are consistent. |
| if (get_InstalledCode_address(installed_code) != 0) { |
| JVMCI_THROW_MSG(InternalError, "InstalledCode instance already in use"); |
| } |
| if (!isa_HotSpotInstalledCode(installed_code)) { |
| JVMCI_THROW_MSG(InternalError, "InstalledCode instance must be a subclass of HotSpotInstalledCode"); |
| } |
| |
| // Ignore the version which can stay at 0 |
| if (cb->is_nmethod()) { |
| nmethod* nm = cb->as_nmethod_or_null(); |
| if (nm->is_in_use()) { |
| set_InstalledCode_entryPoint(installed_code, (jlong) nm->verified_entry_point()); |
| } |
| } else { |
| set_InstalledCode_entryPoint(installed_code, (jlong) cb->code_begin()); |
| } |
| set_InstalledCode_address(installed_code, (jlong) cb); |
| set_HotSpotInstalledCode_size(installed_code, cb->size()); |
| set_HotSpotInstalledCode_codeStart(installed_code, (jlong) cb->code_begin()); |
| set_HotSpotInstalledCode_codeSize(installed_code, cb->code_size()); |
| } |
| |
| |
| void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, bool deoptimize, JVMCI_TRAPS) { |
| if (mirror.is_null()) { |
| JVMCI_THROW(NullPointerException); |
| } |
| |
| nmethod* nm = JVMCIENV->get_nmethod(mirror); |
| if (nm == nullptr) { |
| // Nothing to do |
| return; |
| } |
| |
| Thread* current = Thread::current(); |
| if (!mirror.is_hotspot() && !current->is_Java_thread()) { |
| // Calling back into native might cause the execution to block, so only allow this when calling |
| // from a JavaThread, which is the normal case anyway. |
| JVMCI_THROW_MSG(IllegalArgumentException, |
| "Cannot invalidate HotSpotNmethod object in shared library VM heap from non-JavaThread"); |
| } |
| |
| if (!deoptimize) { |
| // Prevent future executions of the nmethod but let current executions complete. |
| nm->make_not_entrant(); |
| |
| // Do not clear the address field here as the Java code may still |
| // want to later call this method with deoptimize == true. That requires |
| // the address field to still be pointing at the nmethod. |
| } else { |
| // Deoptimize the nmethod immediately. |
| DeoptimizationScope deopt_scope; |
| deopt_scope.mark(nm); |
| nm->make_not_entrant(); |
| nm->make_deoptimized(); |
| deopt_scope.deoptimize_marked(); |
| |
| // A HotSpotNmethod instance can only reference a single nmethod |
| // during its lifetime so simply clear it here. |
| set_InstalledCode_address(mirror, 0); |
| } |
| } |
| |
| Klass* JVMCIEnv::asKlass(JVMCIObject obj) { |
| return (Klass*) get_HotSpotResolvedObjectTypeImpl_klassPointer(obj); |
| } |
| |
| Method* JVMCIEnv::asMethod(JVMCIObject obj) { |
| Method** methodHandle = (Method**) get_HotSpotResolvedJavaMethodImpl_methodHandle(obj); |
| return *methodHandle; |
| } |
| |
| ConstantPool* JVMCIEnv::asConstantPool(JVMCIObject obj) { |
| ConstantPool** constantPoolHandle = (ConstantPool**) get_HotSpotConstantPool_constantPoolHandle(obj); |
| return *constantPoolHandle; |
| } |
| |
| MethodData* JVMCIEnv::asMethodData(JVMCIObject obj) { |
| return (MethodData*) get_HotSpotMethodData_methodDataPointer(obj); |
| } |
| |
| // Lookup an nmethod with a matching base and compile id |
| nmethod* JVMCIEnv::lookup_nmethod(address code, jlong compile_id_snapshot) { |
| if (code == nullptr) { |
| return nullptr; |
| } |
| |
| CodeBlob* cb = CodeCache::find_blob(code); |
| if (cb == (CodeBlob*) code) { |
| nmethod* nm = cb->as_nmethod_or_null(); |
| if (nm != nullptr && (compile_id_snapshot == 0 || nm->compile_id() == compile_id_snapshot)) { |
| return nm; |
| } |
| } |
| return nullptr; |
| } |
| |
| |
| CodeBlob* JVMCIEnv::get_code_blob(JVMCIObject obj) { |
| address code = (address) get_InstalledCode_address(obj); |
| if (code == nullptr) { |
| return nullptr; |
| } |
| if (isa_HotSpotNmethod(obj)) { |
| jlong compile_id_snapshot = get_HotSpotNmethod_compileIdSnapshot(obj); |
| nmethod* nm = lookup_nmethod(code, compile_id_snapshot); |
| if (nm != nullptr && compile_id_snapshot != 0L && nm->is_not_entrant()) { |
| // Zero the entry point so that the nmethod |
| // cannot be invoked by the mirror but can |
| // still be deoptimized. |
| set_InstalledCode_entryPoint(obj, 0); |
| // Refetch the nmethod since the previous call will be a safepoint in libjvmci |
| nm = lookup_nmethod(code, compile_id_snapshot); |
| } |
| |
| if (nm == nullptr) { |
| // The HotSpotNmethod was pointing at some nmethod but the nmethod is no longer valid, so |
| // clear the InstalledCode fields of this HotSpotNmethod so that it no longer refers to a |
| // nmethod in the code cache. |
| set_InstalledCode_address(obj, 0); |
| set_InstalledCode_entryPoint(obj, 0); |
| set_HotSpotInstalledCode_codeStart(obj, 0); |
| } |
| return nm; |
| } |
| |
| CodeBlob* cb = (CodeBlob*) code; |
| assert(!cb->is_nmethod(), "unexpected nmethod"); |
| return cb; |
| } |
| |
| nmethod* JVMCIEnv::get_nmethod(JVMCIObject obj) { |
| CodeBlob* cb = get_code_blob(obj); |
| if (cb != nullptr) { |
| return cb->as_nmethod_or_null(); |
| } |
| return nullptr; |
| } |
| |
| // Generate implementations for the initialize, new, isa, get and set methods for all the types and |
| // fields declared in the JVMCI_CLASSES_DO macro. |
| |
| #define START_CLASS(className, fullClassName) \ |
| void JVMCIEnv::className##_initialize(JVMCI_TRAPS) { \ |
| if (is_hotspot()) { \ |
| HotSpotJVMCI::className::initialize(JVMCI_CHECK); \ |
| } else { \ |
| JNIJVMCI::className::initialize(JVMCI_CHECK); \ |
| } \ |
| } \ |
| JVMCIObjectArray JVMCIEnv::new_##className##_array(int length, JVMCI_TRAPS) { \ |
| if (is_hotspot()) { \ |
| JavaThread* THREAD = JavaThread::current(); /* For exception macros. */ \ |
| objArrayOop array = oopFactory::new_objArray(HotSpotJVMCI::className::klass(), length, CHECK_(JVMCIObject())); \ |
| return (JVMCIObjectArray) wrap(array); \ |
| } else { \ |
| JNIAccessMark jni(this); \ |
| jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::className::clazz(), nullptr); \ |
| return wrap(result); \ |
| } \ |
| } \ |
| bool JVMCIEnv::isa_##className(JVMCIObject object) { \ |
| if (is_hotspot()) { \ |
| return HotSpotJVMCI::className::is_instance(this, object); \ |
| } else { \ |
| return JNIJVMCI::className::is_instance(this, object); \ |
| } \ |
| } |
| |
| #define END_CLASS |
| |
| #define FIELD(className, name, type, accessor, cast) \ |
| type JVMCIEnv::get_##className##_##name(JVMCIObject obj) { \ |
| if (is_hotspot()) { \ |
| return HotSpotJVMCI::className::get_##name(this, obj); \ |
| } else { \ |
| return JNIJVMCI::className::get_##name(this, obj); \ |
| } \ |
| } \ |
| void JVMCIEnv::set_##className##_##name(JVMCIObject obj, type x) { \ |
| if (is_hotspot()) { \ |
| HotSpotJVMCI::className::set_##name(this, obj, x); \ |
| } else { \ |
| JNIJVMCI::className::set_##name(this, obj, x); \ |
| } \ |
| } |
| |
| #define EMPTY_CAST |
| #define CHAR_FIELD(className, name) FIELD(className, name, jchar, Char, EMPTY_CAST) |
| #define INT_FIELD(className, name) FIELD(className, name, jint, Int, EMPTY_CAST) |
| #define BOOLEAN_FIELD(className, name) FIELD(className, name, jboolean, Boolean, EMPTY_CAST) |
| #define LONG_FIELD(className, name) FIELD(className, name, jlong, Long, EMPTY_CAST) |
| #define FLOAT_FIELD(className, name) FIELD(className, name, jfloat, Float, EMPTY_CAST) |
| |
| #define OBJECT_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObject, Object, EMPTY_CAST) |
| #define OBJECTARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) |
| #define PRIMARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIPrimitiveArray, Object, (JVMCIPrimitiveArray)) |
| |
| #define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObject, Object, (JVMCIObject)) |
| #define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) |
| |
| #define OOPISH_FIELD(className, name, type, accessor, cast) \ |
| type JVMCIEnv::get_##className##_##name(JVMCIObject obj) { \ |
| if (is_hotspot()) { \ |
| return HotSpotJVMCI::className::get_##name(this, obj); \ |
| } else { \ |
| return JNIJVMCI::className::get_##name(this, obj); \ |
| } \ |
| } \ |
| void JVMCIEnv::set_##className##_##name(JVMCIObject obj, type x) { \ |
| if (is_hotspot()) { \ |
| HotSpotJVMCI::className::set_##name(this, obj, x); \ |
| } else { \ |
| JNIJVMCI::className::set_##name(this, obj, x); \ |
| } \ |
| } |
| |
| #define STATIC_OOPISH_FIELD(className, name, type, accessor, cast) \ |
| type JVMCIEnv::get_##className##_##name() { \ |
| if (is_hotspot()) { \ |
| return HotSpotJVMCI::className::get_##name(this); \ |
| } else { \ |
| return JNIJVMCI::className::get_##name(this); \ |
| } \ |
| } \ |
| void JVMCIEnv::set_##className##_##name(type x) { \ |
| if (is_hotspot()) { \ |
| HotSpotJVMCI::className::set_##name(this, x); \ |
| } else { \ |
| JNIJVMCI::className::set_##name(this, x); \ |
| } \ |
| } |
| |
| #define STATIC_PRIMITIVE_FIELD(className, name, type, accessor, cast) \ |
| type JVMCIEnv::get_##className##_##name() { \ |
| if (is_hotspot()) { \ |
| return HotSpotJVMCI::className::get_##name(this); \ |
| } else { \ |
| return JNIJVMCI::className::get_##name(this); \ |
| } \ |
| } \ |
| void JVMCIEnv::set_##className##_##name(type x) { \ |
| if (is_hotspot()) { \ |
| HotSpotJVMCI::className::set_##name(this, x); \ |
| } else { \ |
| JNIJVMCI::className::set_##name(this, x); \ |
| } \ |
| } |
| #define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint, Int, EMPTY_CAST) |
| #define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean, Boolean, EMPTY_CAST) |
| #define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) |
| #define CONSTRUCTOR(className, signature) |
| |
| JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) |
| |
| #undef START_CLASS |
| #undef END_CLASS |
| #undef METHOD |
| #undef CONSTRUCTOR |
| #undef FIELD |
| #undef CHAR_FIELD |
| #undef INT_FIELD |
| #undef BOOLEAN_FIELD |
| #undef LONG_FIELD |
| #undef FLOAT_FIELD |
| #undef OBJECT_FIELD |
| #undef PRIMARRAY_FIELD |
| #undef OBJECTARRAY_FIELD |
| #undef STATIC_OOPISH_FIELD |
| #undef STATIC_OBJECT_FIELD |
| #undef STATIC_OBJECTARRAY_FIELD |
| #undef STATIC_INT_FIELD |
| #undef STATIC_BOOLEAN_FIELD |
| #undef EMPTY_CAST |