# HG changeset patch # User vlivanov # Date 1455557162 -10800 # Node ID 11263906664c3614ac7c549fea6ae8d5f437497f # Parent 1c0381cc1e1d5aabb7420d305c2a6144c1b08c7f 8138922: StubCodeDesc constructor publishes partially-constructed objects on StubCodeDesc::_list Reviewed-by: kvn, coleenp, dholmes diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/code/codeBlob.cpp --- a/hotspot/src/share/vm/code/codeBlob.cpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/code/codeBlob.cpp Mon Feb 15 20:26:02 2016 +0300 @@ -291,6 +291,9 @@ { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = new (size) MethodHandlesAdapterBlob(size); + if (blob == NULL) { + vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for method handle adapter blob"); + } } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Mon Feb 15 20:26:02 2016 +0300 @@ -63,30 +63,21 @@ bool MethodHandles::_enabled = false; // set true after successful native linkage MethodHandlesAdapterBlob* MethodHandles::_adapter_code = NULL; - /** * Generates method handle adapters. Returns 'false' if memory allocation * failed and true otherwise. */ -bool MethodHandles::generate_adapters() { - if (SystemDictionary::MethodHandle_klass() == NULL) { - return true; - } - +void MethodHandles::generate_adapters() { + assert(SystemDictionary::MethodHandle_klass() != NULL, "should be present"); assert(_adapter_code == NULL, "generate only once"); ResourceMark rm; TraceTime timer("MethodHandles adapters generation", TraceStartupTime); _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size); - if (_adapter_code == NULL) { - return false; - } - CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); g.generate(); code.log_section_sizes("MethodHandlesAdapterBlob"); - return true; } //------------------------------------------------------------------------------ @@ -1436,53 +1427,31 @@ }; /** - * Helper method to register native methods. - */ -static bool register_natives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, jint nMethods) { - int status = env->RegisterNatives(clazz, methods, nMethods); - if (status != JNI_OK || env->ExceptionOccurred()) { - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - env->ExceptionClear(); - return false; - } - return true; -} - -/** * This one function is exported, used by NativeLookup. */ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { assert(!MethodHandles::enabled(), "must not be enabled"); - bool enable_MH = true; + assert(SystemDictionary::MethodHandle_klass() != NULL, "should be present"); - jclass MH_class = NULL; - if (SystemDictionary::MethodHandle_klass() == NULL) { - enable_MH = false; - } else { - oop mirror = SystemDictionary::MethodHandle_klass()->java_mirror(); - MH_class = (jclass) JNIHandles::make_local(env, mirror); - } + oop mirror = SystemDictionary::MethodHandle_klass()->java_mirror(); + jclass MH_class = (jclass) JNIHandles::make_local(env, mirror); - if (enable_MH) { + { ThreadToNativeFromVM ttnfv(thread); - if (enable_MH) { - enable_MH = register_natives(env, MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod)); - } - if (enable_MH) { - enable_MH = register_natives(env, MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); - } + int status = env->RegisterNatives(MHN_class, MHN_methods, sizeof(MHN_methods)/sizeof(JNINativeMethod)); + guarantee(status == JNI_OK && !env->ExceptionOccurred(), + "register java.lang.invoke.MethodHandleNative natives"); + + status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); + guarantee(status == JNI_OK && !env->ExceptionOccurred(), + "register java.lang.invoke.MethodHandle natives"); } if (TraceInvokeDynamic) { tty->print_cr("MethodHandle support loaded (using LambdaForms)"); } - if (enable_MH) { - if (MethodHandles::generate_adapters() == false) { - THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "Out of space in CodeCache for method handle adapters"); - } - MethodHandles::set_enabled(true); - } + MethodHandles::set_enabled(true); } JVM_END diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/prims/methodHandles.hpp --- a/hotspot/src/share/vm/prims/methodHandles.hpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/prims/methodHandles.hpp Mon Feb 15 20:26:02 2016 +0300 @@ -81,7 +81,7 @@ static void flush_dependent_nmethods(Handle call_site, Handle target); // Generate MethodHandles adapters. - static bool generate_adapters(); + static void generate_adapters(); // Called from MethodHandlesAdapterGenerator. static address generate_method_handle_interpreter_entry(MacroAssembler* _masm, vmIntrinsics::ID iid); diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/runtime/init.cpp --- a/hotspot/src/share/vm/runtime/init.cpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/runtime/init.cpp Mon Feb 15 20:26:02 2016 +0300 @@ -145,6 +145,7 @@ } javaClasses_init(); // must happen after vtable initialization stubRoutines_init2(); // note: StubRoutines need 2-phase init + MethodHandles::generate_adapters(); CodeCacheExtensions::complete_step(CodeCacheExtensionsSteps::StubRoutines2); #if INCLUDE_NMT diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/runtime/stubCodeGenerator.cpp --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Mon Feb 15 20:26:02 2016 +0300 @@ -37,7 +37,7 @@ StubCodeDesc* StubCodeDesc::_list = NULL; int StubCodeDesc::_count = 0; - +bool StubCodeDesc::_frozen = false; StubCodeDesc* StubCodeDesc::desc_for(address pc) { StubCodeDesc* p = _list; @@ -46,20 +46,23 @@ return p; } - StubCodeDesc* StubCodeDesc::desc_for_index(int index) { StubCodeDesc* p = _list; while (p != NULL && p->index() != index) p = p->_next; return p; } - const char* StubCodeDesc::name_for(address pc) { StubCodeDesc* p = desc_for(pc); return p == NULL ? NULL : p->name(); } +void StubCodeDesc::freeze() { + assert(!_frozen, "repeated freeze operation"); + _frozen = true; +} + void StubCodeDesc::print_on(outputStream* st) const { st->print("%s", group()); st->print("::"); @@ -110,12 +113,10 @@ } } - void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) { // default implementation - do nothing } - void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { // default implementation - record the cdesc if (_first_stub == NULL) _first_stub = cdesc; diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/runtime/stubCodeGenerator.hpp --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp Mon Feb 15 20:26:02 2016 +0300 @@ -28,7 +28,7 @@ #include "asm/assembler.hpp" #include "memory/allocation.hpp" -// All the basic framework for stubcode generation/debugging/printing. +// All the basic framework for stub code generation/debugging/printing. // A StubCodeDesc describes a piece of generated code (usually stubs). @@ -37,9 +37,10 @@ // this may have to change if searching becomes too slow. class StubCodeDesc: public CHeapObj { - protected: + private: static StubCodeDesc* _list; // the list of all descriptors static int _count; // length of list + static bool _frozen; // determines whether _list modifications are allowed StubCodeDesc* _next; // the next element in the linked list const char* _group; // the group to which the stub code belongs @@ -68,6 +69,7 @@ static const char* name_for(address pc); // returns the name of the code containing pc or NULL StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) { + assert(!_frozen, "no modifications allowed"); assert(name != NULL, "no name specified"); _next = _list; _group = group; @@ -78,6 +80,8 @@ _list = this; }; + static void freeze(); + const char* group() const { return _group; } const char* name() const { return _name; } int index() const { return _index; } @@ -117,7 +121,7 @@ // later via an address pointing into it. class StubCodeMark: public StackObj { - protected: + private: StubCodeGenerator* _cgen; StubCodeDesc* _cdesc; diff -r 1c0381cc1e1d -r 11263906664c hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Mon Feb 15 20:02:51 2016 +0300 +++ b/hotspot/src/share/vm/runtime/thread.cpp Mon Feb 15 20:26:02 2016 +0300 @@ -3600,6 +3600,9 @@ vm_exit_during_initialization("Failed to initialize tracing backend"); } + // No more stub generation allowed after that point. + StubCodeDesc::freeze(); + // Set flag that basic initialization has completed. Used by exceptions and various // debug stuff, that does not work until all basic classes have been initialized. set_init_completed();