# HG changeset patch # User andrew # Date 1598507145 -3600 # Thu Aug 27 06:45:45 2020 +0100 # Node ID 0bb5fba5f9b2b35e8f5432b4e4164eb951c7bf6a # Parent bbb544bc4e856ffa306b3b7c6a8e9edc873f521f # Parent 6898cbe6d575295fc708d6d0b72cb0f5ff549ae6 Merge jdk8u272-b05 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1501,3 +1501,4 @@ f83192268a5a92e43e4f06bc616f56b503d4b12f aarch64-shenandoah-jdk8u272-b03 cbabffce5685f9a18bfd05bd1fb18c4c73be98cf jdk8u272-b04 f9a4ff26a4bda97390d178b64afd7aa21a6f8983 aarch64-shenandoah-jdk8u272-b04 +1b2d99958c293b7ab324c5786664f82c8e9c4e50 jdk8u272-b05 diff --git a/make/excludeSrc.make b/make/excludeSrc.make --- a/make/excludeSrc.make +++ b/make/excludeSrc.make @@ -95,6 +95,7 @@ gc_shared_keep := \ adaptiveSizePolicy.cpp \ ageTable.cpp \ + ageTableTracer.cpp \ collectorCounters.cpp \ cSpaceCounters.cpp \ gcId.cpp \ diff --git a/make/linux/makefiles/mapfile-vers-debug b/make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug +++ b/make/linux/makefiles/mapfile-vers-debug @@ -190,6 +190,7 @@ JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsUseContainerSupport; JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; diff --git a/make/linux/makefiles/mapfile-vers-product b/make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product +++ b/make/linux/makefiles/mapfile-vers-product @@ -185,6 +185,7 @@ JVM_IsInterface; JVM_IsInterrupted; JVM_IsNaN; + JVM_IsUseContainerSupport; JVM_IsPrimitiveClass; JVM_IsSameClassPackage; JVM_IsSilentCompiler; diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -3096,7 +3096,10 @@ } void do_object_work(oop obj) { - guarantee(!_g1h->obj_in_cs(obj), + guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || obj->is_oop(), + err_msg("Non-oop " PTR_FORMAT ", phase: %s, info: %d", + p2i((void*) obj), phase_str(), _info)); + guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->obj_in_cs(obj), err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", p2i((void*) obj), phase_str(), _info)); } @@ -3506,18 +3509,25 @@ template inline void CMTask::process_grey_object(oop obj) { assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); - assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } - size_t obj_size = obj->size(); - _words_scanned += obj_size; + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked((HeapWord*) obj), + "Any stolen object should be a slice or marked"); if (scan) { - obj->oop_iterate(_cm_oop_closure); + if (G1CMObjArrayProcessor::is_array_slice(obj)) { + _words_scanned += _objArray_processor.process_slice(obj); + } else if (G1CMObjArrayProcessor::should_be_sliced(obj)) { + _words_scanned += _objArray_processor.process_obj(obj); + } else { + size_t obj_size = obj->size(); + _words_scanned += obj_size; + obj->oop_iterate(_cm_oop_closure);; + } } statsOnly( ++_objs_scanned ); check_limits(); @@ -3877,6 +3887,8 @@ _worker_id, n); } for (int i = 0; i < n; ++i) { + assert(G1CMObjArrayProcessor::is_array_slice(buffer[i]) || buffer[i]->is_oop(), + err_msg("Element " PTR_FORMAT " must be an array slice or oop", p2i(buffer[i]))); bool success = _task_queue->push(buffer[i]); // We only call this when the local queue is empty or under a // given target limit. So, we do not expect this push to fail. @@ -3895,7 +3907,9 @@ } void CMTask::drain_local_queue(bool partially) { - if (has_aborted()) return; + if (has_aborted()) { + return; + } // Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out @@ -3923,10 +3937,6 @@ p2i((void*) obj)); } - assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" ); - assert(!_g1h->is_on_master_free_list( - _g1h->heap_region_containing((HeapWord*) obj)), "invariant"); - scan_object(obj); if (_task_queue->size() <= target_size || has_aborted()) { @@ -4427,8 +4437,6 @@ statsOnly( ++_steals ); - assert(_nextMarkBitMap->isMarked((HeapWord*) obj), - "any stolen object should be marked"); scan_object(obj); // And since we're towards the end, let's totally drain the @@ -4602,6 +4610,7 @@ CMTaskQueueSet* task_queues) : _g1h(G1CollectedHeap::heap()), _worker_id(worker_id), _cm(cm), + _objArray_processor(this), _claimed(false), _nextMarkBitMap(NULL), _hash_seed(17), _task_queue(task_queue), diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_HPP #include "classfile/javaClasses.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp" #include "gc_implementation/g1/heapRegionSet.hpp" #include "gc_implementation/g1/g1RegionToSpaceMapper.hpp" #include "gc_implementation/shared/gcId.hpp" @@ -942,7 +943,7 @@ words_scanned_period = 12*1024, // the regular clock call is called once the number of visited // references reaches this limit - refs_reached_period = 384, + refs_reached_period = 1024, // initial value for the hash seed, used in the work stealing code init_hash_seed = 17, // how many entries will be transferred between global stack and @@ -950,6 +951,8 @@ global_stack_transfer_size = 16 }; + G1CMObjArrayProcessor _objArray_processor; + uint _worker_id; G1CollectedHeap* _g1h; ConcurrentMark* _cm; @@ -1110,6 +1113,9 @@ template void process_grey_object(oop obj); public: + // Apply the closure on the given area of the objArray. Return the number of words + // scanned. + inline size_t scan_objArray(objArrayOop obj, MemRegion mr); // It resets the task; it should be called right at the beginning of // a marking phase. void reset(CMBitMap* _nextMarkBitMap); diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -27,6 +27,7 @@ #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" // Utility routine to set an exclusive range of cards on the given // card liveness bitmap @@ -224,11 +225,11 @@ inline void CMTask::push(oop obj) { HeapWord* objAddr = (HeapWord*) obj; - assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); - assert(!_g1h->is_on_master_free_list( + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _g1h->is_in_g1_reserved(objAddr), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_on_master_free_list( _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant"); - assert(!_g1h->is_obj_ill(obj), "invariant"); - assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_obj_ill(obj), "invariant"); + assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked(objAddr), "invariant"); if (_cm->verbose_high()) { gclog_or_tty->print_cr("[%u] pushing " PTR_FORMAT, _worker_id, p2i((void*) obj)); @@ -365,6 +366,11 @@ } } +inline size_t CMTask::scan_objArray(objArrayOop obj, MemRegion mr) { + obj->oop_iterate(_cm_oop_closure, mr); + return mr.word_size(); +} + inline void ConcurrentMark::markPrev(oop p) { assert(!_prevMarkBitMap->isMarked((HeapWord*) p), "sanity"); // Note we are overriding the read-only view of the prev map here, via diff --git a/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.cpp b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.cpp new file mode 100644 --- /dev/null +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/concurrentMark.inline.hpp" +#include "gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp" + +oop G1CMObjArrayProcessor::encode_array_slice(HeapWord* addr) { + return oop((void*)((uintptr_t)addr | ArraySliceBit)); +} + +HeapWord* G1CMObjArrayProcessor::decode_array_slice(oop value) { + assert(is_array_slice(value), err_msg("Given value " PTR_FORMAT " is not an array slice", p2i(value))); + return (HeapWord*)((uintptr_t)(void*)value & ~ArraySliceBit); +} + +void G1CMObjArrayProcessor::push_array_slice(HeapWord* what) { + oop obj = encode_array_slice(what); + _task->push(obj); +} + +size_t G1CMObjArrayProcessor::process_array_slice(objArrayOop obj, HeapWord* start_from, size_t remaining) { + size_t words_to_scan = MIN2(remaining, ObjArrayMarkingStride); + + if (remaining > ObjArrayMarkingStride) { + push_array_slice(start_from + ObjArrayMarkingStride); + } + + // Then process current area. + MemRegion mr(start_from, words_to_scan); + return _task->scan_objArray(obj, mr); +} + +size_t G1CMObjArrayProcessor::process_obj(oop obj) { + assert(should_be_sliced(obj), err_msg("Must be an array object %d and large " SIZE_FORMAT, obj->is_objArray(), (size_t)obj->size())); + + return process_array_slice(objArrayOop(obj), (HeapWord*)obj, (size_t)objArrayOop(obj)->size()); +} + +size_t G1CMObjArrayProcessor::process_slice(oop obj) { + HeapWord* const decoded_address = decode_array_slice(obj); + + // Find the start address of the objArrayOop. + // Shortcut the BOT access if the given address is from a humongous object. The BOT + // slide is fast enough for "smaller" objects in non-humongous regions, but is slower + // than directly using heap region table. + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* r = g1h->heap_region_containing(decoded_address); + + HeapWord* const start_address = r->isHumongous() ? + r->humongous_start_region()->bottom() : + g1h->block_start(decoded_address); + + assert(oop(start_address)->is_objArray(), err_msg("Address " PTR_FORMAT " does not refer to an object array ", p2i(start_address))); + assert(start_address < decoded_address, + err_msg("Object start address " PTR_FORMAT " must be smaller than decoded address " PTR_FORMAT, + p2i(start_address), + p2i(decoded_address))); + + objArrayOop objArray = objArrayOop(start_address); + + size_t already_scanned = decoded_address - start_address; + size_t remaining = objArray->size() - already_scanned; + + return process_array_slice(objArray, decoded_address, remaining); +} diff --git a/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp new file mode 100644 --- /dev/null +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP +#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP + +#include "oops/oopsHierarchy.hpp" +#include "memory/allocation.hpp" + +class CMTask; + +// Helper class to mark through large objArrays during marking in an efficient way. +// Instead of pushing large object arrays, we push continuations onto the +// mark stack. These continuations are identified by having their LSB set. +// This allows incremental processing of large objects. +class G1CMObjArrayProcessor VALUE_OBJ_CLASS_SPEC { +private: + // The bit mask for the continuation indicator of elements on the mark stack. + static const size_t ArraySliceBit = 1; + + // Reference to the task for doing the actual work. + CMTask* _task; + + // Encodes the given address as a continuation "oop". + oop encode_array_slice(HeapWord* addr); + // Remove the continuation marker from the given oop from the mark stack. + HeapWord* decode_array_slice(oop value); + + // Push the continuation at the given address onto the mark stack. + void push_array_slice(HeapWord* addr); + + // Process (apply the closure) on the given continuation of the given objArray. + size_t process_array_slice(objArrayOop const obj, HeapWord* start_from, size_t remaining); +public: + static bool is_array_slice(void* obj) { return ((uintptr_t)obj & ArraySliceBit) != 0; } + + static bool should_be_sliced(oop obj); + + G1CMObjArrayProcessor(CMTask* task) : _task(task) { + } + + // Process the given continuation "oop". Returns the number of words scanned. + size_t process_slice(oop obj); + // Start processing the given objArrayOop by scanning the header and pushing its + // continuation. + size_t process_obj(oop obj); +}; + +#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP */ diff --git a/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp new file mode 100644 --- /dev/null +++ b/src/share/vm/gc_implementation/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP +#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP + +#include "oops/oop.inline.hpp" +#include "oops/oopsHierarchy.hpp" +#include "runtime/globals.hpp" + +inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) { + return obj->is_objArray() && ((size_t)((objArrayOop)obj)->size()) >= 2 * ObjArrayMarkingStride; +} + +#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP */ diff --git a/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp b/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp --- a/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp +++ b/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -31,9 +31,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrEventClass.hpp" #include "memory/resourceArea.hpp" -#include "prims/jvmtiEnvBase.hpp" #include "prims/jvmtiExport.hpp" -#include "prims/jvmtiUtil.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/thread.inline.hpp" #include "utilities/exceptions.hpp" @@ -53,17 +51,19 @@ } } -static bool set_event_notification_mode(jvmtiEventMode mode, - jvmtiEvent event, - jthread event_thread, - ...) { - assert(jfr_jvmti_env != NULL, "invariant"); +static jvmtiError set_event_notification_mode(jvmtiEventMode mode, + jvmtiEvent event, + jthread event_thread, + ...) { + if (jfr_jvmti_env == NULL) { + return JVMTI_ERROR_NONE; + } const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } -static bool update_class_file_load_hook_event(jvmtiEventMode mode) { +static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) { return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); } @@ -116,23 +116,12 @@ return classes; } -// caller needs ResourceMark -static void log_and_throw(jvmtiError error, TRAPS) { +static void log_and_throw(TRAPS) { if (!HAS_PENDING_EXCEPTION) { DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); ThreadInVMfromNative tvmfn((JavaThread*)THREAD); - const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: "; - size_t length = sizeof base_error_msg; // includes terminating null - const char* const jvmti_error_name = JvmtiUtil::error_name(error); - assert(jvmti_error_name != NULL, "invariant"); - length += strlen(jvmti_error_name); - char* error_msg = NEW_RESOURCE_ARRAY(char, length); - jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name); - if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) { - JfrJavaSupport::throw_class_format_error(error_msg, THREAD); - } else { - JfrJavaSupport::throw_runtime_exception(error_msg, THREAD); - } + if (true) tty->print_cr("JfrJvmtiAgent::retransformClasses failed"); + JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD); } } @@ -147,15 +136,12 @@ } } -static bool is_valid_jvmti_phase() { - return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE; -} - void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { assert(env != NULL, "invariant"); - assert(classes_array != NULL, "invariant"); - assert(is_valid_jvmti_phase(), "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); + if (classes_array == NULL) { + return; + } const jint classes_count = env->GetArrayLength(classes_array); if (classes_count <= 0) { return; @@ -166,27 +152,27 @@ for (jint i = 0; i < classes_count; i++) { jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); check_exception_and_log(env, THREAD); - classes[i] = clz; - } - { + // inspecting the oop/klass requires a thread transition - ThreadInVMfromNative transition((JavaThread*)THREAD); - for (jint i = 0; i < classes_count; ++i) { - jclass clz = classes[i]; - if (!JdkJfrEvent::is_a(clz)) { + { + ThreadInVMfromNative transition((JavaThread*)THREAD); + if (JdkJfrEvent::is_a(clz)) { + // should have been tagged already + assert(JdkJfrEvent::is_subklass(clz), "invariant"); + } else { // outside the event hierarchy JdkJfrEvent::tag_as_host(clz); } } + + classes[i] = clz; } - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); - const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes); - if (result != JVMTI_ERROR_NONE) { - log_and_throw(result, THREAD); + if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { + log_and_throw(THREAD); } } -static bool register_callbacks(JavaThread* jt) { +static jvmtiError register_callbacks(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiEventCallbacks callbacks; @@ -195,10 +181,10 @@ callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } -static bool register_capabilities(JavaThread* jt) { +static jvmtiError register_capabilities(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiCapabilities capabilities; @@ -208,7 +194,7 @@ capabilities.can_retransform_any_class = 1; const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } static jint create_jvmti_env(JavaThread* jt) { @@ -219,14 +205,16 @@ return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); } -static bool unregister_callbacks(JavaThread* jt) { - assert(jfr_jvmti_env != NULL, "invariant"); +static jvmtiError unregister_callbacks(JavaThread* jt) { + if (jfr_jvmti_env == NULL) { + return JVMTI_ERROR_NONE; + } jvmtiEventCallbacks callbacks; /* Set empty callbacks */ memset(&callbacks, 0, sizeof(callbacks)); const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code == JVMTI_ERROR_NONE; + return jvmti_ret_code; } JfrJvmtiAgent::JfrJvmtiAgent() {} @@ -234,17 +222,20 @@ JfrJvmtiAgent::~JfrJvmtiAgent() { JavaThread* jt = current_java_thread(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); + ThreadToNativeFromVM transition(jt); + update_class_file_load_hook_event(JVMTI_DISABLE); + unregister_callbacks(jt); if (jfr_jvmti_env != NULL) { - ThreadToNativeFromVM transition(jt); - update_class_file_load_hook_event(JVMTI_DISABLE); - unregister_callbacks(jt); jfr_jvmti_env->DisposeEnvironment(); jfr_jvmti_env = NULL; } + agent = NULL; } -static bool initialize(JavaThread* jt) { +static bool initialize() { + JavaThread* const jt = current_java_thread(); assert(jt != NULL, "invariant"); + assert(jt->thread_state() == _thread_in_vm, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); ThreadToNativeFromVM transition(jt); if (create_jvmti_env(jt) != JNI_OK) { @@ -252,38 +243,25 @@ return false; } assert(jfr_jvmti_env != NULL, "invariant"); - if (!register_capabilities(jt)) { - return false; - } - if (!register_callbacks(jt)) { + if (register_capabilities(jt) != JVMTI_ERROR_NONE) { return false; } - return update_class_file_load_hook_event(JVMTI_ENABLE); -} - -static void log_and_throw_illegal_state_exception(TRAPS) { - DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); - const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence."; - if (true) { - tty->print_cr("%s\n", illegal_state_msg); - tty->print_cr("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE.\n"); - tty->print_cr("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START.\n"); + if (register_callbacks(jt) != JVMTI_ERROR_NONE) { + return false; } - JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD); + if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { + return false; + } + return true; } bool JfrJvmtiAgent::create() { - assert(agent == NULL, "invariant"); - JavaThread* const jt = current_java_thread(); - if (!is_valid_jvmti_phase()) { - log_and_throw_illegal_state_exception(jt); - return false; - } + assert(jfr_jvmti_env == NULL, "invariant"); agent = new JfrJvmtiAgent(); if (agent == NULL) { return false; } - if (!initialize(jt)) { + if (!initialize()) { delete agent; agent = NULL; return false; @@ -297,3 +275,4 @@ agent = NULL; } } + diff --git a/src/share/vm/jfr/jfr.cpp b/src/share/vm/jfr/jfr.cpp --- a/src/share/vm/jfr/jfr.cpp +++ b/src/share/vm/jfr/jfr.cpp @@ -32,7 +32,6 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "runtime/java.hpp" -#include "utilities/defaultStream.hpp" bool Jfr::is_enabled() { return JfrRecorder::is_enabled(); @@ -46,21 +45,15 @@ return JfrRecorder::is_recording(); } -void Jfr::on_create_vm_1() { - if (!JfrRecorder::on_create_vm_1()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_1"); +void Jfr::on_vm_init() { + if (!JfrRecorder::on_vm_init()) { + vm_exit_during_initialization("Failure when starting JFR on_vm_init"); } } -void Jfr::on_create_vm_2() { - if (!JfrRecorder::on_create_vm_2()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_2"); - } -} - -void Jfr::on_create_vm_3() { - if (!JfrRecorder::on_create_vm_3()) { - vm_exit_during_initialization("Failure when starting JFR on_create_vm_3"); +void Jfr::on_vm_start() { + if (!JfrRecorder::on_vm_start()) { + vm_exit_during_initialization("Failure when starting JFR on_vm_start"); } } diff --git a/src/share/vm/jfr/jfr.hpp b/src/share/vm/jfr/jfr.hpp --- a/src/share/vm/jfr/jfr.hpp +++ b/src/share/vm/jfr/jfr.hpp @@ -43,9 +43,8 @@ static bool is_enabled(); static bool is_disabled(); static bool is_recording(); - static void on_create_vm_1(); - static void on_create_vm_2(); - static void on_create_vm_3(); + static void on_vm_init(); + static void on_vm_start(); static void on_unloading_classes(); static void on_thread_start(Thread* thread); static void on_thread_exit(Thread* thread); diff --git a/src/share/vm/jfr/jni/jfrJavaSupport.cpp b/src/share/vm/jfr/jni/jfrJavaSupport.cpp --- a/src/share/vm/jfr/jni/jfrJavaSupport.cpp +++ b/src/share/vm/jfr/jni/jfrJavaSupport.cpp @@ -515,10 +515,6 @@ create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD); } -void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) { - create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD); -} - void JfrJavaSupport::abort(jstring errorMsg, Thread* t) { DEBUG_ONLY(check_java_thread_in_vm(t)); diff --git a/src/share/vm/jfr/jni/jfrJavaSupport.hpp b/src/share/vm/jfr/jni/jfrJavaSupport.hpp --- a/src/share/vm/jfr/jni/jfrJavaSupport.hpp +++ b/src/share/vm/jfr/jni/jfrJavaSupport.hpp @@ -81,7 +81,6 @@ static void throw_internal_error(const char* message, TRAPS); static void throw_out_of_memory_error(const char* message, TRAPS); static void throw_class_format_error(const char* message, TRAPS); - static void throw_runtime_exception(const char* message, TRAPS); static jlong jfr_thread_id(jobject target_thread); diff --git a/src/share/vm/jfr/jni/jfrJniMethod.cpp b/src/share/vm/jfr/jni/jfrJniMethod.cpp --- a/src/share/vm/jfr/jni/jfrJniMethod.cpp +++ b/src/share/vm/jfr/jni/jfrJniMethod.cpp @@ -191,9 +191,7 @@ return JNI_TRUE; } if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) { - if (!thread->has_pending_exception()) { - JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); - } + JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); return JNI_FALSE; } return JNI_TRUE; diff --git a/src/share/vm/jfr/recorder/jfrRecorder.cpp b/src/share/vm/jfr/recorder/jfrRecorder.cpp --- a/src/share/vm/jfr/recorder/jfrRecorder.cpp +++ b/src/share/vm/jfr/recorder/jfrRecorder.cpp @@ -44,9 +44,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/globals_extension.hpp" #include "utilities/growableArray.hpp" -#ifdef ASSERT -#include "prims/jvmtiEnvBase.hpp" -#endif bool JfrRecorder::_shutting_down = false; @@ -60,9 +57,7 @@ static bool enable() { assert(!_enabled, "invariant"); - if (!FlightRecorder) { - FLAG_SET_MGMT(bool, FlightRecorder, true); - } + FLAG_SET_MGMT(bool, FlightRecorder, true); _enabled = FlightRecorder; assert(_enabled, "invariant"); return _enabled; @@ -72,7 +67,7 @@ return _enabled; } -bool JfrRecorder::on_create_vm_1() { +bool JfrRecorder::on_vm_init() { if (!is_disabled()) { if (FlightRecorder || StartFlightRecording != NULL) { enable(); @@ -97,7 +92,7 @@ static void teardown_startup_support() { release_recordings(); - JfrOptionSet::release_start_flight_recording_options(); + JfrOptionSet::release_startup_recording_options(); } // Parsing options here to detect errors as soon as possible @@ -115,7 +110,7 @@ } static bool validate_recording_options(TRAPS) { - const GrowableArray* options = JfrOptionSet::start_flight_recording_options(); + const GrowableArray* options = JfrOptionSet::startup_recording_options(); if (options == NULL) { return true; } @@ -148,7 +143,7 @@ return true; } -static bool launch_command_line_recordings(TRAPS) { +static bool launch_recordings(TRAPS) { bool result = true; if (dcmd_recordings_array != NULL) { const int length = dcmd_recordings_array->length(); @@ -166,7 +161,7 @@ static bool is_cds_dump_requested() { // we will not be able to launch recordings if a cds dump is being requested - if (DumpSharedSpaces && (JfrOptionSet::start_flight_recording_options() != NULL)) { + if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) { warning("JFR will be disabled during CDS dumping"); teardown_startup_support(); return true; @@ -174,7 +169,7 @@ return false; } -bool JfrRecorder::on_create_vm_2() { +bool JfrRecorder::on_vm_start() { if (is_cds_dump_requested()) { return true; } @@ -201,14 +196,10 @@ if (!is_enabled()) { return true; } - return true; + + return launch_recordings(thread); } -bool JfrRecorder::on_create_vm_3() { - assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); - return launch_command_line_recordings(Thread::current()); - } - static bool _created = false; // @@ -275,6 +266,7 @@ } // subsystems +static JfrJvmtiAgent* _jvmti_agent = NULL; static JfrPostBox* _post_box = NULL; static JfrStorage* _storage = NULL; static JfrCheckpointManager* _checkpoint_manager = NULL; diff --git a/src/share/vm/jfr/recorder/jfrRecorder.hpp b/src/share/vm/jfr/recorder/jfrRecorder.hpp --- a/src/share/vm/jfr/recorder/jfrRecorder.hpp +++ b/src/share/vm/jfr/recorder/jfrRecorder.hpp @@ -40,9 +40,6 @@ private: static bool _shutting_down; - static bool on_create_vm_1(); - static bool on_create_vm_2(); - static bool on_create_vm_3(); static bool create_checkpoint_manager(); static bool create_chunk_repository(); static bool create_java_event_writer(); @@ -57,6 +54,8 @@ static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); + static bool on_vm_start(); + static bool on_vm_init(); public: static bool is_enabled(); diff --git a/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp b/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp --- a/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp @@ -676,7 +676,7 @@ return false; } -static GrowableArray* start_flight_recording_options_array = NULL; +static GrowableArray* startup_recording_options_array = NULL; bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { assert(option != NULL, "invariant"); @@ -699,28 +699,28 @@ assert(value != NULL, "invariant"); const size_t value_length = strlen(value); - if (start_flight_recording_options_array == NULL) { - start_flight_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(8, true, mtTracing); + if (startup_recording_options_array == NULL) { + startup_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(8, true, mtTracing); } - assert(start_flight_recording_options_array != NULL, "invariant"); + assert(startup_recording_options_array != NULL, "invariant"); char* const startup_value = NEW_C_HEAP_ARRAY(char, value_length + 1, mtTracing); strncpy(startup_value, value, value_length + 1); assert(strncmp(startup_value, value, value_length) == 0, "invariant"); - start_flight_recording_options_array->append(startup_value); + startup_recording_options_array->append(startup_value); return false; } -const GrowableArray* JfrOptionSet::start_flight_recording_options() { - return start_flight_recording_options_array; +const GrowableArray* JfrOptionSet::startup_recording_options() { + return startup_recording_options_array; } -void JfrOptionSet::release_start_flight_recording_options() { - if (start_flight_recording_options_array != NULL) { - const int length = start_flight_recording_options_array->length(); +void JfrOptionSet::release_startup_recording_options() { + if (startup_recording_options_array != NULL) { + const int length = startup_recording_options_array->length(); for (int i = 0; i < length; ++i) { - FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i), mtTracing); + FREE_C_HEAP_ARRAY(char, startup_recording_options_array->at(i), mtTracing); } - delete start_flight_recording_options_array; - start_flight_recording_options_array = NULL; + delete startup_recording_options_array; + startup_recording_options_array = NULL; } } diff --git a/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp b/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp --- a/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp @@ -80,8 +80,8 @@ static bool parse_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter); - static const GrowableArray* start_flight_recording_options(); - static void release_start_flight_recording_options(); + static const GrowableArray* startup_recording_options(); + static void release_startup_recording_options(); }; #endif // SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP diff --git a/src/share/vm/memory/metaspaceShared.cpp b/src/share/vm/memory/metaspaceShared.cpp --- a/src/share/vm/memory/metaspaceShared.cpp +++ b/src/share/vm/memory/metaspaceShared.cpp @@ -723,12 +723,15 @@ int class_list_path_len = (int)strlen(class_list_path_str); if (class_list_path_len >= 3) { if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) { - strcat(class_list_path_str, os::file_separator()); - strcat(class_list_path_str, "lib"); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%slib", os::file_separator()); + class_list_path_len += 4; } } - strcat(class_list_path_str, os::file_separator()); - strcat(class_list_path_str, "classlist"); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%sclasslist", os::file_separator()); class_list_path = class_list_path_str; } else { class_list_path = SharedClassListFile; diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp +++ b/src/share/vm/opto/compile.cpp @@ -1181,6 +1181,9 @@ _range_check_casts = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); _shenandoah_barriers = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); register_library_intrinsics(); +#ifdef ASSERT + _type_verify_symmetry = true; +#endif } //---------------------------init_start---------------------------------------- diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp +++ b/src/share/vm/opto/compile.hpp @@ -1240,6 +1240,9 @@ // Auxiliary method for randomized fuzzing/stressing static bool randomized_select(int count); +#ifdef ASSERT + bool _type_verify_symmetry; +#endif void shenandoah_eliminate_g1_wb_pre(Node* call, PhaseIterGVN* igvn); }; diff --git a/src/share/vm/opto/type.cpp b/src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp +++ b/src/share/vm/opto/type.cpp @@ -668,6 +668,35 @@ #endif +void Type::check_symmetrical(const Type *t, const Type *mt) const { +#ifdef ASSERT + assert(mt == t->xmeet(this), "meet not commutative"); + const Type* dual_join = mt->_dual; + const Type *t2t = dual_join->xmeet(t->_dual); + const Type *t2this = dual_join->xmeet(this->_dual); + + // Interface meet Oop is Not Symmetric: + // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull + // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull + + if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this->_dual) ) { + tty->print_cr("=== Meet Not Symmetric ==="); + tty->print("t = "); t->dump(); tty->cr(); + tty->print("this= "); dump(); tty->cr(); + tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); + + tty->print("t_dual= "); t->_dual->dump(); tty->cr(); + tty->print("this_dual= "); _dual->dump(); tty->cr(); + tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); + + tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); + tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); + + fatal("meet not symmetric" ); + } +#endif +} + //------------------------------meet------------------------------------------- // Compute the MEET of two types. NOT virtual. It enforces that meet is // commutative and the lattice is symmetric. @@ -685,33 +714,28 @@ t = t->maybe_remove_speculative(include_speculative); const Type *mt = this_t->xmeet(t); +#ifdef ASSERT if (isa_narrowoop() || t->isa_narrowoop()) return mt; if (isa_narrowklass() || t->isa_narrowklass()) return mt; -#ifdef ASSERT - assert(mt == t->xmeet(this_t), "meet not commutative"); - const Type* dual_join = mt->_dual; - const Type *t2t = dual_join->xmeet(t->_dual); - const Type *t2this = dual_join->xmeet(this_t->_dual); - - // Interface meet Oop is Not Symmetric: - // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull - // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull - - if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this_t->_dual) ) { - tty->print_cr("=== Meet Not Symmetric ==="); - tty->print("t = "); t->dump(); tty->cr(); - tty->print("this= "); this_t->dump(); tty->cr(); - tty->print("mt=(t meet this)= "); mt->dump(); tty->cr(); - - tty->print("t_dual= "); t->_dual->dump(); tty->cr(); - tty->print("this_dual= "); this_t->_dual->dump(); tty->cr(); - tty->print("mt_dual= "); mt->_dual->dump(); tty->cr(); - - tty->print("mt_dual meet t_dual= "); t2t ->dump(); tty->cr(); - tty->print("mt_dual meet this_dual= "); t2this ->dump(); tty->cr(); - - fatal("meet not symmetric" ); + Compile* C = Compile::current(); + if (!C->_type_verify_symmetry) { + return mt; } + this_t->check_symmetrical(t, mt); + // In the case of an array, computing the meet above, caused the + // computation of the meet of the elements which at verification + // time caused the computation of the meet of the dual of the + // elements. Computing the meet of the dual of the arrays here + // causes the meet of the dual of the elements to be computed which + // would cause the meet of the dual of the dual of the elements, + // that is the meet of the elements already computed above to be + // computed. Avoid redundant computations by requesting no + // verification. + C->_type_verify_symmetry = false; + const Type *mt_dual = this_t->_dual->xmeet(t->_dual); + this_t->_dual->check_symmetrical(t->_dual, mt_dual); + assert(!C->_type_verify_symmetry, "shouldn't have changed"); + C->_type_verify_symmetry = true; #endif return mt; } @@ -3967,10 +3991,10 @@ (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) || // 'this' is exact and super or unrelated: (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) { - if (above_centerline(ptr)) { + if (above_centerline(ptr) || (tary->_elem->make_ptr() && above_centerline(tary->_elem->make_ptr()->_ptr))) { tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable); } - return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot); + return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth); } bool xk = false; diff --git a/src/share/vm/opto/type.hpp b/src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp +++ b/src/share/vm/opto/type.hpp @@ -165,6 +165,7 @@ #endif const Type *meet_helper(const Type *t, bool include_speculative) const; + void check_symmetrical(const Type *t, const Type *mt) const; protected: // Each class of type is also identified by its base. diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp +++ b/src/share/vm/prims/jvm.cpp @@ -527,6 +527,17 @@ JVM_END +JVM_ENTRY_NO_ENV(jboolean, JVM_IsUseContainerSupport(void)) + JVMWrapper("JVM_IsUseContainerSupport"); +#ifdef TARGET_OS_FAMILY_linux + if (UseContainerSupport) { + return JNI_TRUE; + } +#endif + return JNI_FALSE; +JVM_END + + // java.lang.Throwable ////////////////////////////////////////////////////// diff --git a/src/share/vm/prims/jvm.h b/src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h +++ b/src/share/vm/prims/jvm.h @@ -202,6 +202,9 @@ JNIEXPORT jint JNICALL JVM_ActiveProcessorCount(void); +JNIEXPORT jboolean JNICALL +JVM_IsUseContainerSupport(void); + JNIEXPORT void * JNICALL JVM_LoadLibrary(const char *name); diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -2034,7 +2034,7 @@ experimental(uintx, WorkStealingSpinToYieldRatio, 10, \ "Ratio of hard spins to calls to yield") \ \ - develop(uintx, ObjArrayMarkingStride, 512, \ + develop(uintx, ObjArrayMarkingStride, 2048, \ "Number of object array elements to push onto the marking stack " \ "before pushing a continuation entry") \ \ diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -3509,7 +3509,7 @@ return status; } - JFR_ONLY(Jfr::on_create_vm_1();) + JFR_ONLY(Jfr::on_vm_init();) // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3560,16 +3560,11 @@ ShouldNotReachHere(); } -#if !INCLUDE_JFR - // if JFR is not enabled at the build time keep the original JvmtiExport location - // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution JvmtiExport::enter_start_phase(); // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. - JvmtiExport::post_vm_start(); -#endif { TraceTime timer("Initialize java.lang classes", TraceStartupTime); @@ -3616,19 +3611,6 @@ initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); } - JFR_ONLY( - Jfr::on_create_vm_2(); - - // if JFR is enabled at build time the JVMTI needs to be handled only after on_create_vm_2() call - - // Always call even when there are not JVMTI environments yet, since environments - // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_start_phase(); - - // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. - JvmtiExport::post_vm_start(); - ) - // See : bugid 4211085. // Background : the static initializer of java.lang.Compiler tries to read // property"java.compiler" and read & write property "java.vm.info". @@ -3725,7 +3707,7 @@ // Notify JVMTI agents that VM initialization is complete - nop if no agents. JvmtiExport::post_vm_initialized(); - JFR_ONLY(Jfr::on_create_vm_3();) + JFR_ONLY(Jfr::on_vm_start();) if (CleanChunkPoolAsync) { Chunk::start_chunk_pool_cleaner_task(); diff --git a/src/share/vm/utilities/taskqueue.hpp b/src/share/vm/utilities/taskqueue.hpp --- a/src/share/vm/utilities/taskqueue.hpp +++ b/src/share/vm/utilities/taskqueue.hpp @@ -332,7 +332,8 @@ // index, &_elems[index], _elems[index]); E* t = (E*)&_elems[index]; // cast away volatility oop* p = (oop*)t; - assert((*t)->is_oop_or_null(), "Not an oop or null"); + // G1 does its own checking + assert(UseG1GC || (*t)->is_oop_or_null(), "Not an oop or null"); f->do_oop(p); } // tty->print_cr("END OopTaskQueue::oops_do"); diff --git a/test/compiler/types/TestArrayMeetNotSymmetrical.java b/test/compiler/types/TestArrayMeetNotSymmetrical.java new file mode 100644 --- /dev/null +++ b/test/compiler/types/TestArrayMeetNotSymmetrical.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, Red Hat, Inc. 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. + */ + +/** + * @test + * @bug 8240676 + * @summary Meet not symmetric failure when running lucene on jdk8 + * + * @run main/othervm -XX:-BackgroundCompilation TestArrayMeetNotSymmetrical + * + */ + +public class TestArrayMeetNotSymmetrical { + private static final Object field = new Object[0]; + private static final Object field2 = new A[0]; + + public static void main(String[] args) { + Object array = new A[10]; + for (int i = 0; i < 20_000; i++) { + test1(true, 10); + test1(false, 10); + test2(true); + test2(false); + } + } + + private static Object test1(boolean flag, int len) { + Object o; + if (flag) { + o = field; + } else { + o = new A[len]; + } + return o; + } + + private static Object test2(boolean flag) { + Object o; + if (flag) { + o = field; + } else { + o = field2; + } + return o; + } + + + private static class A { + } +} diff --git a/test/runtime/8233197/T.java b/test/runtime/8233197/T.java deleted file mode 100644 --- a/test/runtime/8233197/T.java +++ /dev/null @@ -1,11 +0,0 @@ -public class T -{ - public static void main(String[] args) throws Exception - { - for (int i = 0; i < 50; i++) { - System.out.print("+"); - Thread.sleep(1); - } - System.out.println(); - } -} diff --git a/test/runtime/8233197/Test8233197.sh b/test/runtime/8233197/Test8233197.sh deleted file mode 100644 --- a/test/runtime/8233197/Test8233197.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2013, 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. - -## -## @test Test8233197.sh -## @bug 8233197 -## @summary Check that JFR subsystem can be initialized from VMStart JVMTI event -## @compile T.java -## @run shell Test8233197.sh -## - -set -x -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Linux) - gcc_cmd=`which gcc` - if [ "x$gcc_cmd" == "x" ]; then - echo "WARNING: gcc not found. Cannot execute test." 2>&1 - exit 0; - fi - NULL=/dev/null - PS=":" - FS="/" - ;; - * ) - echo "Test passed; only valid for Linux" - exit 0; - ;; -esac - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 - -# Bitness: -# Cannot simply look at TESTVMOPTS as -d64 is not -# passed if there is only a 64-bit JVM available. - -grep "64-Bit" vm_version.out > ${NULL} -if [ "$?" = "0" ] -then - COMP_FLAG="-m64" -else - COMP_FLAG="-m32" -fi - - -# Architecture: -# Translate uname output to JVM directory name, but permit testing -# 32-bit x86 on an x64 platform. -ARCH=`uname -m` -case "$ARCH" in - x86_64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=i386 - else - ARCH=amd64 - fi - ;; - ppc64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=ppc - else - ARCH=ppc64 - fi - ;; - sparc64) - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=sparc - else - ARCH=sparc64 - fi - ;; - arm*) - # 32-bit ARM machine: compiler may not recognise -m32 - COMP_FLAG="" - ARCH=arm - ;; - aarch64) - # 64-bit arm machine, could be testing 32 or 64-bit: - if [ "$COMP_FLAG" = "-m32" ]; then - ARCH=arm - else - ARCH=aarch64 - fi - ;; - i586) - ARCH=i386 - ;; - i686) - ARCH=i386 - ;; - # Assuming other ARCH values need no translation -esac - - -# VM type: need to know server or client -VMTYPE=client -grep Server vm_version.out > ${NULL} -if [ "$?" = "0" ] -then - VMTYPE=server -fi - - -LD_LIBRARY_PATH=.:${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH -export LD_LIBRARY_PATH - -cp ${TESTSRC}${FS}libJvmtiAgent.c . - -# Copy the result of our @compile action: -cp ${TESTCLASSES}${FS}T.class . - -echo "Architecture: ${ARCH}" -echo "Compilation flag: ${COMP_FLAG}" -echo "VM type: ${VMTYPE}" - -$gcc_cmd -DLINUX ${COMP_FLAG} -Wl, -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -c -o libJvmtiAgent.o \ - -I${COMPILEJAVA}/include -I${COMPILEJAVA}/include/linux \ - -L${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE} \ - libJvmtiAgent.c -$gcc_cmd -shared -o libJvmtiAgent.so libJvmtiAgent.o - -"$TESTJAVA/bin/java" $TESTVMOPTS -agentlib:JvmtiAgent -cp $(pwd) T > T.out -exit $? \ No newline at end of file diff --git a/test/runtime/8233197/libJvmtiAgent.c b/test/runtime/8233197/libJvmtiAgent.c deleted file mode 100644 --- a/test/runtime/8233197/libJvmtiAgent.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include -#include "jvmti.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef JNI_ENV_ARG - -#ifdef __cplusplus -#define JNI_ENV_ARG(x, y) y -#define JNI_ENV_PTR(x) x -#else -#define JNI_ENV_ARG(x,y) x, y -#define JNI_ENV_PTR(x) (*x) -#endif - -#endif - -#define TranslateError(err) "JVMTI error" - -static jvmtiEnv *jvmti = NULL; - -static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); - -JNIEXPORT -jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT -jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { - return Agent_Initialize(jvm, options, reserved); -} - -JNIEXPORT -jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { - return JNI_VERSION_1_8; -} - -static void JNICALL -Callback_VMStart(jvmtiEnv *jvmti_env, JNIEnv *env) { - printf("Localizing jdk.jfr.FlightRecorder\n"); - // without fix for 8233197 the process will crash at the following line - jclass cls = (*env)->FindClass(env, "jdk/jfr/FlightRecorder"); - jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getFlightRecorder", "()Ljdk/jfr/FlightRecorder;"); - if (mid == 0) { - printf("Unable to localize jdk.jfr.FlightRecorder#getFlightRecorder() method\n"); - // crash the tested JVM to make the test fail - exit(-1); - } - printf("Going to initialize JFR subsystem ...\n"); - jobject jfr = (*env)->CallStaticObjectMethod(env, cls, mid); - - if (!(*env)->ExceptionCheck(env)) { - // crash the tested JVM to make the test fail - printf("JFR subsystem is wrongly initialized too early\n"); - exit(-2); - } - // exit VM - exit(0); -} - -static -jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { - jint res, size; - jvmtiCapabilities caps; - jvmtiEventCallbacks callbacks; - jvmtiError err; - - res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), - JVMTI_VERSION_1_2); - if (res != JNI_OK || jvmti == NULL) { - printf(" Error: wrong result of a valid call to GetEnv!\n"); - return JNI_ERR; - } - - size = (jint)sizeof(callbacks); - - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.VMStart = Callback_VMStart; - - err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); - if (err != JVMTI_ERROR_NONE) { - printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err); - return JNI_ERR; - } - - err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL); - if (err != JVMTI_ERROR_NONE) { - printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err); - return JNI_ERR; - } - return JNI_OK; -} - -#ifdef __cplusplus -} -#endif