# HG changeset patch # User kvn # Date 1557198319 25200 # Node ID 2d012a75d35c5cc53979ce75828ce14a6569962e # Parent 81de17a335759d091363a4bbab3ab0adb971384a 8223332: Update JVMCI Reviewed-by: never, dnsimon diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/compiler/compileBroker.cpp --- a/src/hotspot/share/compiler/compileBroker.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/compiler/compileBroker.cpp Mon May 06 20:05:19 2019 -0700 @@ -70,7 +70,6 @@ #if INCLUDE_JVMCI #include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "runtime/vframe.hpp" #endif #ifdef COMPILER2 #include "opto/c2compiler.hpp" @@ -1063,20 +1062,22 @@ } #if INCLUDE_JVMCI - if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) { + if (UseJVMCICompiler && blocking) { // Don't allow blocking compiles for requests triggered by JVMCI. if (thread->is_Compiler_thread()) { blocking = false; } - // Don't allow blocking compiles if inside a class initializer or while performing class loading - vframeStream vfst((JavaThread*) thread); - for (; !vfst.at_end(); vfst.next()) { - if (vfst.method()->is_static_initializer() || - (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && - vfst.method()->name() == vmSymbols::loadClass_name())) { - blocking = false; - break; + if (!UseJVMCINativeLibrary) { + // Don't allow blocking compiles if inside a class initializer or while performing class loading + vframeStream vfst((JavaThread*) thread); + for (; !vfst.at_end(); vfst.next()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { + blocking = false; + break; + } } } @@ -2063,7 +2064,7 @@ compilable = ciEnv::MethodCompilable_never; } else { JVMCICompileState compile_state(task, system_dictionary_modification_counter); - JVMCIEnv env(&compile_state, __FILE__, __LINE__); + JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__); methodHandle method(thread, target_handle); env.runtime()->compile_method(&env, jvmci, method, osr_bci); diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Mon May 06 20:05:19 2019 -0700 @@ -62,12 +62,17 @@ return *this; } -void JNIHandleMark::push_jni_handle_block() { - JavaThread* thread = JavaThread::current(); +static void requireInHotSpot(const char* caller, JVMCI_TRAPS) { + if (!JVMCIENV->is_hotspot()) { + JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot call %s from JVMCI shared library", caller)); + } +} + +void JNIHandleMark::push_jni_handle_block(JavaThread* thread) { if (thread != NULL) { // Allocate a new block for JNI handles. // Inlined code from jni_PushLocalFrame() - JNIHandleBlock* java_handles = ((JavaThread*)thread)->active_handles(); + JNIHandleBlock* java_handles = thread->active_handles(); JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread); assert(compile_handles != NULL && java_handles != NULL, "should not be NULL"); compile_handles->set_pop_frame_link(java_handles); @@ -75,8 +80,7 @@ } } -void JNIHandleMark::pop_jni_handle_block() { - JavaThread* thread = JavaThread::current(); +void JNIHandleMark::pop_jni_handle_block(JavaThread* thread) { if (thread != NULL) { // Release our JNI handle block JNIHandleBlock* compile_handles = thread->active_handles(); @@ -111,25 +115,88 @@ return Handle(Thread::current(), arg); } -// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +// Bring the JVMCI compiler thread into the VM state. +#define JVMCI_VM_ENTRY_MARK \ + ThreadInVMfromNative __tiv(thread); \ + ResetNoHandleMark rnhm; \ + HandleMarkCleaner __hm(thread); \ + Thread* THREAD = thread; \ + debug_only(VMNativeEntryWrapper __vew;) + +// Native method block that transitions current thread to '_thread_in_vm'. +#define C2V_BLOCK(result_type, name, signature) \ + TRACE_CALL(result_type, jvmci_ ## name signature) \ + JVMCI_VM_ENTRY_MARK; \ + ResourceMark rm; \ + JNI_JVMCIENV(thread, env); + +static Thread* get_current_thread() { + return Thread::current_or_null_safe(); +} + +// Entry to native method implementation that transitions +// current thread to '_thread_in_vm'. #define C2V_VMENTRY(result_type, name, signature) \ JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + Thread* base_thread = get_current_thread(); \ + if (base_thread == NULL) { \ + env->ThrowNew(JNIJVMCI::InternalError::clazz(), \ + err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \ + return; \ + } \ + assert(base_thread->is_Java_thread(), "just checking");\ + JavaThread* thread = (JavaThread*) base_thread; \ JVMCITraceMark jtm("CompilerToVM::" #name); \ - TRACE_CALL(result_type, jvmci_ ## name signature) \ - JVMCI_VM_ENTRY_MARK; \ - ResourceMark rm; \ - JNI_JVMCIENV(env); + C2V_BLOCK(result_type, name, signature) + +#define C2V_VMENTRY_(result_type, name, signature, result) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + Thread* base_thread = get_current_thread(); \ + if (base_thread == NULL) { \ + env->ThrowNew(JNIJVMCI::InternalError::clazz(), \ + err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \ + return result; \ + } \ + assert(base_thread->is_Java_thread(), "just checking");\ + JavaThread* thread = (JavaThread*) base_thread; \ + JVMCITraceMark jtm("CompilerToVM::" #name); \ + C2V_BLOCK(result_type, name, signature) + +#define C2V_VMENTRY_NULL(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, NULL) +#define C2V_VMENTRY_0(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, 0) + +// Entry to native method implementation that does not transition +// current thread to '_thread_in_vm'. +#define C2V_VMENTRY_PREFIX(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + Thread* base_thread = get_current_thread(); #define C2V_END } +#define JNI_THROW(caller, name, msg) do { \ + jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg); \ + if (__throw_res != JNI_OK) { \ + tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \ + } \ + return; \ + } while (0); + +#define JNI_THROW_(caller, name, msg, result) do { \ + jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg); \ + if (__throw_res != JNI_OK) { \ + tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \ + } \ + return result; \ + } while (0) + jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS); -C2V_VMENTRY(jobjectArray, readConfiguration, (JNIEnv* env)) +C2V_VMENTRY_NULL(jobjectArray, readConfiguration, (JNIEnv* env)) jobjectArray config = readConfiguration0(env, JVMCI_CHECK_NULL); return config; } -C2V_VMENTRY(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name_handle)) +C2V_VMENTRY_NULL(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name_handle)) #define RETURN_BOXED_LONG(value) jvalue p; p.j = (jlong) (value); JVMCIObject box = JVMCIENV->create_box(T_LONG, &p, JVMCI_CHECK_NULL); return box.as_jobject(); #define RETURN_BOXED_DOUBLE(value) jvalue p; p.d = (jdouble) (value); JVMCIObject box = JVMCIENV->create_box(T_DOUBLE, &p, JVMCI_CHECK_NULL); return box.as_jobject(); JVMCIObject name = JVMCIENV->wrap(name_handle); @@ -170,10 +237,8 @@ #undef RETURN_BOXED_DOUBLE C2V_END -C2V_VMENTRY(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address)) - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); - } +C2V_VMENTRY_NULL(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address)) + requireInHotSpot("getObjectAtAddress", JVMCI_CHECK_NULL); if (oop_address == 0) { JVMCI_THROW_MSG_NULL(InternalError, "Handle must be non-zero"); } @@ -184,7 +249,7 @@ return JNIHandles::make_local(obj); C2V_END -C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_NULL(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); int code_size = method->code_size(); @@ -262,12 +327,12 @@ return JVMCIENV->get_jbyteArray(result); C2V_END -C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jint, getExceptionTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); return method->exception_table_length(); C2V_END -C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jlong, getExceptionTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); if (method->exception_table_length() == 0) { return 0L; @@ -275,11 +340,8 @@ return (jlong) (address) method->exception_table_start(); C2V_END -C2V_VMENTRY(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject executable_handle)) - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); - } - +C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject executable_handle)) + requireInHotSpot("asResolvedJavaMethod", JVMCI_CHECK_NULL); oop executable = JNIHandles::resolve(executable_handle); oop mirror = NULL; int slot = 0; @@ -298,7 +360,7 @@ return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset)) +C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset)) methodHandle method; JVMCIObject base_object = JVMCIENV->wrap(base); if (base_object.is_null()) { @@ -321,7 +383,7 @@ return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getConstantPool, (JNIEnv* env, jobject, jobject object_handle)) +C2V_VMENTRY_NULL(jobject, getConstantPool, (JNIEnv* env, jobject, jobject object_handle)) constantPoolHandle cp; JVMCIObject object = JVMCIENV->wrap(object_handle); if (object.is_null()) { @@ -341,7 +403,7 @@ return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject base, jlong offset, jboolean compressed)) +C2V_VMENTRY_NULL(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject base, jlong offset, jboolean compressed)) JVMCIKlassHandle klass(THREAD); JVMCIObject base_object = JVMCIENV->wrap(base); jlong base_address = 0; @@ -384,7 +446,7 @@ return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) +C2V_VMENTRY_NULL(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); Klass* holder = JVMCIENV->asKlass(jvmci_type); if (holder->is_interface()) { @@ -400,7 +462,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, getImplementor, (JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_NULL(jobject, getImplementor, (JNIEnv* env, jobject, jobject jvmci_type)) Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_interface()) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -417,12 +479,12 @@ return JVMCIENV->get_jobject(implementor); C2V_END -C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); return method->is_ignored_by_security_stack_walk(); C2V_END -C2V_VMENTRY(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); constantPoolHandle cp = method->constMethod()->constants(); assert(!cp.is_null(), "npe"); @@ -430,17 +492,17 @@ return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant(); C2V_END -C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); return !Inline || CompilerOracle::should_not_inline(method) || method->dont_inline(); C2V_END -C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); return CompilerOracle::should_inline(method) || method->force_inline(); C2V_END -C2V_VMENTRY(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve)) +C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve)) JVMCIObject name = JVMCIENV->wrap(jname); const char* str = JVMCIENV->as_utf8_string(name); TempNewSymbol class_name = SymbolTable::new_symbol(str, CHECK_NULL); @@ -465,6 +527,9 @@ if (resolve) { resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0); + if (resolved_klass == NULL) { + JVMCI_THROW_MSG_NULL(ClassNotFoundException, str); + } } else { if (class_name->char_at(0) == 'L' && class_name->char_at(class_name->utf8_length()-1) == ';') { @@ -483,7 +548,6 @@ TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(), class_name->utf8_length()-2-fd.dimension(), CHECK_0); - // naked oop "k" is OK here -- we assign back into it resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, @@ -502,10 +566,8 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); - } +C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) + requireInHotSpot("lookupClass", JVMCI_CHECK_NULL); if (mirror == NULL) { return NULL; } @@ -518,55 +580,56 @@ return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_NULL(jobject, resolveConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop result = cp->resolve_constant_at(index, CHECK_NULL); return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result)); C2V_END -C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result)); C2V_END -C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->name_and_type_ref_index_at(index); C2V_END -C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) +C2V_VMENTRY_NULL(jobject, lookupNameInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); JVMCIObject sym = JVMCIENV->create_string(cp->name_ref_at(which), JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(sym); C2V_END -C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) +C2V_VMENTRY_NULL(jobject, lookupSignatureInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); JVMCIObject sym = JVMCIENV->create_string(cp->signature_ref_at(which), JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(sym); C2V_END -C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_0(jint, lookupKlassRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->klass_ref_index_at(index); C2V_END -C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_NULL(jobject, resolveTypeInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Klass* klass = cp->klass_at(index, CHECK_NULL); JVMCIKlassHandle resolved_klass(THREAD, klass); if (resolved_klass->is_instance_klass()) { - bool linked = InstanceKlass::cast(resolved_klass())->link_class_or_fail(CHECK_NULL); - if (!linked) { - return NULL; + InstanceKlass::cast(resolved_klass())->link_class(CHECK_NULL); + if (!InstanceKlass::cast(resolved_klass())->is_linked()) { + // link_class() should not return here if there is an issue. + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Class %s must be linked", resolved_klass()->external_name())); } } JVMCIObject klassObject = JVMCIENV->get_jvmci_type(resolved_klass, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(klassObject); C2V_END -C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) +C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Klass* loading_klass = cp->pool_holder(); bool is_accessible = false; @@ -594,13 +657,13 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_NULL(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(appendix_oop)); C2V_END -C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) +C2V_VMENTRY_NULL(jobject, lookupMethodInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); InstanceKlass* pool_holder = cp->pool_holder(); Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); @@ -609,12 +672,12 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_0(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->remap_instruction_operand_from_cache(index); C2V_END -C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle)) +C2V_VMENTRY_NULL(jobject, resolveFieldInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); fieldDescriptor fd; @@ -632,7 +695,7 @@ return JVMCIENV->get_jobject(field_holder); C2V_END -C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) +C2V_VMENTRY_0(jint, getVtableIndexForInterfaceMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) Klass* klass = JVMCIENV->asKlass(jvmci_type); Method* method = JVMCIENV->asMethod(jvmci_method); if (klass->is_interface()) { @@ -650,7 +713,7 @@ return LinkResolver::vtable_index_of_interface_method(klass, method); C2V_END -C2V_VMENTRY(jobject, resolveMethod, (JNIEnv* env, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) +C2V_VMENTRY_NULL(jobject, resolveMethod, (JNIEnv* env, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) Klass* recv_klass = JVMCIENV->asKlass(receiver_jvmci_type); Klass* caller_klass = JVMCIENV->asKlass(caller_jvmci_type); methodHandle method = JVMCIENV->asMethod(jvmci_method); @@ -697,13 +760,13 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_0(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type)) Klass* klass = JVMCIENV->asKlass(jvmci_type); assert(klass != NULL, "method must not be called for primitive types"); return Dependencies::find_finalizable_subclass(klass) != NULL; C2V_END -C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_NULL(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type)) Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_instance_klass()) { return NULL; @@ -713,7 +776,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr)) +C2V_VMENTRY_0(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr)) address target_addr = (address) addr; if (target_addr != 0x0) { int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); @@ -730,10 +793,10 @@ method->set_dont_inline(true); C2V_END -C2V_VMENTRY(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code, +C2V_VMENTRY_0(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject installed_code, jlong failed_speculations_address, jbyteArray speculations_obj)) HandleMark hm; - JNIHandleMark jni_hm; + JNIHandleMark jni_hm(thread); JVMCIObject target_handle = JVMCIENV->wrap(target); JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code); @@ -791,7 +854,7 @@ return result; C2V_END -C2V_VMENTRY(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata)) +C2V_VMENTRY_0(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata)) #if INCLUDE_AOT HandleMark hm; assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode"); @@ -872,7 +935,7 @@ stats->_osr.reset(); C2V_END -C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv* env, jobject, jobject installedCode)) +C2V_VMENTRY_NULL(jobject, disassembleCodeBlob, (JNIEnv* env, jobject, jobject installedCode)) HandleMark hm; if (installedCode == NULL) { @@ -909,7 +972,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv* env, jobject, jobject jvmci_method, int bci)) +C2V_VMENTRY_NULL(jobject, getStackTraceElement, (JNIEnv* env, jobject, jobject jvmci_method, int bci)) HandleMark hm; methodHandle method = JVMCIENV->asMethod(jvmci_method); @@ -917,12 +980,10 @@ return JVMCIENV->get_jobject(element); C2V_END -C2V_VMENTRY(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod)) - if (env != JavaThread::current()->jni_environment()) { - // The incoming arguments array would have to contain JavaConstants instead of regular objects - // and the return value would have to be wrapped as a JavaConstant. - JVMCI_THROW_MSG_NULL(InternalError, "Wrapping of arguments is currently unsupported"); - } +C2V_VMENTRY_NULL(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod)) + // The incoming arguments array would have to contain JavaConstants instead of regular objects + // and the return value would have to be wrapped as a JavaConstant. + requireInHotSpot("executeHotSpotNmethod", JVMCI_CHECK_NULL); HandleMark hm; @@ -968,7 +1029,7 @@ } C2V_END -C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_NULL(jlongArray, getLineNumberTable, (JNIEnv* env, jobject, jobject jvmci_method)) Method* method = JVMCIENV->asMethod(jvmci_method); if (!method->has_linenumber_table()) { return NULL; @@ -995,7 +1056,7 @@ return (jlongArray) JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jlong, getLocalVariableTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) Method* method = JVMCIENV->asMethod(jvmci_method); if (!method->has_localvariable_table()) { return 0; @@ -1003,7 +1064,7 @@ return (jlong) (address) method->localvariable_table_start(); C2V_END -C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jint, getLocalVariableTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) Method* method = JVMCIENV->asMethod(jvmci_method); return method->localvariable_table_length(); C2V_END @@ -1037,18 +1098,23 @@ JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, JVMCI_CHECK); C2V_END -C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr)) +C2V_VMENTRY_NULL(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr)) oop ret = RawAccess<>::oop_load((oop*)(address)addr); return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(ret)); C2V_END -C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv* env, jobject)) +C2V_VMENTRY_NULL(jlongArray, collectCounters, (JNIEnv* env, jobject)) + // Returns a zero length array if counters aren't enabled JVMCIPrimitiveArray array = JVMCIENV->new_longArray(JVMCICounterSize, JVMCI_CHECK_NULL); - JavaThread::collect_counters(JVMCIENV, array); + if (JVMCICounterSize > 0) { + jlong* temp_array = NEW_RESOURCE_ARRAY(jlong, JVMCICounterSize); + JavaThread::collect_counters(temp_array, JVMCICounterSize); + JVMCIENV->copy_longs_from(temp_array, array, 0, JVMCICounterSize); + } return (jlongArray) JVMCIENV->get_jobject(array); C2V_END -C2V_VMENTRY(int, allocateCompileId, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci)) +C2V_VMENTRY_0(int, allocateCompileId, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci)) HandleMark hm; if (jvmci_method == NULL) { JVMCI_THROW_0(NullPointerException); @@ -1061,17 +1127,17 @@ C2V_END -C2V_VMENTRY(jboolean, isMature, (JNIEnv* env, jobject, jlong metaspace_method_data)) +C2V_VMENTRY_0(jboolean, isMature, (JNIEnv* env, jobject, jlong metaspace_method_data)) MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data); return mdo != NULL && mdo->is_mature(); C2V_END -C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci, int comp_level)) +C2V_VMENTRY_0(jboolean, hasCompiledCodeForOSR, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci, int comp_level)) Method* method = JVMCIENV->asMethod(jvmci_method); return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL; C2V_END -C2V_VMENTRY(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol)) +C2V_VMENTRY_NULL(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol)) JVMCIObject sym = JVMCIENV->create_string((Symbol*)(address)symbol, JVMCI_CHECK_NULL); return JVMCIENV->get_jobject(sym); C2V_END @@ -1102,16 +1168,14 @@ JavaCalls::call(result, method, args, CHECK); } -C2V_VMENTRY(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle)) +C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle)) if (!thread->has_last_Java_frame()) { return NULL; } Handle visitor(THREAD, JNIHandles::resolve_non_null(visitor_handle)); - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "getNextStackFrame is only supported for HotSpot stack walking"); - } + requireInHotSpot("iterateFrames", JVMCI_CHECK_NULL); HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL); Handle frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL); @@ -1283,7 +1347,7 @@ } C2V_END -C2V_VMENTRY(jint, isResolvedInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) +C2V_VMENTRY_0(jint, isResolvedInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); if (cp_cache_entry->is_resolved(Bytecodes::_invokehandle)) { @@ -1324,7 +1388,7 @@ C2V_END -C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv* env, jobject)) +C2V_VMENTRY_NULL(jobject, getSignaturePolymorphicHolders, (JNIEnv* env, jobject)) JVMCIObjectArray holders = JVMCIENV->new_String_array(2, JVMCI_CHECK_NULL); JVMCIObject mh = JVMCIENV->create_string("Ljava/lang/invoke/MethodHandle;", JVMCI_CHECK_NULL); JVMCIObject vh = JVMCIENV->create_string("Ljava/lang/invoke/VarHandle;", JVMCI_CHECK_NULL); @@ -1333,7 +1397,7 @@ return JVMCIENV->get_jobject(holders); C2V_END -C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv* env, jobject)) +C2V_VMENTRY_0(jboolean, shouldDebugNonSafepoints, (JNIEnv* env, jobject)) //see compute_recording_non_safepoints in debugInfroRec.cpp if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) { return true; @@ -1348,9 +1412,7 @@ JVMCI_THROW_MSG(NullPointerException, "stack frame is null"); } - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG(InternalError, "getNextStackFrame is only supported for HotSpot stack walking"); - } + requireInHotSpot("materializeVirtualObjects", JVMCI_CHECK); JVMCIENV->HotSpotStackFrameReference_initialize(JVMCI_CHECK); @@ -1465,20 +1527,76 @@ HotSpotJVMCI::HotSpotStackFrameReference::set_objectsMaterialized(JVMCIENV, hs_frame, JNI_TRUE); C2V_END -C2V_VMENTRY(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length)) +// Creates a scope where the current thread is attached and detached +// from HotSpot if it wasn't already attached when entering the scope. +extern "C" void jio_printf(const char *fmt, ...); +class AttachDetach : public StackObj { + public: + bool _attached; + AttachDetach(JNIEnv* env, Thread* current_thread) { + if (current_thread == NULL) { + extern struct JavaVM_ main_vm; + JNIEnv* hotspotEnv; + jint res = main_vm.AttachCurrentThread((void**)&hotspotEnv, NULL); + _attached = res == JNI_OK; + static volatile int report_attach_error = 0; + if (res != JNI_OK && report_attach_error == 0 && Atomic::cmpxchg(1, &report_attach_error, 0) == 0) { + // Only report an attach error once + jio_printf("Warning: attaching current thread to VM failed with %d (future attach errors are suppressed)\n", res); + } + } else { + _attached = false; + } + } + ~AttachDetach() { + if (_attached && get_current_thread() != NULL) { + extern struct JavaVM_ main_vm; + jint res = main_vm.DetachCurrentThread(); + static volatile int report_detach_error = 0; + if (res != JNI_OK && report_detach_error == 0 && Atomic::cmpxchg(1, &report_detach_error, 0) == 0) { + // Only report an attach error once + jio_printf("Warning: detaching current thread from VM failed with %d (future attach errors are suppressed)\n", res); + } + } + } +}; + +C2V_VMENTRY_PREFIX(jint, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length, bool flush, bool can_throw)) + AttachDetach ad(env, base_thread); + bool use_tty = true; + if (base_thread == NULL) { + if (!ad._attached) { + // Can only use tty if the current thread is attached + return 0; + } + base_thread = get_current_thread(); + } + JVMCITraceMark jtm("writeDebugOutput"); + assert(base_thread->is_Java_thread(), "just checking"); + JavaThread* thread = (JavaThread*) base_thread; + C2V_BLOCK(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length)) if (bytes == NULL) { - JVMCI_THROW(NullPointerException); + if (can_throw) { + JVMCI_THROW_0(NullPointerException); + } + return -1; } JVMCIPrimitiveArray array = JVMCIENV->wrap(bytes); // Check if offset and length are non negative. if (offset < 0 || length < 0) { - JVMCI_THROW(ArrayIndexOutOfBoundsException); + if (can_throw) { + JVMCI_THROW_0(ArrayIndexOutOfBoundsException); + } + return -2; } // Check if the range is valid. int array_length = JVMCIENV->get_length(array); if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array_length)) { - JVMCI_THROW(ArrayIndexOutOfBoundsException); + if (can_throw) { + JVMCI_THROW_0(ArrayIndexOutOfBoundsException); + } + return -2; } jbyte buffer[O_BUFLEN]; while (length > 0) { @@ -1488,13 +1606,17 @@ length -= O_BUFLEN; offset += O_BUFLEN; } + if (flush) { + tty->flush(); + } + return 0; C2V_END C2V_VMENTRY(void, flushDebugOutput, (JNIEnv* env, jobject)) tty->flush(); C2V_END -C2V_VMENTRY(int, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong metaspace_method_data, jint position)) +C2V_VMENTRY_0(int, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong metaspace_method_data, jint position)) MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data); ProfileData* profile_data = mdo->data_at(position); if (mdo->is_valid(profile_data)) { @@ -1512,7 +1634,7 @@ JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Invalid profile data position %d", position)); C2V_END -C2V_VMENTRY(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass)) +C2V_VMENTRY_0(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass)) #if INCLUDE_AOT Klass *k = (Klass*) (address) metaspace_klass; if (k->is_instance_klass()) { @@ -1525,7 +1647,7 @@ #endif C2V_END -C2V_VMENTRY(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_NULL(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type)) InstanceKlass* k = InstanceKlass::cast(JVMCIENV->asKlass(jvmci_type)); InstanceKlass* host = k->unsafe_anonymous_host(); JVMCIKlassHandle handle(THREAD, host); @@ -1533,7 +1655,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type)) if (jvmci_type == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1560,7 +1682,7 @@ return JVMCIENV->get_jobject(interfaces); C2V_END -C2V_VMENTRY(jobject, getComponentType, (JNIEnv* env, jobject, jobject jvmci_type)) +C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, jobject jvmci_type)) if (jvmci_type == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1600,7 +1722,7 @@ } C2V_END -C2V_VMENTRY(int, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle)) +C2V_VMENTRY_0(int, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle)) if (bytecode_frame_handle == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1648,12 +1770,12 @@ } C2V_END -C2V_VMENTRY(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_0(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object)) Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0); return obj->identity_hash(); C2V_END -C2V_VMENTRY(jboolean, isInternedString, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_0(jboolean, isInternedString, (JNIEnv* env, jobject, jobject object)) Handle str = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0); if (!java_lang_String::is_instance(str())) { return false; @@ -1664,7 +1786,7 @@ C2V_END -C2V_VMENTRY(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_NULL(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1678,7 +1800,7 @@ return JVMCIENV->get_jobject(boxResult); C2V_END -C2V_VMENTRY(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_NULL(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1722,7 +1844,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, jobject holder)) +C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, jobject holder)) if (holder == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1751,7 +1873,7 @@ return JVMCIENV->get_jobjectArray(methods); C2V_END -C2V_VMENTRY(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobject holder)) +C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobject holder)) if (holder == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1780,7 +1902,7 @@ return JVMCIENV->get_jobjectArray(methods); C2V_END -C2V_VMENTRY(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject field, jboolean is_volatile)) +C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject field, jboolean is_volatile)) if (object == NULL || field == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1848,7 +1970,7 @@ return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jboolean, isInstance, (JNIEnv* env, jobject, jobject holder, jobject object)) +C2V_VMENTRY_0(jboolean, isInstance, (JNIEnv* env, jobject, jobject holder, jobject object)) if (object == NULL || holder == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1857,7 +1979,7 @@ return obj->is_a(klass); C2V_END -C2V_VMENTRY(jboolean, isAssignableFrom, (JNIEnv* env, jobject, jobject holder, jobject otherHolder)) +C2V_VMENTRY_0(jboolean, isAssignableFrom, (JNIEnv* env, jobject, jobject holder, jobject otherHolder)) if (holder == NULL || otherHolder == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1866,7 +1988,7 @@ return otherKlass->is_subtype_of(klass); C2V_END -C2V_VMENTRY(jboolean, isTrustedForIntrinsics, (JNIEnv* env, jobject, jobject holder)) +C2V_VMENTRY_0(jboolean, isTrustedForIntrinsics, (JNIEnv* env, jobject, jobject holder)) if (holder == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1877,7 +1999,7 @@ return false; C2V_END -C2V_VMENTRY(jobject, asJavaType, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_NULL(jobject, asJavaType, (JNIEnv* env, jobject, jobject object)) if (object == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1897,7 +2019,7 @@ C2V_END -C2V_VMENTRY(jobject, asString, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_NULL(jobject, asString, (JNIEnv* env, jobject, jobject object)) if (object == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1908,14 +2030,14 @@ C2V_END -C2V_VMENTRY(jboolean, equals, (JNIEnv* env, jobject, jobject x, jlong xHandle, jobject y, jlong yHandle)) +C2V_VMENTRY_0(jboolean, equals, (JNIEnv* env, jobject, jobject x, jlong xHandle, jobject y, jlong yHandle)) if (x == NULL || y == NULL) { JVMCI_THROW_0(NullPointerException); } return JVMCIENV->resolve_handle(xHandle) == JVMCIENV->resolve_handle(yHandle); C2V_END -C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv* env, jobject, jobject object)) +C2V_VMENTRY_NULL(jobject, getJavaMirror, (JNIEnv* env, jobject, jobject object)) if (object == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1934,7 +2056,7 @@ C2V_END -C2V_VMENTRY(jint, getArrayLength, (JNIEnv* env, jobject, jobject x)) +C2V_VMENTRY_0(jint, getArrayLength, (JNIEnv* env, jobject, jobject x)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1946,7 +2068,7 @@ C2V_END -C2V_VMENTRY(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index)) +C2V_VMENTRY_NULL(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1986,7 +2108,7 @@ C2V_END -C2V_VMENTRY(jint, arrayBaseOffset, (JNIEnv* env, jobject, jobject kind)) +C2V_VMENTRY_0(jint, arrayBaseOffset, (JNIEnv* env, jobject, jobject kind)) if (kind == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -1994,7 +2116,7 @@ return arrayOopDesc::header_size(type) * HeapWordSize; C2V_END -C2V_VMENTRY(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind)) +C2V_VMENTRY_0(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind)) if (kind == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2002,7 +2124,7 @@ return type2aelembytes(type); C2V_END -C2V_VMENTRY(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement)) +C2V_VMENTRY_0(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2010,7 +2132,7 @@ return xobj->byte_field(displacement); } -C2V_VMENTRY(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement)) +C2V_VMENTRY_0(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2018,7 +2140,7 @@ return xobj->short_field(displacement); } -C2V_VMENTRY(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement)) +C2V_VMENTRY_0(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2026,7 +2148,7 @@ return xobj->int_field(displacement); } -C2V_VMENTRY(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement)) +C2V_VMENTRY_0(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2034,7 +2156,7 @@ return xobj->long_field(displacement); } -C2V_VMENTRY(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement)) +C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement)) if (x == NULL) { JVMCI_THROW_0(NullPointerException); } @@ -2052,30 +2174,38 @@ } } -C2V_VMENTRY(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror)) +static void requireJVMCINativeLibrary(JVMCI_TRAPS) { if (!UseJVMCINativeLibrary) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is not enabled (requires -XX:+UseJVMCINativeLibrary)"); + JVMCI_THROW_MSG(UnsupportedOperationException, "JVMCI shared library is not enabled (requires -XX:+UseJVMCINativeLibrary)"); } - if (!JVMCIENV->is_hotspot()) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "Cannot call registerNativeMethods from JVMCI shared library"); +} + +static JavaVM* requireNativeLibraryJavaVM(const char* caller, JVMCI_TRAPS) { + JavaVM* javaVM = JVMCIEnv::get_shared_library_javavm(); + if (javaVM == NULL) { + JVMCI_THROW_MSG_NULL(IllegalStateException, err_msg("Require JVMCI shared library to be initialized in %s", caller)); } + return javaVM; +} + +C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror)) + requireJVMCINativeLibrary(JVMCI_CHECK_NULL); + requireInHotSpot("registerNativeMethods", JVMCI_CHECK_NULL); void* shared_library = JVMCIEnv::get_shared_library_handle(); if (shared_library == NULL) { // Ensure the JVMCI shared library runtime is initialized. - JVMCIEnv __peer_jvmci_env__(false, __FILE__, __LINE__); + JVMCIEnv __peer_jvmci_env__(thread, false, __FILE__, __LINE__); JVMCIEnv* peerEnv = &__peer_jvmci_env__; HandleMark hm; JVMCIRuntime* runtime = JVMCI::compiler_runtime(); JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerEnv); if (peerEnv->has_pending_exception()) { peerEnv->describe_pending_exception(true); - JVMCI_THROW_MSG_0(InternalError, "Error initializing JVMCI runtime"); } shared_library = JVMCIEnv::get_shared_library_handle(); - } - - if (shared_library == NULL) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is unavailable"); + if (shared_library == NULL) { + JVMCI_THROW_MSG_0(InternalError, "Error initializing JVMCI runtime"); + } } if (mirror == NULL) { @@ -2113,15 +2243,18 @@ st.print_raw(pure_name); st.print_raw(long_name); os::print_jni_name_suffix_on(&st, args_size); - jni_name = st.as_string(); - entry = (address) os::dll_lookup(shared_library, jni_name); + char* jni_long_name = st.as_string(); + entry = (address) os::dll_lookup(shared_library, jni_long_name); + if (entry == NULL) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]", + method->name_and_sig_as_C_string(), + jni_name, jni_long_name, JVMCIEnv::get_shared_library_path())); + } } - if (entry == NULL) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, method->name_and_sig_as_C_string()); - } + if (method->has_native_function() && entry != method->native_function()) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("Cannot overwrite existing native implementation for %s", - method->name_and_sig_as_C_string())); + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]", + method->name_and_sig_as_C_string(), p2i(method->native_function()), p2i(entry))); } method->set_native_function(entry, Method::native_bind_event_is_interesting); if (PrintJNIResolving) { @@ -2141,11 +2274,102 @@ return (jlongArray) JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle)) +C2V_VMENTRY_PREFIX(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject c2vm)) + if (base_thread == NULL) { + // Called from unattached JVMCI shared library thread + return false; + } + JVMCITraceMark jtm("isCurrentThreadAttached"); + assert(base_thread->is_Java_thread(), "just checking"); + JavaThread* thread = (JavaThread*) base_thread; + if (thread->jni_environment() == env) { + C2V_BLOCK(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject)) + requireJVMCINativeLibrary(JVMCI_CHECK_0); + JavaVM* javaVM = requireNativeLibraryJavaVM("isCurrentThreadAttached", JVMCI_CHECK_0); + JNIEnv* peerEnv; + return javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK; + } + return true; +C2V_END + +C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jboolean as_daemon)) + if (base_thread == NULL) { + // Called from unattached JVMCI shared library thread + extern struct JavaVM_ main_vm; + JNIEnv* hotspotEnv; + jint res = as_daemon ? main_vm.AttachCurrentThreadAsDaemon((void**)&hotspotEnv, NULL) : + main_vm.AttachCurrentThread((void**)&hotspotEnv, NULL); + if (res != JNI_OK) { + JNI_THROW_("attachCurrentThread", InternalError, err_msg("Trying to attach thread returned %d", res), false); + } + return true; + } + JVMCITraceMark jtm("attachCurrentThread"); + assert(base_thread->is_Java_thread(), "just checking");\ + JavaThread* thread = (JavaThread*) base_thread; + if (thread->jni_environment() == env) { + // Called from HotSpot + C2V_BLOCK(jboolean, attachCurrentThread, (JNIEnv* env, jobject, jboolean)) + requireJVMCINativeLibrary(JVMCI_CHECK_0); + JavaVM* javaVM = requireNativeLibraryJavaVM("attachCurrentThread", JVMCI_CHECK_0); + JavaVMAttachArgs attach_args; + attach_args.version = JNI_VERSION_1_2; + attach_args.name = thread->name(); + attach_args.group = NULL; + JNIEnv* peerEnv; + if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK) { + return false; + } + jint res = as_daemon ? javaVM->AttachCurrentThreadAsDaemon((void**)&peerEnv, &attach_args) : + javaVM->AttachCurrentThread((void**)&peerEnv, &attach_args); + if (res == JNI_OK) { + guarantee(peerEnv != NULL, "must be"); + return true; + } + JVMCI_THROW_MSG_0(InternalError, err_msg("Error %d while attaching %s", res, attach_args.name)); + } + // Called from JVMCI shared library + return false; +C2V_END + +C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm)) + if (base_thread == NULL) { + // Called from unattached JVMCI shared library thread + JNI_THROW("detachCurrentThread", IllegalStateException, err_msg("Cannot detach non-attached thread")); + } + JVMCITraceMark jtm("detachCurrentThread"); + assert(base_thread->is_Java_thread(), "just checking");\ + JavaThread* thread = (JavaThread*) base_thread; + if (thread->jni_environment() == env) { + // Called from HotSpot + C2V_BLOCK(void, detachCurrentThread, (JNIEnv* env, jobject)) + requireJVMCINativeLibrary(JVMCI_CHECK); + requireInHotSpot("detachCurrentThread", JVMCI_CHECK); + JavaVM* javaVM = requireNativeLibraryJavaVM("detachCurrentThread", JVMCI_CHECK); + JNIEnv* peerEnv; + if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) != JNI_OK) { + JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot detach non-attached thread: %s", thread->name())); + } + jint res = javaVM->DetachCurrentThread(); + if (res != JNI_OK) { + JVMCI_THROW_MSG(InternalError, err_msg("Error %d while attaching %s", res, thread->name())); + } + } else { + // Called from attached JVMCI shared library thread + extern struct JavaVM_ main_vm; + jint res = main_vm.DetachCurrentThread(); + if (res != JNI_OK) { + JNI_THROW("detachCurrentThread", InternalError, err_msg("Cannot detach non-attached thread")); + } + } +C2V_END + +C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle)) + requireJVMCINativeLibrary(JVMCI_CHECK_0); if (obj_handle == NULL) { return 0L; } - JVMCIEnv __peer_jvmci_env__(!JVMCIENV->is_hotspot(), __FILE__, __LINE__); + JVMCIEnv __peer_jvmci_env__(thread, !JVMCIENV->is_hotspot(), __FILE__, __LINE__); JVMCIEnv* peerEnv = &__peer_jvmci_env__; JVMCIEnv* thisEnv = JVMCIENV; @@ -2216,7 +2440,8 @@ return (jlong) peerEnv->make_global(result).as_jobject(); } -C2V_VMENTRY(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) +C2V_VMENTRY_NULL(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) + requireJVMCINativeLibrary(JVMCI_CHECK_NULL); if (obj_handle == 0L) { return NULL; } @@ -2234,7 +2459,7 @@ JVMCIENV->asNmethod(code); } -C2V_VMENTRY(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle)) +C2V_VMENTRY_NULL(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle)) JVMCIObject code = JVMCIENV->wrap(code_handle); CodeBlob* cb = JVMCIENV->asCodeBlob(code); if (cb == NULL) { @@ -2246,10 +2471,8 @@ return JVMCIENV->get_jbyteArray(result); } -C2V_VMENTRY(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method)) - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); - } +C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method)) + requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL); methodHandle m = JVMCIENV->asMethod(jvmci_method); oop executable; if (m->is_initializer()) { @@ -2264,10 +2487,8 @@ return JNIHandles::make_local(THREAD, executable); } -C2V_VMENTRY(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index)) - if (env != JavaThread::current()->jni_environment()) { - JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); - } +C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index)) + requireInHotSpot("asReflectionField", JVMCI_CHECK_NULL); Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_instance_klass()) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, @@ -2284,7 +2505,7 @@ return JNIHandles::make_local(env, reflected); } -C2V_VMENTRY(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) +C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) FailedSpeculation* head = *((FailedSpeculation**)(address) failed_speculations_address); int result_length = 0; for (FailedSpeculation* fs = head; fs != NULL; fs = fs->next()) { @@ -2316,7 +2537,7 @@ return JVMCIENV->get_jobjectArray(result); } -C2V_VMENTRY(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method)) +C2V_VMENTRY_0(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method)) methodHandle method = JVMCIENV->asMethod(jvmci_method); MethodData* method_data = method->method_data(); if (method_data == NULL) { @@ -2331,7 +2552,7 @@ FailedSpeculation::free_failed_speculations((FailedSpeculation**)(address) failed_speculations_address); } -C2V_VMENTRY(bool, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj)) +C2V_VMENTRY_0(bool, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj)) JVMCIPrimitiveArray speculation_handle = JVMCIENV->wrap(speculation_obj); int speculation_len = JVMCIENV->get_length(speculation_handle); char* speculation = NEW_RESOURCE_ARRAY(char, speculation_len); @@ -2431,7 +2652,7 @@ {CC "iterateFrames", CC "([" RESOLVED_METHOD "[" RESOLVED_METHOD "I" INSPECTED_FRAME_VISITOR ")" OBJECT, FN_PTR(iterateFrames)}, {CC "materializeVirtualObjects", CC "(" HS_STACK_FRAME_REF "Z)V", FN_PTR(materializeVirtualObjects)}, {CC "shouldDebugNonSafepoints", CC "()Z", FN_PTR(shouldDebugNonSafepoints)}, - {CC "writeDebugOutput", CC "([BII)V", FN_PTR(writeDebugOutput)}, + {CC "writeDebugOutput", CC "([BIIZZ)I", FN_PTR(writeDebugOutput)}, {CC "flushDebugOutput", CC "()V", FN_PTR(flushDebugOutput)}, {CC "methodDataProfileDataSize", CC "(JI)I", FN_PTR(methodDataProfileDataSize)}, {CC "getFingerprint", CC "(J)J", FN_PTR(getFingerprint)}, @@ -2469,6 +2690,9 @@ {CC "getObject", CC "(" OBJECTCONSTANT "J)" OBJECTCONSTANT, FN_PTR(getObject)}, {CC "deleteGlobalHandle", CC "(J)V", FN_PTR(deleteGlobalHandle)}, {CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)}, + {CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)}, + {CC "attachCurrentThread", CC "(Z)Z", FN_PTR(attachCurrentThread)}, + {CC "detachCurrentThread", CC "()V", FN_PTR(detachCurrentThread)}, {CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)}, {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciCompilerToVM.hpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Mon May 06 20:05:19 2019 -0700 @@ -160,13 +160,14 @@ }; class JNIHandleMark : public StackObj { + JavaThread* _thread; public: - JNIHandleMark() { push_jni_handle_block(); } - ~JNIHandleMark() { pop_jni_handle_block(); } + JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); } + ~JNIHandleMark() { pop_jni_handle_block(_thread); } private: - static void push_jni_handle_block(); - static void pop_jni_handle_block(); + static void push_jni_handle_block(JavaThread* thread); + static void pop_jni_handle_block(JavaThread* thread); }; #endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciEnv.cpp --- a/src/hotspot/share/jvmci/jvmciEnv.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp Mon May 06 20:05:19 2019 -0700 @@ -129,11 +129,10 @@ } } -JNIEnv* JVMCIEnv::attach_shared_library() { +JNIEnv* JVMCIEnv::init_shared_library(JavaThread* thread) { if (_shared_library_javavm == NULL) { MutexLocker locker(JVMCI_lock); if (_shared_library_javavm == NULL) { - char path[JVM_MAXPATHLEN]; char ebuf[1024]; if (JVMCILibPath != NULL) { @@ -179,85 +178,107 @@ } } } - JNIEnv* env; - if (_shared_library_javavm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) { - guarantee(env != NULL, "missing env"); - return env; - } - fatal("Error attaching current thread to JVMCI shared library JNI interface"); return NULL; } -void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) { +void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { + assert(thread != NULL, "npe"); // By default there is only one runtime which is the compiler runtime. _runtime = JVMCI::compiler_runtime(); + _env = NULL; + _pop_frame_on_close = false; + _detach_on_close = false; if (!UseJVMCINativeLibrary) { // In HotSpot mode, JNI isn't used at all. _is_hotspot = true; - _env = NULL; return; } if (parent_env != NULL) { // 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. - JavaThread* thread = JavaThread::current(); - if (thread->jni_environment() == parent_env) { + _is_hotspot = thread->jni_environment() == parent_env; + if (_is_hotspot) { // Select the Java runtime _runtime = JVMCI::java_runtime(); - _is_hotspot = true; - _env = NULL; return; } + _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; + _env = init_shared_library(thread); + + if (_env != NULL) { + // Creating the JVMCI shared library VM also attaches the current thread + _detach_on_close = true; + } else { + _shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2); + if (parent_env != NULL) { + // 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 = thread->name(); + attach_args.group = NULL; + if (_shared_library_javavm->AttachCurrentThread((void**)&_env, &attach_args) != JNI_OK) { + fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name); + } + _detach_on_close = true; + } } - // Running in JVMCI shared library mode so get a shared library JNIEnv - _is_hotspot = false; - _env = attach_shared_library(); - assert(parent_env == NULL || _env == parent_env, "must be"); + assert(_env != NULL, "missing env"); + assert(_throw_to_caller == false, "must be"); - if (parent_env == NULL) { - // There is no parent shared library JNI env so push - // a JNI local frame to release all local handles in - // this JVMCIEnv scope when it's closed. - assert(_throw_to_caller == false, "must be"); - JNIAccessMark jni(this); - 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::exit_on_pending_exception(this, message); - } + JNIAccessMark jni(this); + 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::exit_on_pending_exception(this, message); } + _pop_frame_on_close = true; } -JVMCIEnv::JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line): +JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line): _throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) { - init_env_mode_runtime(NULL); + init_env_mode_runtime(thread, NULL); } JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): _throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) { - init_env_mode_runtime(NULL); + init_env_mode_runtime(thread, NULL); } -JVMCIEnv::JVMCIEnv(JNIEnv* parent_env, const char* file, int line): +JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line): _throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) { - init_env_mode_runtime(parent_env); + init_env_mode_runtime(thread, parent_env); assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment"); } -void JVMCIEnv::init(bool is_hotspot, const char* file, int line) { +void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int line) { _compile_state = NULL; _throw_to_caller = false; _file = file; _line = line; if (is_hotspot) { _env = NULL; + _pop_frame_on_close = false; + _detach_on_close = false; _is_hotspot = true; _runtime = JVMCI::java_runtime(); } else { - init_env_mode_runtime(NULL); + init_env_mode_runtime(thread, NULL); } } @@ -324,7 +345,7 @@ } } } else { - if (!is_hotspot()) { + if (_pop_frame_on_close) { // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope. JNIAccessMark jni(this); jni()->PopLocalFrame(NULL); @@ -335,6 +356,10 @@ jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line); JVMCIRuntime::exit_on_pending_exception(this, message); } + + if (_detach_on_close) { + get_shared_library_javavm()->DetachCurrentThread(); + } } } @@ -463,26 +488,38 @@ } } -void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes) { - if (size_in_bytes == 0) { +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(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), size_in_bytes); + memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, length); } else { JNIAccessMark jni(this); - jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest); + jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src); } } -void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) { - if (size_in_bytes == 0) { + +void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) { + if (length == 0) { return; } if (is_hotspot()) { - memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, size_in_bytes); + memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong)); } else { JNIAccessMark jni(this); - jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src); + jni()->SetLongArrayRegion(dest.as_jlongArray(), offset, length, src); } } @@ -612,6 +649,8 @@ DO_THROW(IllegalArgumentException) DO_THROW(InvalidInstalledCodeException) DO_THROW(UnsatisfiedLinkError) +DO_THROW(UnsupportedOperationException) +DO_THROW(ClassNotFoundException) #undef DO_THROW @@ -888,7 +927,7 @@ return JVMCIObject(); } jobject file_name = NULL; - if (file_name != NULL) { + if (file_name_sym != NULL) { file_name = jni()->NewStringUTF(file_name_sym->as_C_string()); if (jni()->ExceptionCheck()) { return JVMCIObject(); @@ -1323,14 +1362,15 @@ assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type"); oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant)); return Handle(THREAD, obj); - } else { - assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type"); + } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) { jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); oop result = resolve_handle(object_handle); if (result == NULL) { 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()); } } diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciEnv.hpp --- a/src/hotspot/share/jvmci/jvmciEnv.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp Mon May 06 20:05:19 2019 -0700 @@ -36,15 +36,6 @@ class JVMCICompiler; class JVMCIRuntime; -// Bring the JVMCI compiler thread into the VM state. -#define JVMCI_VM_ENTRY_MARK \ - JavaThread* thread = JavaThread::current(); \ - ThreadInVMfromNative __tiv(thread); \ - ResetNoHandleMark rnhm; \ - HandleMarkCleaner __hm(thread); \ - Thread* THREAD = thread; \ - debug_only(VMNativeEntryWrapper __vew;) - #define JVMCI_EXCEPTION_CONTEXT \ JavaThread* thread=JavaThread::current(); \ Thread* THREAD = thread; @@ -154,24 +145,25 @@ static void* _shared_library_handle; // result of os::dll_load static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library - // Attaches the current thread to the JavaVM in the shared library, - // initializing the shared library VM first if necessary. - // Returns the JNI interface pointer of the current thread. - // The _shared_library_* fields are initialized by the first - // call to this method. - static JNIEnv* attach_shared_library(); + // Initializes the shared library JavaVM if not already initialized. + // Returns the JNI interface pointer for the current thread + // if initialization was performed by this call, NULL if + // initialization was performed by a previous call. + static JNIEnv* init_shared_library(JavaThread* thread); // Initializes the _env, _mode and _runtime fields. - void init_env_mode_runtime(JNIEnv* parent_env); + void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env); - void init(bool is_hotspot, const char* file, int line); + void init(JavaThread* thread, bool is_hotspot, const char* file, int line); - JNIEnv* _env; // JNI env for calling into shared library - JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime - bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in - bool _throw_to_caller; // Propagate an exception raised in this env to the caller? - const char* _file; // The file and ... - int _line; // ... line where this JNIEnv was created + JNIEnv* _env; // JNI env for calling into shared library + bool _pop_frame_on_close; // Must pop frame on close? + bool _detach_on_close; // Must detach on close? + JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime + bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in + bool _throw_to_caller; // Propagate an exception raised in this env to the caller? + const char* _file; // The file and ... + int _line; // ... line where this JNIEnv was created // Translates an exception on the HotSpot heap to an exception on // the shared library heap. The translation includes the stack and @@ -185,12 +177,12 @@ // scope closes so that it will be propagated back to Java. // The JVMCIEnv destructor translates the exception object for the // Java runtime if necessary. - JVMCIEnv(JNIEnv* env, const char* file, int line); + JVMCIEnv(JavaThread* thread, JNIEnv* env, const char* file, int line); // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker. // An exception occurring within the scope must not be propagated back to // the CompileBroker. - JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line); + JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line); // Opens a JNIEnv scope for a call from within the VM. An exception occurring // within the scope must not be propagated back to the caller. @@ -198,20 +190,20 @@ // Opens a JNIEnv scope for accessing `for_object`. An exception occurring // within the scope must not be propagated back to the caller. - JVMCIEnv(JVMCIObject for_object, const char* file, int line) { + JVMCIEnv(JavaThread* thread, JVMCIObject for_object, const char* file, int line) { // A JNI call to access an object in the shared library heap // can block or take a long time so do not allow such access // on the VM thread. assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(), "cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object"); - init(for_object.is_hotspot(), file, line); + init(thread, for_object.is_hotspot(), file, line); } // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true // otherwise for the shared library runtime. An exception occurring // within the scope must not be propagated back to the caller. - JVMCIEnv(bool is_hotspot, const char* file, int line) { - init(is_hotspot, file, line); + JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) { + init(thread, is_hotspot, file, line); } ~JVMCIEnv(); @@ -247,8 +239,10 @@ long get_long_at(JVMCIPrimitiveArray array, int index); void put_long_at(JVMCIPrimitiveArray array, int index, jlong value); - void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes); - void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes); + void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length); + void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length); + + void copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length); JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS); @@ -323,6 +317,8 @@ DO_THROW(IllegalArgumentException) DO_THROW(InvalidInstalledCodeException) DO_THROW(UnsatisfiedLinkError) + DO_THROW(UnsupportedOperationException) + DO_THROW(ClassNotFoundException) #undef DO_THROW diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciExceptions.hpp --- a/src/hotspot/share/jvmci/jvmciExceptions.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciExceptions.hpp Mon May 06 20:05:19 2019 -0700 @@ -32,8 +32,8 @@ #define JVMCIENV __jvmci_env__ #define JVMCI_TRAPS JVMCIEnv* JVMCIENV -#define JNI_JVMCIENV(env) \ - JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__); \ +#define JNI_JVMCIENV(thread, env) \ + JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__); \ JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ #define THREAD_JVMCIENV(thread) \ diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciJavaClasses.cpp --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Mon May 06 20:05:19 2019 -0700 @@ -356,6 +356,43 @@ jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); } +// Dumps symbols for public () and (String) methods of +// non-abstract Throwable subtypes known by the VM. This is to +// support the use of reflection in jdk.vm.ci.hotspot.TranslatedException.create(). +class ThrowableInitDumper : public SymbolClosure { + private: + fileStream* _st; + public: + ThrowableInitDumper(fileStream* st) { _st = st; } + void do_symbol(Symbol** p) { + Thread* THREAD = Thread::current(); + Symbol* name = *p; + if (name == NULL) { + return; + } + Klass* k = SystemDictionary::resolve_or_null(name, CHECK_EXIT); + if (k != NULL && k->is_instance_klass()) { + InstanceKlass* iklass = InstanceKlass::cast(k); + if (iklass->is_subclass_of(SystemDictionary::Throwable_klass()) && iklass->is_public() && !iklass->is_abstract()) { + const char* class_name = NULL; + Array* methods = iklass->methods(); + for (int i = 0; i < methods->length(); i++) { + Method* m = methods->at(i); + if (m->name() == vmSymbols::object_initializer_name() && + m->is_public() && + (m->signature() == vmSymbols::void_method_signature() || m->signature() == vmSymbols::string_void_signature())) { + if (class_name == NULL) { + class_name = name->as_C_string(); + _st->print_cr("class %s", class_name); + } + _st->print_cr("method %s %s %s", class_name, m->name()->as_C_string(), m->signature()->as_C_string()); + } + } + } + } + } +}; + #define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string() /** * Initializes the JNI method and field ids used in JNIJVMCI. @@ -441,6 +478,8 @@ fileStream* st = JVMCIGlobals::get_jni_config_file(); DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()); + ThrowableInitDumper dumper(st); + vmSymbols::symbols_do(&dumper); st->flush(); tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig); diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciJavaClasses.hpp --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp Mon May 06 20:05:19 2019 -0700 @@ -381,12 +381,18 @@ start_class(InternalError, java_lang_InternalError) \ jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \ end_class \ + start_class(ClassNotFoundException, java_lang_ClassNotFoundException) \ + jvmci_constructor(ClassNotFoundException, "(Ljava/lang/String;)V") \ + end_class \ start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \ jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \ end_class \ start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \ jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \ end_class \ + start_class(UnsupportedOperationException, java_lang_UnsupportedOperationException) \ + jvmci_constructor(UnsupportedOperationException, "(Ljava/lang/String;)V") \ + end_class \ start_class(StackTraceElement, java_lang_StackTraceElement) \ object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \ object_field(StackTraceElement, methodName, "Ljava/lang/String;") \ diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmciRuntime.cpp --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Mon May 06 20:05:19 2019 -0700 @@ -655,7 +655,7 @@ // private static JVMCIRuntime JVMCI.initializeRuntime() JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) - JNI_JVMCIENV(env); + JNI_JVMCIENV(thread, env); if (!EnableJVMCI) { JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled"); } @@ -877,7 +877,7 @@ fatal("check TLAB allocation code for address space conflicts"); #endif - JNI_JVMCIENV(env); + JNI_JVMCIENV(thread, env); if (!EnableJVMCI) { JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled"); @@ -1353,6 +1353,10 @@ compile_state->set_failure(true, "No OSR during boostrap"); return; } + if (JVMCI::shutdown_called()) { + compile_state->set_failure(false, "Avoiding compilation during shutdown"); + return; + } HandleMark hm; JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV); diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmci_globals.cpp --- a/src/hotspot/share/jvmci/jvmci_globals.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp Mon May 06 20:05:19 2019 -0700 @@ -83,7 +83,7 @@ } FLAG_SET_DEFAULT(EnableJVMCI, true); if (BootstrapJVMCI && UseJVMCINativeLibrary) { - jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary"); + jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary\n"); return false; } } diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/jvmci_globals.hpp --- a/src/hotspot/share/jvmci/jvmci_globals.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp Mon May 06 20:05:19 2019 -0700 @@ -53,7 +53,10 @@ "Prints properties used by the JVMCI compiler and exits") \ \ experimental(bool, BootstrapJVMCI, false, \ - "Bootstrap JVMCI before running Java main method") \ + "Bootstrap JVMCI before running Java main method. This " \ + "initializes the compile queue with a small set of methods " \ + "and processes the queue until it is empty. Combining this with " \ + "-XX:-TieredCompilation makes JVMCI compile more of itself.") \ \ experimental(bool, EagerJVMCI, false, \ "Force eager JVMCI initialization") \ diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/jvmci/vmStructs_jvmci.cpp --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Mon May 06 20:05:19 2019 -0700 @@ -246,6 +246,10 @@ \ nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ \ + volatile_nonstatic_field(ObjectMonitor, _cxq, ObjectWaiter*) \ + volatile_nonstatic_field(ObjectMonitor, _EntryList, ObjectWaiter*) \ + volatile_nonstatic_field(ObjectMonitor, _succ, Thread*) \ + \ volatile_nonstatic_field(oopDesc, _mark, markOop) \ volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ \ @@ -347,6 +351,7 @@ declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(LocalVariableTableElement) \ declare_toplevel_type(narrowKlass) \ + declare_toplevel_type(ObjectWaiter) \ declare_toplevel_type(Symbol*) \ declare_toplevel_type(vtableEntry) \ \ diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/runtime/objectMonitor.hpp --- a/src/hotspot/share/runtime/objectMonitor.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/runtime/objectMonitor.hpp Mon May 06 20:05:19 2019 -0700 @@ -139,6 +139,7 @@ friend class ObjectSynchronizer; friend class ObjectWaiter; friend class VMStructs; + JVMCI_ONLY(friend class JVMCIVMStructs;) volatile markOop _header; // displaced object header word - mark void* volatile _object; // backward object pointer - strong root diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/runtime/thread.cpp Mon May 06 20:05:19 2019 -0700 @@ -1575,18 +1575,15 @@ return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); } -void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) { - if (JVMCICounterSize > 0) { - JavaThreadIteratorWithHandle jtiwh; - int len = jvmci_env->get_length(array); - for (int i = 0; i < len; i++) { - jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]); - } - for (; JavaThread *tp = jtiwh.next(); ) { - if (jvmci_counters_include(tp)) { - for (int i = 0; i < len; i++) { - jvmci_env->put_long_at(array, i, jvmci_env->get_long_at(array, i) + tp->_jvmci_counters[i]); - } +void JavaThread::collect_counters(jlong* array, int length) { + assert(length == JVMCICounterSize, "wrong value"); + for (int i = 0; i < length; i++) { + array[i] = _jvmci_old_thread_counters[i]; + } + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) { + if (jvmci_counters_include(tp)) { + for (int i = 0; i < length; i++) { + array[i] += tp->_jvmci_counters[i]; } } } diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/runtime/thread.hpp --- a/src/hotspot/share/runtime/thread.hpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/runtime/thread.hpp Mon May 06 20:05:19 2019 -0700 @@ -1152,7 +1152,7 @@ public: static jlong* _jvmci_old_thread_counters; - static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array); + static void collect_counters(jlong* array, int length); private: #endif // INCLUDE_JVMCI diff -r 81de17a33575 -r 2d012a75d35c src/hotspot/share/runtime/vmOperations.cpp --- a/src/hotspot/share/runtime/vmOperations.cpp Tue May 07 10:21:04 2019 +0800 +++ b/src/hotspot/share/runtime/vmOperations.cpp Mon May 06 20:05:19 2019 -0700 @@ -438,14 +438,14 @@ if (thr->is_Compiler_thread()) { #if INCLUDE_JVMCI CompilerThread* ct = (CompilerThread*) thr; - if (ct->compiler() == NULL || !ct->compiler()->is_jvmci() || !UseJVMCINativeLibrary) { + if (ct->compiler() == NULL || !ct->compiler()->is_jvmci()) { num_active_compiler_thread++; } else { - // When using a compiler in a JVMCI shared library, it's possible - // for one compiler thread to grab a lock in the shared library, - // enter HotSpot and go to sleep on the shutdown safepoint. Another - // JVMCI shared library compiler thread can then attempt to grab the - // lock and thus never make progress. + // A JVMCI compiler thread never accesses VM data structures + // while in _thread_in_native state so there's no need to wait + // for it and potentially add a 300 millisecond delay to VM + // shutdown. + num_active--; } #else num_active_compiler_thread++; diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Mon May 06 20:05:19 2019 -0700 @@ -612,10 +612,15 @@ * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's * log stream. * + * @param flush specifies if the log stream should be flushed after writing + * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length} + * arguments should result in an exception or a negative return value + * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and + * copying would cause access of data outside array bounds * @throws NullPointerException if {@code bytes == null} * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds */ - native void writeDebugOutput(byte[] bytes, int offset, int length); + native int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow); /** * Flush HotSpot's log stream. @@ -947,4 +952,18 @@ */ native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation); + /** + * @see HotSpotJVMCIRuntime#isCurrentThreadAttached() + */ + native boolean isCurrentThreadAttached(); + + /** + * @see HotSpotJVMCIRuntime#attachCurrentThread + */ + native boolean attachCurrentThread(boolean asDaemon); + + /** + * @see HotSpotJVMCIRuntime#detachCurrentThread() + */ + native void detachCurrentThread(); } diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Mon May 06 20:05:19 2019 -0700 @@ -46,7 +46,6 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; -import java.util.TreeMap; import java.util.function.Predicate; import jdk.internal.misc.Unsafe; @@ -180,8 +179,8 @@ // Can only do eager initialization of the JVMCI compiler // once the singleton instance is available. - if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { - instance.getCompiler(); + if (result.config.getFlag("EagerJVMCI", Boolean.class)) { + result.getCompiler(); } } // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is @@ -464,7 +463,7 @@ } if (Option.PrintConfig.getBoolean()) { - printConfig(configStore, compilerToVm); + configStore.printConfig(); } } @@ -727,39 +726,21 @@ } } - @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!") - private static void printConfigLine(CompilerToVM vm, String format, Object... args) { - String line = String.format(format, args); - byte[] lineBytes = line.getBytes(); - vm.writeDebugOutput(lineBytes, 0, lineBytes.length); - vm.flushDebugOutput(); - } - - private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) { - TreeMap fields = new TreeMap<>(store.getFields()); - for (VMField field : fields.values()) { - if (!field.isStatic()) { - printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset); - } else { - String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value); - printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address); - } - } - TreeMap flags = new TreeMap<>(store.getFlags()); - for (VMFlag flag : flags.values()) { - printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value); - } - TreeMap addresses = new TreeMap<>(store.getAddresses()); - for (Map.Entry e : addresses.entrySet()) { - printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); - } - TreeMap constants = new TreeMap<>(store.getConstants()); - for (Map.Entry e : constants.entrySet()) { - printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); - } - for (VMIntrinsicMethod e : store.getIntrinsics()) { - printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor); - } + /** + * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's + * log stream. + * + * @param flush specifies if the log stream should be flushed after writing + * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length} + * arguments should result in an exception or a negative return value. If + * {@code false}, this call will not perform any heap allocation + * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and + * copying would cause access of data outside array bounds + * @throws NullPointerException if {@code bytes == null} + * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds + */ + public int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow) { + return compilerToVm.writeDebugOutput(bytes, offset, length, flush, canThrow); } /** @@ -777,7 +758,7 @@ } else if (len == 0) { return; } - compilerToVm.writeDebugOutput(b, off, len); + compilerToVm.writeDebugOutput(b, off, len, false, true); } @Override @@ -907,11 +888,13 @@ * the Java VM in the JVMCI shared library, and the remaining values are the first 3 * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) * @throws NullPointerException if {@code clazz == null} - * @throws IllegalArgumentException if the current execution context is the JVMCI shared library - * or if {@code clazz} is {@link Class#isPrimitive()} - * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in - * {@code clazz} is already linked or the JVMCI shared library does not contain a - * JNI-compatible symbol for a native method in {@code clazz} + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) + * @throws IllegalStateException if the current execution context is the JVMCI shared library + * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()} + * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz} + * (no matching JNI symbol or the native method is already linked to a different + * address) */ public long[] registerNativeMethods(Class clazz) { return compilerToVm.registerNativeMethods(clazz); @@ -935,6 +918,8 @@ * * @param obj an object for which an equivalent instance in the peer runtime is requested * @return a JNI global reference to the mirror of {@code obj} in the peer runtime + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) * @throws IllegalArgumentException if {@code obj} is not of a translatable type * * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" @@ -950,7 +935,9 @@ * * @param handle a JNI global reference to an object in the current runtime * @return the object referred to by {@code handle} - * @throws ClassCastException if the returned object cannot be case to {@code type} + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) + * @throws ClassCastException if the returned object cannot be cast to {@code type} * * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" * @@ -960,6 +947,44 @@ } /** + * Determines if the current thread is attached to the peer runtime. + * + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) + * @throws IllegalStateException if the peer runtime has not been initialized + */ + public boolean isCurrentThreadAttached() { + return compilerToVm.isCurrentThreadAttached(); + } + + /** + * Ensures the current thread is attached to the peer runtime. + * + * @param asDaemon if the thread is not yet attached, should it be attached as a daemon + * @return {@code true} if this call attached the current thread, {@code false} if the current + * thread was already attached + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) + * @throws IllegalStateException if the peer runtime has not been initialized or there is an + * error while trying to attach the thread + */ + public boolean attachCurrentThread(boolean asDaemon) { + return compilerToVm.attachCurrentThread(asDaemon); + } + + /** + * Detaches the current thread from the peer runtime. + * + * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e. + * {@code -XX:-UseJVMCINativeLibrary}) + * @throws IllegalStateException if the peer runtime has not been initialized or if the current + * thread is not attached or if there is an error while trying to detach the thread + */ + public void detachCurrentThread() { + compilerToVm.detachCurrentThread(); + } + + /** * Informs HotSpot that no method whose module is in {@code modules} is to be compiled * with {@link #compileMethod}. * diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java Mon May 06 20:05:19 2019 -0700 @@ -193,8 +193,7 @@ private static void printConfigLine(CompilerToVM vm, String format, Object... args) { String line = String.format(format, args); byte[] lineBytes = line.getBytes(); - vm.writeDebugOutput(lineBytes, 0, lineBytes.length); - vm.flushDebugOutput(); + vm.writeDebugOutput(lineBytes, 0, lineBytes.length, true, true); } } diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java Mon May 06 20:05:19 2019 -0700 @@ -49,16 +49,23 @@ return this; } - @Override - public String toString() { - return getMessage(); - } + private static Throwable create(String className, String message) { + // Try create with reflection first. + try { + Class cls = Class.forName(className); + if (message == null) { + return (Throwable) cls.getConstructor().newInstance(); + } + cls.getDeclaredConstructor(String.class); + return (Throwable) cls.getConstructor(String.class).newInstance(message); + } catch (Throwable ignore) { + } - private static TranslatedException create(String className, String message) { if (className.equals(TranslatedException.class.getName())) { // Chop the class name when boxing another TranslatedException return new TranslatedException(message); } + if (message == null) { return new TranslatedException(className); } @@ -147,7 +154,7 @@ Throwable throwable = create(exceptionClassName, exceptionMessage); int stackTraceDepth = Integer.parseInt(parts[i++]); - StackTraceElement[] suffix = parent == null ? new StackTraceElement[0] : getStackTraceSuffix(); + StackTraceElement[] suffix = getStackTraceSuffix(); StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length]; for (int j = 0; j < stackTraceDepth; j++) { String className = parts[i++]; diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java Mon May 06 20:05:19 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -38,13 +38,13 @@ * @return the simple name */ public static String getSimpleName(Class clazz, boolean withEnclosingClass) { - final String simpleName = clazz.getSimpleName(); + final String simpleName = safeSimpleName(clazz); if (simpleName.length() != 0) { if (withEnclosingClass) { String prefix = ""; Class enclosingClass = clazz; while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { - prefix = enclosingClass.getSimpleName() + "." + prefix; + prefix = safeSimpleName(enclosingClass) + "." + prefix; } return prefix + simpleName; } @@ -63,6 +63,29 @@ return name.substring(index + 1); } + private static String safeSimpleName(Class clazz) { + try { + return clazz.getSimpleName(); + } catch (InternalError e) { + // Scala inner class names do not always start with '$', + // causing Class.getSimpleName to throw an InternalError + Class enclosingClass = clazz.getEnclosingClass(); + String fqn = clazz.getName(); + if (enclosingClass == null) { + // Should never happen given logic in + // Class.getSimpleName but best be safe + return fqn; + } + String enclosingFQN = enclosingClass.getName(); + int length = fqn.length(); + if (enclosingFQN.length() >= length) { + // Should also never happen + return fqn; + } + return fqn.substring(enclosingFQN.length()); + } + } + /** * Converts a type name in internal form to an external form. * diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Mon May 06 20:05:19 2019 -0700 @@ -283,6 +283,17 @@ } /** + * A Java {@code char} has a maximal UTF8 length of 3. + */ + private static final int MAX_UNICODE_IN_UTF8_LENGTH = 3; + + /** + * {@link DataOutputStream#writeUTF(String)} only supports values whose UTF8 encoding length is + * less than 65535. + */ + private static final int MAX_UTF8_PROPERTY_STRING_LENGTH = 65535 / MAX_UNICODE_IN_UTF8_LENGTH; + + /** * Serializes the {@linkplain #getSavedProperties() saved system properties} to a byte array for * the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial * properties in the JVMCI shared library. @@ -292,25 +303,48 @@ if (IS_IN_NATIVE_IMAGE) { throw new InternalError("Can only serialize saved properties in HotSpot runtime"); } - Map props = Services.getSavedProperties(); + return serializeProperties(Services.getSavedProperties()); + } + private static byte[] serializeProperties(Map props) throws IOException { // Compute size of output on the assumption that // all system properties have ASCII names and values - int estimate = 4; + int estimate = 4 + 4; + int nonUtf8Props = 0; for (Map.Entry e : props.entrySet()) { String name = e.getKey(); String value = e.getValue(); estimate += (2 + (name.length())) + (2 + (value.length())); + if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) { + nonUtf8Props++; + } } ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate); DataOutputStream out = new DataOutputStream(baos); - out.writeInt(props.size()); + out.writeInt(props.size() - nonUtf8Props); + out.writeInt(nonUtf8Props); for (Map.Entry e : props.entrySet()) { String name = e.getKey(); String value = e.getValue(); - out.writeUTF(name); - out.writeUTF(value); + if (name.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH && value.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH) { + out.writeUTF(name); + out.writeUTF(value); + } + } + if (nonUtf8Props != 0) { + for (Map.Entry e : props.entrySet()) { + String name = e.getKey(); + String value = e.getValue(); + if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) { + byte[] utf8Name = name.getBytes("UTF-8"); + byte[] utf8Value = value.getBytes("UTF-8"); + out.writeInt(utf8Name.length); + out.write(utf8Name); + out.writeInt(utf8Value.length); + out.write(utf8Value); + } + } } return baos.toByteArray(); } @@ -325,13 +359,33 @@ if (!IS_IN_NATIVE_IMAGE) { throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime"); } + savedProperties = Collections.unmodifiableMap(deserializeProperties(serializedProperties)); + } + + private static Map deserializeProperties(byte[] serializedProperties) throws IOException { DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties)); - Map props = new HashMap<>(in.readInt()); + int utf8Props = in.readInt(); + int nonUtf8Props = in.readInt(); + Map props = new HashMap<>(utf8Props + nonUtf8Props); + int index = 0; while (in.available() != 0) { - String name = in.readUTF(); - String value = in.readUTF(); - props.put(name, value); + if (index < utf8Props) { + String name = in.readUTF(); + String value = in.readUTF(); + props.put(name, value); + } else { + int nameLen = in.readInt(); + byte[] nameBytes = new byte[nameLen]; + in.read(nameBytes); + int valueLen = in.readInt(); + byte[] valueBytes = new byte[valueLen]; + in.read(valueBytes); + String name = new String(nameBytes, "UTF-8"); + String value = new String(valueBytes, "UTF-8"); + props.put(name, value); + } + index++; } - savedProperties = Collections.unmodifiableMap(props); + return props; } } diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java Mon May 06 20:05:19 2019 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package jdk.vm.ci.services; + +/** + * Used to suppress FindBugs warnings. + */ +@interface SuppressFBWarnings { + /** + * The set of FindBugs + * warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.ci/share/classes/module-info.java --- a/src/jdk.internal.vm.ci/share/classes/module-info.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.ci/share/classes/module-info.java Mon May 06 20:05:19 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -30,6 +30,9 @@ exports jdk.vm.ci.runtime to jdk.internal.vm.compiler, jdk.internal.vm.compiler.management; + exports jdk.vm.ci.meta to jdk.internal.vm.compiler; + exports jdk.vm.ci.code to jdk.internal.vm.compiler; + exports jdk.vm.ci.hotspot to jdk.internal.vm.compiler; uses jdk.vm.ci.services.JVMCIServiceLocator; uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java Mon May 06 20:05:19 2019 -0700 @@ -43,6 +43,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; +import jdk.vm.ci.hotspot.HotSpotConstantPoolObject; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.Constant; @@ -83,7 +84,7 @@ public void generate(NodeLIRBuilderTool gen) { assert constant != null : "Expected the value to fold: " + value; Value result; - if (constant instanceof HotSpotObjectConstant) { + if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) { result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant); } else if (constant instanceof HotSpotMetaspaceConstant) { result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action); diff -r 81de17a33575 -r 2d012a75d35c src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java Tue May 07 10:21:04 2019 +0800 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java Mon May 06 20:05:19 2019 -0700 @@ -45,6 +45,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.word.Word; +import jdk.vm.ci.hotspot.HotSpotConstantPoolObject; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.Constant; @@ -100,7 +101,7 @@ Value result; LIRFrameState fs = gen.state(this); assert fs != null : "The stateAfter is null"; - if (constant instanceof HotSpotObjectConstant) { + if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) { result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs); } else if (constant instanceof HotSpotMetaspaceConstant) { if (action == HotSpotConstantLoadAction.RESOLVE) { diff -r 81de17a33575 -r 2d012a75d35c test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java --- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java Tue May 07 10:21:04 2019 +0800 +++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java Mon May 06 20:05:19 2019 -0700 @@ -301,7 +301,7 @@ } public static void writeDebugOutput(byte[] bytes, int offset, int length) { - CTVM.writeDebugOutput(bytes, offset, length); + CTVM.writeDebugOutput(bytes, offset, length, true, true); } public static void flushDebugOutput() { diff -r 81de17a33575 -r 2d012a75d35c test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java Mon May 06 20:05:19 2019 -0700 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018, 2019, 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. + */ +package jdk.vm.ci.hotspot.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class TestHotSpotJVMCIRuntime { + + @Test + public void writeDebugOutputTest() { + HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime(); + + expectWriteDebugOutputFailure(runtime, null, 0, 0, true, true, NullPointerException.class); + expectWriteDebugOutputFailure(runtime, null, 0, 0, true, false, -1); + + byte[] emptyOutput = {}; + byte[] nonEmptyOutput = String.format("non-empty output%n").getBytes(); + + for (boolean canThrow : new boolean[]{true, false}) { + for (byte[] output : new byte[][]{emptyOutput, nonEmptyOutput}) { + for (int offset = 0; offset < output.length; offset++) { + int length = output.length - offset; + runtime.writeDebugOutput(output, offset, length, true, canThrow); + } + + Object expect = canThrow ? IndexOutOfBoundsException.class : -2; + expectWriteDebugOutputFailure(runtime, output, output.length + 1, 0, true, canThrow, expect); + expectWriteDebugOutputFailure(runtime, output, 0, output.length + 1, true, canThrow, expect); + expectWriteDebugOutputFailure(runtime, output, -1, 0, true, canThrow, expect); + expectWriteDebugOutputFailure(runtime, output, 0, -1, true, canThrow, expect); + } + } + } + + private static void expectWriteDebugOutputFailure(HotSpotJVMCIRuntime runtime, byte[] bytes, int offset, int length, boolean flush, boolean canThrow, Object expect) { + try { + int result = runtime.writeDebugOutput(bytes, offset, length, flush, canThrow); + if (expect instanceof Integer) { + Assert.assertEquals((int) expect, result); + } else { + Assert.fail("expected " + expect + ", got " + result + " for bytes == " + Arrays.toString(bytes)); + } + } catch (Exception e) { + if (expect instanceof Integer) { + Assert.fail("expected " + expect + ", got " + e + " for bytes == " + Arrays.toString(bytes)); + } else { + Assert.assertTrue(e.toString(), ((Class) expect).isInstance(e)); + } + } + } + + @Test + public void getIntrinsificationTrustPredicateTest() throws Exception { + HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime(); + MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess(); + Predicate predicate = runtime.getIntrinsificationTrustPredicate(HotSpotJVMCIRuntime.class); + List> classes = new ArrayList<>(Arrays.asList( + Object.class, + String.class, + Class.class, + HotSpotJVMCIRuntime.class, + VirtualObjectLayoutTest.class, + TestHotSpotJVMCIRuntime.class)); + try { + classes.add(Class.forName("com.sun.crypto.provider.AESCrypt")); + classes.add(Class.forName("com.sun.crypto.provider.CipherBlockChaining")); + } catch (ClassNotFoundException e) { + // Extension classes not available + } + ClassLoader jvmciLoader = HotSpotJVMCIRuntime.class.getClassLoader(); + ClassLoader extLoader = getExtensionLoader(); + for (Class c : classes) { + ClassLoader cl = c.getClassLoader(); + boolean expected = cl == null || cl == jvmciLoader || cl == extLoader; + boolean actual = predicate.test(metaAccess.lookupJavaType(c)); + Assert.assertEquals(c + ": cl=" + cl, expected, actual); + } + } + + private static ClassLoader getExtensionLoader() throws Exception { + Object launcher = Class.forName("sun.misc.Launcher").getMethod("getLauncher").invoke(null); + ClassLoader appLoader = (ClassLoader) launcher.getClass().getMethod("getClassLoader").invoke(launcher); + ClassLoader extLoader = appLoader.getParent(); + assert extLoader.getClass().getName().equals("sun.misc.Launcher$ExtClassLoader") : extLoader; + return extLoader; + } +} diff -r 81de17a33575 -r 2d012a75d35c test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestServices.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestServices.java Mon May 06 20:05:19 2019 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, 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. + */ +package jdk.vm.ci.hotspot.test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.services.Services; + +public class TestServices { + + @SuppressWarnings("unchecked") + @Test + public void serializeSavedPropertiesTest() throws Exception { + + Field f = Services.class.getDeclaredField("MAX_UTF8_PROPERTY_STRING_LENGTH"); + f.setAccessible(true); + int maxUtf8PropertyStringLength = (int) f.get(null); + + Method serializeProperties = Services.class.getDeclaredMethod("serializeProperties", Map.class); + Method deserializeProperties = Services.class.getDeclaredMethod("deserializeProperties", byte[].class); + serializeProperties.setAccessible(true); + deserializeProperties.setAccessible(true); + + Map props = new HashMap<>(Services.getSavedProperties()); + String[] names = { + new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', 'x'), + new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', 'x'), + new String(new char[maxUtf8PropertyStringLength]).replace('\0', 'y'), + new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', 'z'), + new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', 'z') + }; + String[] values = { + new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', '1'), + new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', '1'), + new String(new char[maxUtf8PropertyStringLength]).replace('\0', '2'), + new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', '1'), + new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', '3') + }; + for (String name : names) { + for (String value : values) { + props.put(name, value); + } + } + + byte[] data = (byte[]) serializeProperties.invoke(null, props); + + Map newProps = (Map) deserializeProperties.invoke(null, data); + + Assert.assertEquals(props.size(), newProps.size()); + for (String name : props.keySet()) { + String expect = props.get(name); + String actual = newProps.get(name); + Assert.assertEquals(expect, actual); + } + } +} diff -r 81de17a33575 -r 2d012a75d35c test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java --- a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java Tue May 07 10:21:04 2019 +0800 +++ b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java Mon May 06 20:05:19 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, 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 @@ -71,6 +71,9 @@ static Set KNOWN_EXCEPTIONS = Set.of("jdk.internal.vm.ci/jdk.vm.ci.services", "jdk.internal.vm.ci/jdk.vm.ci.runtime", + "jdk.internal.vm.ci/jdk.vm.ci.hotspot", + "jdk.internal.vm.ci/jdk.vm.ci.meta", + "jdk.internal.vm.ci/jdk.vm.ci.code", "jdk.jsobject/jdk.internal.netscape.javascript.spi"); static void checkExports(ModuleDescriptor md) {