--- a/make/autoconf/flags.m4 Fri Jul 19 15:11:33 2019 +0530
+++ b/make/autoconf/flags.m4 Mon Jul 22 11:07:24 2019 +0530
@@ -176,6 +176,10 @@
AC_MSG_WARN([Ignoring LDFLAGS($LDFLAGS) found in environment. Use --with-extra-ldflags])
fi
+ if test "x$ASFLAGS" != "x"; then
+ AC_MSG_WARN([Ignoring ASFLAGS($ASFLAGS) found in environment. Use --with-extra-asflags])
+ fi
+
AC_ARG_WITH(extra-cflags, [AS_HELP_STRING([--with-extra-cflags],
[extra flags to be used when compiling jdk c-files])])
@@ -185,9 +189,13 @@
AC_ARG_WITH(extra-ldflags, [AS_HELP_STRING([--with-extra-ldflags],
[extra flags to be used when linking jdk])])
+ AC_ARG_WITH(extra-asflags, [AS_HELP_STRING([--with-extra-asflags],
+ [extra flags to be passed to the assembler])])
+
USER_CFLAGS="$with_extra_cflags"
USER_CXXFLAGS="$with_extra_cxxflags"
USER_LDFLAGS="$with_extra_ldflags"
+ USER_ASFLAGS="$with_extra_asflags"
])
# Setup the sysroot flags and add them to global CFLAGS and LDFLAGS so
@@ -280,10 +288,12 @@
EXTRA_CFLAGS="$MACHINE_FLAG $USER_CFLAGS"
EXTRA_CXXFLAGS="$MACHINE_FLAG $USER_CXXFLAGS"
EXTRA_LDFLAGS="$MACHINE_FLAG $USER_LDFLAGS"
+ EXTRA_ASFLAGS="$USER_ASFLAGS"
AC_SUBST(EXTRA_CFLAGS)
AC_SUBST(EXTRA_CXXFLAGS)
AC_SUBST(EXTRA_LDFLAGS)
+ AC_SUBST(EXTRA_ASFLAGS)
# For autoconf testing to work, the global flags must also be stored in the
# "unnamed" CFLAGS etc.
--- a/make/autoconf/spec.gmk.in Fri Jul 19 15:11:33 2019 +0530
+++ b/make/autoconf/spec.gmk.in Mon Jul 22 11:07:24 2019 +0530
@@ -489,6 +489,7 @@
EXTRA_CFLAGS = @EXTRA_CFLAGS@
EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@
EXTRA_LDFLAGS = @EXTRA_LDFLAGS@
+EXTRA_ASFLAGS = @EXTRA_ASFLAGS@
CXX:=@FIXPATH@ @CCACHE@ @ICECC@ @CXX@
--- a/make/hotspot/lib/CompileJvm.gmk Fri Jul 19 15:11:33 2019 +0530
+++ b/make/hotspot/lib/CompileJvm.gmk Mon Jul 22 11:07:24 2019 +0530
@@ -47,6 +47,8 @@
$(EXTRA_LDFLAGS) \
#
+JVM_ASFLAGS += $(EXTRA_ASFLAGS)
+
JVM_LIBS += \
$(JVM_LIBS_FEATURES) \
#
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -800,6 +800,7 @@
#endif
// Class initialization barrier for static methods
+ address c2i_no_clinit_check_entry = NULL;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -812,13 +813,15 @@
__ load_method_holder(rscratch2, rmethod);
__ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier);
__ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
+
__ bind(L_skip_barrier);
+ c2i_no_clinit_check_entry = __ pc();
}
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
- return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -1277,6 +1277,7 @@
c2i_entry = __ pc();
// Class initialization barrier for static methods
+ address c2i_no_clinit_check_entry = NULL;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -1295,11 +1296,12 @@
__ bctr();
__ bind(L_skip_barrier);
+ c2i_no_clinit_check_entry = __ pc();
}
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
- return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
}
#ifdef COMPILER2
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -2713,6 +2713,7 @@
address c2i_entry = __ pc();
// Class initialization barrier for static methods
+ address c2i_no_clinit_check_entry = NULL;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
@@ -2729,11 +2730,12 @@
__ z_br(klass);
__ bind(L_skip_barrier);
+ c2i_no_clinit_check_entry = __ pc();
}
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
- return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
}
// This function returns the adjust size (in number of words) to a c2i adapter
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -971,10 +971,8 @@
address c2i_entry = __ pc();
- BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
- bs->c2i_entry_barrier(masm);
-
// Class initialization barrier for static methods
+ address c2i_no_clinit_check_entry = NULL;
if (VM_Version::supports_fast_class_init_checks()) {
Label L_skip_barrier;
Register method = rbx;
@@ -993,12 +991,16 @@
__ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
__ bind(L_skip_barrier);
+ c2i_no_clinit_check_entry = __ pc();
}
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->c2i_entry_barrier(masm);
+
gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
__ flush();
- return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -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.
+ *
+ * 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_GC_G1_G1CARDTABLEENTRYCLOSURE_HPP
+#define SHARE_GC_G1_G1CARDTABLEENTRYCLOSURE_HPP
+
+#include "gc/shared/cardTable.hpp"
+#include "memory/allocation.hpp"
+
+// A closure class for processing card table entries. Note that we don't
+// require these closure objects to be stack-allocated.
+class G1CardTableEntryClosure: public CHeapObj<mtGC> {
+public:
+ typedef CardTable::CardValue CardValue;
+
+ // Process the card whose card table entry is "card_ptr". If returns
+ // "false", terminate the iteration early.
+ virtual bool do_card_ptr(CardValue* card_ptr, uint worker_id) = 0;
+};
+
+#endif // SHARE_GC_G1_G1CARDTABLEENTRYCLOSURE_HPP
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -31,6 +31,7 @@
#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1Arguments.hpp"
#include "gc/g1/g1BarrierSet.hpp"
+#include "gc/g1/g1CardTableEntryClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorState.hpp"
@@ -49,6 +50,7 @@
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
#include "gc/g1/g1Policy.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/g1RegionToSpaceMapper.hpp"
#include "gc/g1/g1RemSet.hpp"
#include "gc/g1/g1RootClosures.hpp"
@@ -1078,7 +1080,9 @@
// Discard all remembered set updates.
G1BarrierSet::dirty_card_queue_set().abandon_logs();
- assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty");
+ assert(G1BarrierSet::dirty_card_queue_set().completed_buffers_num() == 0,
+ "DCQS should be empty");
+ redirty_cards_queue_set().verify_empty();
}
void G1CollectedHeap::verify_after_full_collection() {
@@ -1517,7 +1521,7 @@
_collection_set(this, _policy),
_hot_card_cache(NULL),
_rem_set(NULL),
- _dirty_card_queue_set(false),
+ _redirty_cards_queue_set(),
_cm(NULL),
_cm_thread(NULL),
_cr(NULL),
@@ -1687,8 +1691,8 @@
&bs->dirty_card_queue_buffer_allocator(),
true); // init_free_ids
- dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
- &bs->dirty_card_queue_buffer_allocator());
+ // Use same buffer allocator as dirty card qset, to allow merging.
+ _redirty_cards_queue_set.initialize(&bs->dirty_card_queue_buffer_allocator());
// Create the hot card cache.
_hot_card_cache = new G1HotCardCache(this);
@@ -3213,18 +3217,43 @@
class G1RedirtyLoggedCardsTask : public AbstractGangTask {
private:
- G1DirtyCardQueueSet* _queue;
+ G1RedirtyCardsQueueSet* _qset;
G1CollectedHeap* _g1h;
+ BufferNode* volatile _nodes;
+
+ void apply(G1CardTableEntryClosure* cl, BufferNode* node, uint worker_id) {
+ void** buf = BufferNode::make_buffer_from_node(node);
+ size_t limit = _qset->buffer_size();
+ for (size_t i = node->index(); i < limit; ++i) {
+ CardTable::CardValue* card_ptr = static_cast<CardTable::CardValue*>(buf[i]);
+ bool result = cl->do_card_ptr(card_ptr, worker_id);
+ assert(result, "Closure should always return true");
+ }
+ }
+
+ void par_apply(G1CardTableEntryClosure* cl, uint worker_id) {
+ BufferNode* next = Atomic::load(&_nodes);
+ while (next != NULL) {
+ BufferNode* node = next;
+ next = Atomic::cmpxchg(node->next(), &_nodes, node);
+ if (next == node) {
+ apply(cl, node, worker_id);
+ next = node->next();
+ }
+ }
+ }
+
public:
- G1RedirtyLoggedCardsTask(G1DirtyCardQueueSet* queue, G1CollectedHeap* g1h) : AbstractGangTask("Redirty Cards"),
- _queue(queue), _g1h(g1h) { }
+ G1RedirtyLoggedCardsTask(G1RedirtyCardsQueueSet* qset, G1CollectedHeap* g1h) :
+ AbstractGangTask("Redirty Cards"),
+ _qset(qset), _g1h(g1h), _nodes(qset->all_completed_buffers()) { }
virtual void work(uint worker_id) {
G1GCPhaseTimes* p = _g1h->phase_times();
G1GCParPhaseTimesTracker x(p, G1GCPhaseTimes::RedirtyCards, worker_id);
RedirtyLoggedCardTableEntryClosure cl(_g1h);
- _queue->par_apply_closure_to_all_completed_buffers(&cl);
+ par_apply(&cl, worker_id);
p->record_thread_work_item(G1GCPhaseTimes::RedirtyCards, worker_id, cl.num_dirtied());
}
@@ -3233,13 +3262,12 @@
void G1CollectedHeap::redirty_logged_cards() {
double redirty_logged_cards_start = os::elapsedTime();
- G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set(), this);
- dirty_card_queue_set().reset_for_par_iteration();
+ G1RedirtyLoggedCardsTask redirty_task(&redirty_cards_queue_set(), this);
workers()->run_task(&redirty_task);
G1DirtyCardQueueSet& dcq = G1BarrierSet::dirty_card_queue_set();
- dcq.merge_bufferlists(&dirty_card_queue_set());
- assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
+ dcq.merge_bufferlists(&redirty_cards_queue_set());
+ redirty_cards_queue_set().verify_empty();
phase_times()->record_redirty_logged_cards_time_ms((os::elapsedTime() - redirty_logged_cards_start) * 1000.0);
}
@@ -3571,7 +3599,7 @@
// Should G1EvacuationFailureALot be in effect for this GC?
NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();)
- assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
+ redirty_cards_queue_set().verify_empty();
}
class G1EvacuateRegionsBaseTask : public AbstractGangTask {
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -31,7 +31,6 @@
#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1EdenRegions.hpp"
#include "gc/g1/g1EvacFailure.hpp"
#include "gc/g1/g1EvacStats.hpp"
@@ -42,6 +41,7 @@
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1HeapRegionAttr.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/g1SurvivorRegions.hpp"
#include "gc/g1/g1YCTypes.hpp"
#include "gc/g1/heapRegionManager.hpp"
@@ -73,6 +73,7 @@
class SpaceClosure;
class CompactibleSpaceClosure;
class Space;
+class G1CardTableEntryClosure;
class G1CollectionSet;
class G1Policy;
class G1HotCardCache;
@@ -775,7 +776,7 @@
// A set of cards that cover the objects for which the Rsets should be updated
// concurrently after the collection.
- G1DirtyCardQueueSet _dirty_card_queue_set;
+ G1RedirtyCardsQueueSet _redirty_cards_queue_set;
// After a collection pause, convert the regions in the collection set into free
// regions.
@@ -935,7 +936,9 @@
uint num_task_queues() const;
// A set of cards where updates happened during the GC
- G1DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
+ G1RedirtyCardsQueueSet& redirty_cards_queue_set() {
+ return _redirty_cards_queue_set;
+ }
// Create a G1CollectedHeap.
// Must call the initialize method afterwards.
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -23,9 +23,11 @@
*/
#include "precompiled.hpp"
+#include "gc/g1/g1CardTableEntryClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1FreeIdSet.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/g1RemSet.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
@@ -90,8 +92,7 @@
_completed_buffers_padding(0),
_free_ids(NULL),
_processed_buffers_mut(0),
- _processed_buffers_rs_thread(0),
- _cur_par_buffer_node(NULL)
+ _processed_buffers_rs_thread(0)
{
_all_active = true;
}
@@ -211,26 +212,22 @@
// Merge lists of buffers. Notify the processing threads.
// The source queue is emptied as a result. The queues
// must share the monitor.
-void G1DirtyCardQueueSet::merge_bufferlists(G1DirtyCardQueueSet *src) {
- assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
+void G1DirtyCardQueueSet::merge_bufferlists(G1RedirtyCardsQueueSet* src) {
+ assert(allocator() == src->allocator(), "precondition");
+ const G1RedirtyCardsBufferList from = src->take_all_completed_buffers();
+ if (from._head == NULL) return;
+
MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
if (_completed_buffers_tail == NULL) {
assert(_completed_buffers_head == NULL, "Well-formedness");
- _completed_buffers_head = src->_completed_buffers_head;
- _completed_buffers_tail = src->_completed_buffers_tail;
+ _completed_buffers_head = from._head;
+ _completed_buffers_tail = from._tail;
} else {
assert(_completed_buffers_head != NULL, "Well formedness");
- if (src->_completed_buffers_head != NULL) {
- _completed_buffers_tail->set_next(src->_completed_buffers_head);
- _completed_buffers_tail = src->_completed_buffers_tail;
- }
+ _completed_buffers_tail->set_next(from._head);
+ _completed_buffers_tail = from._tail;
}
- _n_completed_buffers += src->_n_completed_buffers;
-
- src->_n_completed_buffers = 0;
- src->_completed_buffers_head = NULL;
- src->_completed_buffers_tail = NULL;
- src->set_process_completed_buffers(false);
+ _n_completed_buffers += from._count;
assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
_completed_buffers_head != NULL && _completed_buffers_tail != NULL,
@@ -240,7 +237,6 @@
bool G1DirtyCardQueueSet::apply_closure_to_buffer(G1CardTableEntryClosure* cl,
BufferNode* node,
- bool consume,
uint worker_i) {
if (cl == NULL) return true;
bool result = true;
@@ -255,10 +251,8 @@
break;
}
}
- if (consume) {
- assert(i <= buffer_size(), "invariant");
- node->set_index(i);
- }
+ assert(i <= buffer_size(), "invariant");
+ node->set_index(i);
return result;
}
@@ -299,7 +293,7 @@
uint worker_i = _free_ids->claim_par_id(); // temporarily claim an id
G1RefineCardConcurrentlyClosure cl;
- bool result = apply_closure_to_buffer(&cl, node, true, worker_i);
+ bool result = apply_closure_to_buffer(&cl, node, worker_i);
_free_ids->release_par_id(worker_i); // release the id
if (result) {
@@ -328,7 +322,7 @@
if (nd == NULL) {
return false;
} else {
- if (apply_closure_to_buffer(cl, nd, true, worker_i)) {
+ if (apply_closure_to_buffer(cl, nd, worker_i)) {
assert_fully_consumed(nd, buffer_size());
// Done with fully processed buffer.
deallocate_buffer(nd);
@@ -342,21 +336,6 @@
}
}
-void G1DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(G1CardTableEntryClosure* cl) {
- BufferNode* nd = _cur_par_buffer_node;
- while (nd != NULL) {
- BufferNode* next = nd->next();
- BufferNode* actual = Atomic::cmpxchg(next, &_cur_par_buffer_node, nd);
- if (actual == nd) {
- bool b = apply_closure_to_buffer(cl, nd, false);
- guarantee(b, "Should not stop early.");
- nd = next;
- } else {
- nd = actual;
- }
- }
-}
-
void G1DirtyCardQueueSet::abandon_logs() {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
abandon_completed_buffers();
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -25,26 +25,16 @@
#ifndef SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP
#define SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP
-#include "gc/shared/cardTable.hpp"
#include "gc/shared/ptrQueue.hpp"
#include "memory/allocation.hpp"
+class G1CardTableEntryClosure;
class G1DirtyCardQueueSet;
class G1FreeIdSet;
+class G1RedirtyCardsQueueSet;
class Thread;
class Monitor;
-// A closure class for processing card table entries. Note that we don't
-// require these closure objects to be stack-allocated.
-class G1CardTableEntryClosure: public CHeapObj<mtGC> {
-public:
- typedef CardTable::CardValue CardValue;
-
- // Process the card whose card table entry is "card_ptr". If returns
- // "false", terminate the iteration early.
- virtual bool do_card_ptr(CardValue* card_ptr, uint worker_i) = 0;
-};
-
// A ptrQueue whose elements are "oops", pointers to object heads.
class G1DirtyCardQueue: public PtrQueue {
protected:
@@ -95,12 +85,12 @@
// buffer_size. If all closure applications return true, then
// returns true. Stops processing after the first closure
// application that returns false, and returns false from this
- // function. If "consume" is true, the node's index is updated to
- // exclude the processed elements, e.g. up to the element for which
- // the closure returned false.
+ // function. The node's index is updated to exclude the processed
+ // elements, e.g. up to the element for which the closure returned
+ // false, or one past the last element if the closure always
+ // returned true.
bool apply_closure_to_buffer(G1CardTableEntryClosure* cl,
BufferNode* node,
- bool consume,
uint worker_i = 0);
// If there are more than stop_at completed buffers, pop one, apply
@@ -135,9 +125,6 @@
jint _processed_buffers_mut;
jint _processed_buffers_rs_thread;
- // Current buffer node used for parallel iteration.
- BufferNode* volatile _cur_par_buffer_node;
-
public:
G1DirtyCardQueueSet(bool notify_when_complete = true);
~G1DirtyCardQueueSet();
@@ -183,7 +170,7 @@
// Notify the consumer if the number of buffers crossed the threshold
void notify_if_necessary();
- void merge_bufferlists(G1DirtyCardQueueSet* src);
+ void merge_bufferlists(G1RedirtyCardsQueueSet* src);
// Apply G1RefineCardConcurrentlyClosure to completed buffers until there are stop_at
// completed buffers remaining.
@@ -193,12 +180,6 @@
// must never return false. Must only be called during GC.
bool apply_closure_during_gc(G1CardTableEntryClosure* cl, uint worker_i);
- void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; }
- // Applies the current closure to all completed buffers, non-consumptively.
- // Can be used in parallel, all callers using the iteration state initialized
- // by reset_for_par_iteration.
- void par_apply_closure_to_all_completed_buffers(G1CardTableEntryClosure* cl);
-
// If a full collection is happening, reset partial logs, and release
// completed ones: the full collection will make them all irrelevant.
void abandon_logs();
--- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -26,10 +26,10 @@
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1EvacFailure.hpp"
#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
@@ -40,7 +40,7 @@
class UpdateLogBuffersDeferred : public BasicOopIterateClosure {
private:
G1CollectedHeap* _g1h;
- G1DirtyCardQueue* _dcq;
+ G1RedirtyCardsQueue* _rdcq;
G1CardTable* _ct;
// Remember the last enqueued card to avoid enqueuing the same card over and over;
@@ -48,8 +48,8 @@
size_t _last_enqueued_card;
public:
- UpdateLogBuffersDeferred(G1DirtyCardQueue* dcq) :
- _g1h(G1CollectedHeap::heap()), _dcq(dcq), _ct(_g1h->card_table()), _last_enqueued_card(SIZE_MAX) {}
+ UpdateLogBuffersDeferred(G1RedirtyCardsQueue* rdcq) :
+ _g1h(G1CollectedHeap::heap()), _rdcq(rdcq), _ct(_g1h->card_table()), _last_enqueued_card(SIZE_MAX) {}
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
virtual void do_oop( oop* p) { do_oop_work(p); }
@@ -67,7 +67,7 @@
}
size_t card_index = _ct->index_for(p);
if (card_index != _last_enqueued_card) {
- _dcq->enqueue(_ct->byte_for_index(card_index));
+ _rdcq->enqueue(_ct->byte_for_index(card_index));
_last_enqueued_card = card_index;
}
}
@@ -199,15 +199,15 @@
G1CollectedHeap* _g1h;
uint _worker_id;
- G1DirtyCardQueue _dcq;
+ G1RedirtyCardsQueue _rdcq;
UpdateLogBuffersDeferred _log_buffer_cl;
public:
RemoveSelfForwardPtrHRClosure(uint worker_id) :
_g1h(G1CollectedHeap::heap()),
_worker_id(worker_id),
- _dcq(&_g1h->dirty_card_queue_set()),
- _log_buffer_cl(&_dcq) {
+ _rdcq(&_g1h->redirty_cards_queue_set()),
+ _log_buffer_cl(&_rdcq) {
}
size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr,
--- a/src/hotspot/share/gc/g1/g1HotCardCache.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1HotCardCache.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/g1/g1CardTableEntryClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1HotCardCache.hpp"
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -43,7 +43,7 @@
size_t optional_cset_length)
: _g1h(g1h),
_refs(g1h->task_queue(worker_id)),
- _dcq(&g1h->dirty_card_queue_set()),
+ _rdcq(&g1h->redirty_cards_queue_set()),
_ct(g1h->card_table()),
_closures(NULL),
_plab_allocator(NULL),
@@ -88,7 +88,7 @@
// Pass locally gathered statistics to global state.
void G1ParScanThreadState::flush(size_t* surviving_young_words) {
- _dcq.flush();
+ _rdcq.flush();
// Update allocation statistics.
_plab_allocator->flush_and_retire_stats();
_g1h->policy()->record_age_table(&_age_table);
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -27,7 +27,7 @@
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
-#include "gc/g1/g1DirtyCardQueue.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/g1OopClosures.hpp"
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/g1RemSet.hpp"
@@ -46,7 +46,7 @@
class G1ParScanThreadState : public CHeapObj<mtGC> {
G1CollectedHeap* _g1h;
RefToScanQueue* _refs;
- G1DirtyCardQueue _dcq;
+ G1RedirtyCardsQueue _rdcq;
G1CardTable* _ct;
G1EvacuationRootClosures* _closures;
@@ -81,7 +81,7 @@
#define PADDING_ELEM_NUM (DEFAULT_CACHE_LINE_SIZE / sizeof(size_t))
- G1DirtyCardQueue& dirty_card_queue() { return _dcq; }
+ G1RedirtyCardsQueue& redirty_cards_queue() { return _rdcq; }
G1CardTable* ct() { return _ct; }
G1HeapRegionAttr dest(G1HeapRegionAttr original) const {
@@ -133,7 +133,7 @@
size_t card_index = ct()->index_for(p);
// If the card hasn't been added to the buffer, do it.
if (_last_enqueued_card != card_index) {
- dirty_card_queue().enqueue(ct()->byte_for_index(card_index));
+ redirty_cards_queue().enqueue(ct()->byte_for_index(card_index));
_last_enqueued_card = card_index;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1RedirtyCardsQueue.hpp"
+#include "runtime/atomic.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+// G1RedirtyCardsBufferList
+
+G1RedirtyCardsBufferList::G1RedirtyCardsBufferList() :
+ _head(NULL), _tail(NULL), _count(0) {}
+
+G1RedirtyCardsBufferList::G1RedirtyCardsBufferList(BufferNode* head,
+ BufferNode* tail,
+ size_t count) :
+ _head(head), _tail(tail), _count(count)
+{
+ assert((_head == NULL) == (_tail == NULL), "invariant");
+ assert((_head == NULL) == (_count == 0), "invariant");
+}
+
+// G1RedirtyCardsQueueBase::LocalQSet
+
+G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) :
+ PtrQueueSet(),
+ _shared_qset(shared_qset),
+ _buffers()
+{
+ PtrQueueSet::initialize(_shared_qset->allocator());
+}
+
+G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() {
+ assert(_buffers._head == NULL, "unflushed qset");
+ assert(_buffers._tail == NULL, "invariant");
+ assert(_buffers._count == 0, "invariant");
+}
+
+void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* node) {
+ ++_buffers._count;
+ node->set_next(_buffers._head);
+ _buffers._head = node;
+ if (_buffers._tail == NULL) {
+ _buffers._tail = node;
+ }
+}
+
+G1RedirtyCardsBufferList
+G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
+ G1RedirtyCardsBufferList result = _buffers;
+ _buffers = G1RedirtyCardsBufferList();
+ return result;
+}
+
+void G1RedirtyCardsQueueBase::LocalQSet::flush() {
+ _shared_qset->merge_bufferlist(this);
+}
+
+// G1RedirtyCardsQueue
+
+G1RedirtyCardsQueue::G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset) :
+ G1RedirtyCardsQueueBase(qset), // Init _local_qset before passing to PtrQueue.
+ PtrQueue(&_local_qset, true /* active (always) */)
+{}
+
+G1RedirtyCardsQueue::~G1RedirtyCardsQueue() {
+ flush();
+}
+
+void G1RedirtyCardsQueue::handle_completed_buffer() {
+ enqueue_completed_buffer();
+}
+
+void G1RedirtyCardsQueue::flush() {
+ flush_impl();
+ _local_qset.flush();
+}
+
+// G1RedirtyCardsQueueSet
+
+G1RedirtyCardsQueueSet::G1RedirtyCardsQueueSet() :
+ PtrQueueSet(),
+ _list(),
+ _count(0),
+ _tail(NULL)
+ DEBUG_ONLY(COMMA _collecting(true))
+{}
+
+G1RedirtyCardsQueueSet::~G1RedirtyCardsQueueSet() {
+ verify_empty();
+}
+
+#ifdef ASSERT
+void G1RedirtyCardsQueueSet::verify_empty() const {
+ assert(_list.empty(), "precondition");
+ assert(_tail == NULL, "invariant");
+ assert(_count == 0, "invariant");
+}
+#endif // ASSERT
+
+BufferNode* G1RedirtyCardsQueueSet::all_completed_buffers() const {
+ DEBUG_ONLY(_collecting = false;)
+ return _list.top();
+}
+
+G1RedirtyCardsBufferList G1RedirtyCardsQueueSet::take_all_completed_buffers() {
+ DEBUG_ONLY(_collecting = false;)
+ G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _count);
+ _tail = NULL;
+ _count = 0;
+ DEBUG_ONLY(_collecting = true;)
+ return result;
+}
+
+void G1RedirtyCardsQueueSet::update_tail(BufferNode* node) {
+ // Node is the tail of a (possibly single element) list just prepended to
+ // _list. If, after that prepend, node's follower is NULL, then node is
+ // also the tail of _list, so record it as such.
+ if (node->next() == NULL) {
+ assert(_tail == NULL, "invariant");
+ _tail = node;
+ }
+}
+
+void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) {
+ assert(_collecting, "precondition");
+ Atomic::inc(&_count);
+ _list.push(*node);
+ update_tail(node);
+}
+
+void G1RedirtyCardsQueueSet::merge_bufferlist(LocalQSet* src) {
+ assert(_collecting, "precondition");
+ const G1RedirtyCardsBufferList from = src->take_all_completed_buffers();
+ if (from._head != NULL) {
+ assert(from._tail != NULL, "invariant");
+ Atomic::add(from._count, &_count);
+ _list.prepend(*from._head, *from._tail);
+ update_tail(from._tail);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
+#define SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
+
+#include "gc/shared/ptrQueue.hpp"
+#include "memory/allocation.hpp"
+#include "memory/padded.hpp"
+
+class G1CardTableEntryClosure;
+class G1RedirtyCardsQueue;
+class G1RedirtyCardsQueueSet;
+
+struct G1RedirtyCardsBufferList {
+ BufferNode* _head;
+ BufferNode* _tail;
+ size_t _count;
+
+ G1RedirtyCardsBufferList();
+ G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t count);
+};
+
+// Provide G1RedirtyCardsQueue with a thread-local qset. It provides an
+// uncontended staging area for completed buffers, to be flushed to the
+// shared qset en masse. Using the "base from member" idiom so the local
+// qset is constructed before being passed to the PtrQueue constructor.
+class G1RedirtyCardsQueueBase {
+ friend class G1RedirtyCardsQueue;
+ friend class G1RedirtyCardsQueueSet;
+
+ class LocalQSet : public PtrQueueSet {
+ G1RedirtyCardsQueueSet* _shared_qset;
+ G1RedirtyCardsBufferList _buffers;
+
+ public:
+ LocalQSet(G1RedirtyCardsQueueSet* shared_qset);
+ ~LocalQSet();
+
+ // Add the buffer to the local list.
+ virtual void enqueue_completed_buffer(BufferNode* node);
+
+ // Transfer all completed buffers to the shared qset.
+ void flush();
+
+ G1RedirtyCardsBufferList take_all_completed_buffers();
+ };
+
+ G1RedirtyCardsQueueBase(G1RedirtyCardsQueueSet* shared_qset) :
+ _local_qset(shared_qset) {}
+
+ ~G1RedirtyCardsQueueBase() {}
+
+ LocalQSet _local_qset;
+};
+
+// Worker-local queues of card table entries.
+class G1RedirtyCardsQueue : private G1RedirtyCardsQueueBase, public PtrQueue {
+protected:
+ virtual void handle_completed_buffer();
+
+public:
+ G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset);
+
+ // Flushes the queue.
+ ~G1RedirtyCardsQueue();
+
+ // Flushes all enqueued cards to qset.
+ void flush();
+};
+
+// Card table entries to be redirtied and the cards reprocessed later.
+// Has two phases, collecting and processing. During the collecting
+// phase buffers are added to the set. Once collecting is complete and
+// processing starts, buffers can no longer be added. Taking all the
+// collected (and processed) buffers reverts back to collecting, allowing
+// the set to be reused for another round of redirtying.
+class G1RedirtyCardsQueueSet : public PtrQueueSet {
+ DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
+ BufferNode::Stack _list;
+ DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(size_t));
+ volatile size_t _count;
+ DEFINE_PAD_MINUS_SIZE(3, DEFAULT_CACHE_LINE_SIZE, sizeof(BufferNode*));
+ BufferNode* _tail;
+ DEBUG_ONLY(mutable bool _collecting;)
+
+ typedef G1RedirtyCardsQueueBase::LocalQSet LocalQSet;
+
+ void update_tail(BufferNode* node);
+
+public:
+ G1RedirtyCardsQueueSet();
+ ~G1RedirtyCardsQueueSet();
+
+ using PtrQueueSet::initialize;
+
+ void verify_empty() const NOT_DEBUG_RETURN;
+
+ // Collect buffers. These functions are thread-safe.
+ // precondition: Must not be concurrent with buffer processing.
+ virtual void enqueue_completed_buffer(BufferNode* node);
+ void merge_bufferlist(LocalQSet* src);
+
+ // Processing phase operations.
+ // precondition: Must not be concurrent with buffer collection.
+ BufferNode* all_completed_buffers() const;
+ G1RedirtyCardsBufferList take_all_completed_buffers();
+};
+
+#endif // SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -26,6 +26,7 @@
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BlockOffsetTable.inline.hpp"
#include "gc/g1/g1CardTable.inline.hpp"
+#include "gc/g1/g1CardTableEntryClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1ConcurrentRefine.hpp"
#include "gc/g1/g1DirtyCardQueue.hpp"
--- a/src/hotspot/share/gc/shared/ptrQueue.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/shared/ptrQueue.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -296,6 +296,10 @@
class PtrQueueSet {
BufferNode::Allocator* _allocator;
+ // Noncopyable - not defined.
+ PtrQueueSet(const PtrQueueSet&);
+ PtrQueueSet& operator=(const PtrQueueSet&);
+
protected:
bool _all_active;
@@ -309,6 +313,9 @@
public:
+ // Return the associated BufferNode allocator.
+ BufferNode::Allocator* allocator() const { return _allocator; }
+
// Return the buffer for a BufferNode of size buffer_size().
void** allocate_buffer();
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -3016,7 +3016,7 @@
}
uint ShenandoahLoadReferenceBarrierNode::hash() const {
- return Node::hash() + _native ? 1 : 0;
+ return Node::hash() + (_native ? 1 : 0);
}
bool ShenandoahLoadReferenceBarrierNode::cmp( const Node &n ) const {
--- a/src/hotspot/share/oops/method.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/oops/method.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -146,6 +146,12 @@
return adapter()->get_c2i_unverified_entry();
}
+address Method::get_c2i_no_clinit_check_entry() {
+ assert(VM_Version::supports_fast_class_init_checks(), "");
+ assert(adapter() != NULL, "must have");
+ return adapter()->get_c2i_no_clinit_check_entry();
+}
+
char* Method::name_and_sig_as_C_string() const {
return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature());
}
@@ -1045,7 +1051,7 @@
_c2i_entry ---------------------------------+->[c2i entry..]
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
_from_interpreted_entry | _c2i_unverified_entry | |
- | | | |
+ | | _c2i_no_clinit_check_entry| |
| | (_cds_entry_table: CODE) | |
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
| | (allocated at run time) | |
--- a/src/hotspot/share/oops/method.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/oops/method.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -481,6 +481,7 @@
address get_i2c_entry();
address get_c2i_entry();
address get_c2i_unverified_entry();
+ address get_c2i_no_clinit_check_entry();
AdapterHandlerEntry* adapter() const {
return constMethod()->adapter();
}
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -1446,7 +1446,19 @@
guarantee(callee != NULL && callee->is_method(), "bad handshake");
thread->set_vm_result_2(callee);
thread->set_callee_target(NULL);
- return callee->get_c2i_entry();
+ if (caller_frame.is_entry_frame() && VM_Version::supports_fast_class_init_checks()) {
+ // Bypass class initialization checks in c2i when caller is in native.
+ // JNI calls to static methods don't have class initialization checks.
+ // Fast class initialization checks are present in c2i adapters and call into
+ // SharedRuntime::handle_wrong_method() on the slow path.
+ //
+ // JVM upcalls may land here as well, but there's a proper check present in
+ // LinkResolver::resolve_static_call (called from JavaCalls::call_static),
+ // so bypassing it in c2i adapter is benign.
+ return callee->get_c2i_no_clinit_check_entry();
+ } else {
+ return callee->get_c2i_entry();
+ }
}
// Must be compiled to compiled path which is safe to stackwalk
@@ -2450,9 +2462,9 @@
: BasicHashtable<mtCode>(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { }
// Create a new entry suitable for insertion in the table
- AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
+ AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash());
- entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
if (DumpSharedSpaces) {
((CDSAdapterHandlerEntry*)entry)->init();
}
@@ -2601,8 +2613,9 @@
AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
address i2c_entry,
address c2i_entry,
- address c2i_unverified_entry) {
- return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry);
+ address c2i_unverified_entry,
+ address c2i_no_clinit_check_entry) {
+ return _adapters->new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
}
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
@@ -2778,6 +2791,7 @@
if (base == NULL) base = _c2i_entry;
assert(base <= _c2i_entry || _c2i_entry == NULL, "");
assert(base <= _c2i_unverified_entry || _c2i_unverified_entry == NULL, "");
+ assert(base <= _c2i_no_clinit_check_entry || _c2i_no_clinit_check_entry == NULL, "");
return base;
}
@@ -2791,6 +2805,8 @@
_c2i_entry += delta;
if (_c2i_unverified_entry != NULL)
_c2i_unverified_entry += delta;
+ if (_c2i_no_clinit_check_entry != NULL)
+ _c2i_no_clinit_check_entry += delta;
assert(base_address() == new_base, "");
}
@@ -3129,10 +3145,20 @@
}
void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
- st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT,
- p2i(this), fingerprint()->as_string(),
- p2i(get_i2c_entry()), p2i(get_c2i_entry()), p2i(get_c2i_unverified_entry()));
-
+ st->print("AHE@" INTPTR_FORMAT ": %s", p2i(this), fingerprint()->as_string());
+ if (get_i2c_entry() != NULL) {
+ st->print(" i2c: " INTPTR_FORMAT, p2i(get_i2c_entry()));
+ }
+ if (get_c2i_entry() != NULL) {
+ st->print(" c2i: " INTPTR_FORMAT, p2i(get_c2i_entry()));
+ }
+ if (get_c2i_unverified_entry() != NULL) {
+ st->print(" c2iUV: " INTPTR_FORMAT, p2i(get_c2i_unverified_entry()));
+ }
+ if (get_c2i_no_clinit_check_entry() != NULL) {
+ st->print(" c2iNCI: " INTPTR_FORMAT, p2i(get_c2i_no_clinit_check_entry()));
+ }
+ st->cr();
}
#if INCLUDE_CDS
--- a/src/hotspot/share/runtime/sharedRuntime.hpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/runtime/sharedRuntime.hpp Mon Jul 22 11:07:24 2019 +0530
@@ -636,6 +636,7 @@
address _i2c_entry;
address _c2i_entry;
address _c2i_unverified_entry;
+ address _c2i_no_clinit_check_entry;
#ifdef ASSERT
// Captures code and signature used to generate this adapter when
@@ -644,11 +645,12 @@
int _saved_code_length;
#endif
- void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) {
+ void init(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) {
_fingerprint = fingerprint;
_i2c_entry = i2c_entry;
_c2i_entry = c2i_entry;
_c2i_unverified_entry = c2i_unverified_entry;
+ _c2i_no_clinit_check_entry = c2i_no_clinit_check_entry;
#ifdef ASSERT
_saved_code = NULL;
_saved_code_length = 0;
@@ -661,9 +663,11 @@
AdapterHandlerEntry();
public:
- address get_i2c_entry() const { return _i2c_entry; }
- address get_c2i_entry() const { return _c2i_entry; }
- address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
+ address get_i2c_entry() const { return _i2c_entry; }
+ address get_c2i_entry() const { return _c2i_entry; }
+ address get_c2i_unverified_entry() const { return _c2i_unverified_entry; }
+ address get_c2i_no_clinit_check_entry() const { return _c2i_no_clinit_check_entry; }
+
address base_address();
void relocate(address new_base);
@@ -709,7 +713,10 @@
public:
static AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint,
- address i2c_entry, address c2i_entry, address c2i_unverified_entry);
+ address i2c_entry,
+ address c2i_entry,
+ address c2i_unverified_entry,
+ address c2i_no_clinit_check_entry = NULL);
static void create_native_wrapper(const methodHandle& method);
static AdapterHandlerEntry* get_adapter(const methodHandle& method);
--- a/src/hotspot/share/runtime/thread.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/src/hotspot/share/runtime/thread.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -2969,11 +2969,6 @@
}
}
- // callee_target is never live across a gc point so NULL it here should
- // it still contain a methdOop.
-
- set_callee_target(NULL);
-
assert(vframe_array_head() == NULL, "deopt in progress at a safepoint!");
// If we have deferred set_locals there might be oops waiting to be
// written
--- a/src/java.base/share/classes/java/net/ServerSocket.java Fri Jul 19 15:11:33 2019 +0530
+++ b/src/java.base/share/classes/java/net/ServerSocket.java Mon Jul 22 11:07:24 2019 +0530
@@ -27,17 +27,11 @@
import java.io.FileDescriptor;
import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.nio.channels.ServerSocketChannel;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
import java.util.Objects;
import java.util.Set;
import java.util.Collections;
-import jdk.internal.access.JavaNetSocketAccess;
-import jdk.internal.access.SharedSecrets;
import sun.net.PlatformSocketImpl;
/**
@@ -1116,27 +1110,4 @@
}
return options;
}
-
- static {
- SharedSecrets.setJavaNetSocketAccess(
- new JavaNetSocketAccess() {
- @Override
- public ServerSocket newServerSocket(SocketImpl impl) {
- return new ServerSocket(impl);
- }
-
- @Override
- public SocketImpl newSocketImpl(Class<? extends SocketImpl> implClass) {
- try {
- Constructor<? extends SocketImpl> ctor =
- implClass.getDeclaredConstructor();
- return ctor.newInstance();
- } catch (NoSuchMethodException | InstantiationException |
- IllegalAccessException | InvocationTargetException e) {
- throw new AssertionError(e);
- }
- }
- }
- );
- }
}
--- a/src/java.base/share/classes/java/net/URLClassLoader.java Fri Jul 19 15:11:33 2019 +0530
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java Mon Jul 22 11:07:24 2019 +0530
@@ -52,7 +52,6 @@
import jdk.internal.loader.Resource;
import jdk.internal.loader.URLClassPath;
-import jdk.internal.access.JavaNetURLClassLoaderAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.perf.PerfCounter;
import sun.net.www.ParseUtil;
@@ -822,14 +821,6 @@
}
static {
- SharedSecrets.setJavaNetURLClassLoaderAccess(
- new JavaNetURLClassLoaderAccess() {
- @Override
- public AccessControlContext getAccessControlContext(URLClassLoader u) {
- return u.acc;
- }
- }
- );
ClassLoader.registerAsParallelCapable();
}
}
--- a/src/java.base/share/classes/jdk/internal/access/JavaNetSocketAccess.java Fri Jul 19 15:11:33 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * 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
- * 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.internal.access;
-
-import java.net.ServerSocket;
-import java.net.SocketImpl;
-
-public interface JavaNetSocketAccess {
- /**
- * Creates a ServerSocket associated with the given SocketImpl.
- */
- ServerSocket newServerSocket(SocketImpl impl);
-
- /*
- * Constructs a SocketImpl instance of the given class.
- */
- SocketImpl newSocketImpl(Class<? extends SocketImpl> implClass);
-}
--- a/src/java.base/share/classes/jdk/internal/access/JavaNetURLClassLoaderAccess.java Fri Jul 19 15:11:33 2019 +0530
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * 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
- * 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.internal.access;
-
-import java.net.URLClassLoader;
-import java.security.AccessControlContext;
-
-public interface JavaNetURLClassLoaderAccess {
- AccessControlContext getAccessControlContext(URLClassLoader u);;
-}
--- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java Fri Jul 19 15:11:33 2019 +0530
+++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java Mon Jul 22 11:07:24 2019 +0530
@@ -58,10 +58,8 @@
private static JavaIOAccess javaIOAccess;
private static JavaNetInetAddressAccess javaNetInetAddressAccess;
private static JavaNetHttpCookieAccess javaNetHttpCookieAccess;
- private static JavaNetSocketAccess javaNetSocketAccess;
private static JavaNetUriAccess javaNetUriAccess;
private static JavaNetURLAccess javaNetURLAccess;
- private static JavaNetURLClassLoaderAccess javaNetURLClassLoaderAccess;
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaIOFilePermissionAccess javaIOFilePermissionAccess;
@@ -151,16 +149,6 @@
return javaNetURLAccess;
}
- public static void setJavaNetURLClassLoaderAccess(JavaNetURLClassLoaderAccess jnua) {
- javaNetURLClassLoaderAccess = jnua;
- }
-
- public static JavaNetURLClassLoaderAccess getJavaNetURLClassLoaderAccess() {
- if (javaNetURLClassLoaderAccess == null)
- unsafe.ensureClassInitialized(java.net.URLClassLoader.class);
- return javaNetURLClassLoaderAccess;
- }
-
public static void setJavaNetInetAddressAccess(JavaNetInetAddressAccess jna) {
javaNetInetAddressAccess = jna;
}
@@ -181,16 +169,6 @@
return javaNetHttpCookieAccess;
}
- public static void setJavaNetSocketAccess(JavaNetSocketAccess jnsa) {
- javaNetSocketAccess = jnsa;
- }
-
- public static JavaNetSocketAccess getJavaNetSocketAccess() {
- if (javaNetSocketAccess == null)
- unsafe.ensureClassInitialized(java.net.ServerSocket.class);
- return javaNetSocketAccess;
- }
-
public static void setJavaNioAccess(JavaNioAccess jna) {
javaNioAccess = jna;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/gc/metaspace/TestSizeTransitions.java Mon Jul 22 11:07:24 2019 +0530
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Twitter, Inc.
+ * 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 gc.metaspace;
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+/* @test TestSizeTransitionsSerial
+ * @key gc
+ * @requires vm.gc.Serial
+ * @summary Tests that the metaspace size transition logging is done correctly.
+ * @library /test/lib
+ * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseSerialGC
+ * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseSerialGC
+ */
+
+/* @test TestSizeTransitionsParallel
+ * @key gc
+ * @requires vm.gc.Parallel
+ * @summary Tests that the metaspace size transition logging is done correctly.
+ * @library /test/lib
+ * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseParallelGC
+ * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseParallelGC
+ */
+
+/* @test TestSizeTransitionsG1
+ * @key gc
+ * @requires vm.gc.G1
+ * @summary Tests that the metaspace size transition logging is done correctly.
+ * @library /test/lib
+ * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseG1GC
+ * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseG1GC
+ */
+
+/* @test TestSizeTransitionsCMS
+ * @key gc
+ * @requires vm.gc.ConcMarkSweep
+ * @summary Tests that the metaspace size transition logging is done correctly.
+ * @library /test/lib
+ * @run driver gc.metaspace.TestSizeTransitions false -XX:+UseConcMarkSweepGC
+ * @run driver gc.metaspace.TestSizeTransitions true -XX:+UseConcMarkSweepGC
+ */
+
+public class TestSizeTransitions {
+ public static class Run {
+ public static void main(String... args) throws Exception {
+ System.out.println("Run started.");
+
+ // easiest way to generate a metaspace transition is to ask for a full GC
+ System.gc();
+
+ System.out.println("Run finished.");
+ }
+ }
+
+ // matches the log tags
+ // e.g., [0.043s][info][gc]
+ private static final String LOG_TAGS_REGEX = "(\\[.*\\])+ ";
+
+ // matches a size transition
+ // e.g., 177K(4864K)->177K(4864K)
+ private static final String SIZE_TRANSITION_REGEX = "\\d+K\\(\\d+K\\)->\\d+K\\(\\d+K\\)";
+
+ // matches -coops metaspace size transitions
+ private static final String NO_COOPS_REGEX =
+ String.format("^%s.* Metaspace: %s$",
+ LOG_TAGS_REGEX,
+ SIZE_TRANSITION_REGEX);
+
+ // matches +coops metaspace size transitions
+ private static final String COOPS_REGEX =
+ String.format("^%s.* Metaspace: %s NonClass: %s Class: %s$",
+ LOG_TAGS_REGEX,
+ SIZE_TRANSITION_REGEX,
+ SIZE_TRANSITION_REGEX,
+ SIZE_TRANSITION_REGEX);
+
+ public static void main(String... args) throws Exception {
+ // args: <use-coops> <gc-arg>
+ if (args.length != 2) {
+ throw new RuntimeException("wrong number of args: " + args.length);
+ }
+
+ final boolean useCoops = Boolean.parseBoolean(args[0]);
+ final String gcArg = args[1];
+ final String[] jvmArgs = {
+ useCoops ? "-XX:+UseCompressedOops" : "-XX:-UseCompressedOops",
+ gcArg,
+ "-Xmx256m",
+ "-Xlog:gc,gc+metaspace=info",
+ TestSizeTransitions.Run.class.getName()
+ };
+
+ System.out.println("JVM args:");
+ for (String a : jvmArgs) {
+ System.out.println(" " + a);
+ }
+
+ final ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(jvmArgs);
+ final OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ System.out.println(output.getStdout());
+ output.shouldHaveExitValue(0);
+
+ if (useCoops) {
+ output.stdoutShouldMatch(COOPS_REGEX);
+ output.stdoutShouldNotMatch(NO_COOPS_REGEX);
+ } else {
+ output.stdoutShouldMatch(NO_COOPS_REGEX);
+ output.stdoutShouldNotMatch(COOPS_REGEX);
+ }
+ }
+}
--- a/test/hotspot/jtreg/runtime/clinit/ClassInitBarrier.java Fri Jul 19 15:11:33 2019 +0530
+++ b/test/hotspot/jtreg/runtime/clinit/ClassInitBarrier.java Mon Jul 22 11:07:24 2019 +0530
@@ -27,24 +27,24 @@
*
* @requires !vm.graal.enabled
*
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=false ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=true ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=false -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=true -Xcheck:jni ClassInitBarrier
*
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -Xcheck:jni ClassInitBarrier
*
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -Xcheck:jni ClassInitBarrier
*
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
*
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* ClassInitBarrier
- * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
+ * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
*/
import jdk.test.lib.Asserts;
@@ -70,6 +70,10 @@
static class Test {
static class A {
static {
+ if (!init(B.class)) {
+ throw new Error("init failed");
+ }
+
changePhase(Phase.IN_PROGRESS);
runTests(); // interpreted mode
warmup(); // trigger compilation
@@ -89,13 +93,15 @@
int f;
void m() {}
+
+ static native boolean init(Class<B> cls);
}
static class B extends A {}
- static void testInvokeStatic(Runnable action) { A.staticM(action); }
- static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
- static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
+ static void testInvokeStatic(Runnable action) { A.staticM(action); }
+ static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
+ static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
static int testGetStatic(Runnable action) { int v = A.staticF; action.run(); return v; }
static void testPutStatic(Runnable action) { A.staticF = 1; action.run(); }
@@ -106,20 +112,45 @@
static void testPutField(A recv, Runnable action) { recv.f = 1; action.run(); }
static void testInvokeVirtual(A recv, Runnable action) { recv.m(); action.run(); }
+ static native void testInvokeStaticJNI(Runnable action);
+ static native void testInvokeStaticSyncJNI(Runnable action);
+ static native void testInvokeStaticNativeJNI(Runnable action);
+
+ static native int testGetStaticJNI(Runnable action);
+ static native void testPutStaticJNI(Runnable action);
+ static native A testNewInstanceAJNI(Runnable action);
+ static native B testNewInstanceBJNI(Runnable action);
+
+ static native int testGetFieldJNI(A recv, Runnable action);
+ static native void testPutFieldJNI(A recv, Runnable action);
+ static native void testInvokeVirtualJNI(A recv, Runnable action);
+
static void runTests() {
checkBlockingAction(Test::testInvokeStatic); // invokestatic
+ checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
- checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
checkBlockingAction(Test::testGetStatic); // getstatic
checkBlockingAction(Test::testPutStatic); // putstatic
checkBlockingAction(Test::testNewInstanceA); // new
+ checkNonBlockingAction(Test::testInvokeStaticJNI); // invokestatic
+ checkNonBlockingAction(Test::testInvokeStaticSyncJNI); // invokestatic
+ checkNonBlockingAction(Test::testInvokeStaticNativeJNI); // invokestatic
+ checkNonBlockingAction(Test::testGetStaticJNI); // getstatic
+ checkNonBlockingAction(Test::testPutStaticJNI); // putstatic
+ checkBlockingAction(Test::testNewInstanceAJNI); // new
+
A recv = testNewInstanceB(NON_BLOCKING.get()); // trigger B initialization
checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
checkNonBlockingAction(recv, Test::testGetField); // getfield
checkNonBlockingAction(recv, Test::testPutField); // putfield
checkNonBlockingAction(recv, Test::testInvokeVirtual); // invokevirtual
+
+ checkNonBlockingAction(Test::testNewInstanceBJNI); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
+ checkNonBlockingAction(recv, Test::testGetFieldJNI); // getfield
+ checkNonBlockingAction(recv, Test::testPutFieldJNI); // putfield
+ checkNonBlockingAction(recv, Test::testInvokeVirtualJNI); // invokevirtual
}
static void warmup() {
--- a/test/hotspot/jtreg/runtime/clinit/libClassInitBarrier.cpp Fri Jul 19 15:11:33 2019 +0530
+++ b/test/hotspot/jtreg/runtime/clinit/libClassInitBarrier.cpp Mon Jul 22 11:07:24 2019 +0530
@@ -25,6 +25,17 @@
static jmethodID methodId;
+static jclass test_class_A;
+static jclass test_class_B;
+
+static jmethodID test_staticM_id;
+static jmethodID test_staticS_id;
+static jmethodID test_staticN_id;
+static jmethodID test_A_m_id;
+
+static jfieldID test_staticF_id;
+static jfieldID test_A_f_id;
+
extern "C" {
JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_init(JNIEnv* env, jclass cls) {
jclass runnable = env->FindClass("java/lang/Runnable");
@@ -36,7 +47,103 @@
return JNI_TRUE;
}
+ JNIEXPORT jboolean JNICALL Java_ClassInitBarrier_00024Test_00024A_init(JNIEnv* env, jclass cls, jclass arg1) {
+ test_class_A = (jclass)env->NewGlobalRef(cls);
+ if (test_class_A == NULL) return JNI_FALSE;
+
+ test_class_B = (jclass)env->NewGlobalRef(arg1);
+ if (test_class_B == NULL) return JNI_FALSE;
+
+ test_staticM_id = env->GetStaticMethodID(test_class_A, "staticM", "(Ljava/lang/Runnable;)V");
+ if (test_staticM_id == NULL) return JNI_FALSE;
+
+ test_staticS_id = env->GetStaticMethodID(test_class_A, "staticS", "(Ljava/lang/Runnable;)V");
+ if (test_staticS_id == NULL) return JNI_FALSE;
+
+ test_staticN_id = env->GetStaticMethodID(test_class_A, "staticN", "(Ljava/lang/Runnable;)V");
+ if (test_staticN_id == NULL) return JNI_FALSE;
+
+ test_A_m_id = env->GetMethodID(test_class_A, "m", "()V");
+ if (test_A_m_id == NULL) return JNI_FALSE;
+
+ test_staticF_id = env->GetStaticFieldID(test_class_A, "staticF", "I");
+ if (test_staticF_id == NULL) return JNI_FALSE;
+
+ test_A_f_id = env->GetFieldID(test_class_A, "f", "I");
+ if (test_A_f_id == NULL) return JNI_FALSE;
+
+ return JNI_TRUE;
+ }
+
JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_00024A_staticN(JNIEnv* env, jclass cls, jobject action) {
env->CallVoidMethod(action, methodId);
}
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticJNI(JNIEnv* env, jclass cls, jobject action) {
+ env->CallStaticVoidMethod(test_class_A, test_staticM_id, action);
+ }
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticSyncJNI(JNIEnv* env, jclass cls, jobject action) {
+ env->CallStaticVoidMethod(test_class_A, test_staticS_id, action);
+ }
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeStaticNativeJNI(JNIEnv* env, jclass cls, jobject action) {
+ env->CallStaticVoidMethod(test_class_A, test_staticN_id, action);
+ }
+
+ JNIEXPORT jint JNICALL Java_ClassInitBarrier_00024Test_testGetStaticJNI(JNIEnv* env, jclass cls, jobject action) {
+ jint v = env->GetStaticIntField(test_class_A, test_staticF_id); // int v = A.staticF;
+ env->CallVoidMethod(action, methodId); // action.run();
+ return v;
+ }
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testPutStaticJNI(JNIEnv* env, jclass cls, jobject action) {
+ env->SetStaticIntField(test_class_A, test_staticF_id, 1); // A.staticF = 1;
+ env->CallVoidMethod(action, methodId); // action.run();
+ }
+
+ JNIEXPORT jobject JNICALL Java_ClassInitBarrier_00024Test_testNewInstanceAJNI(JNIEnv* env, jclass cls, jobject action) {
+ jobject obj = env->AllocObject(test_class_A); // A obj = new A();
+ if (env->ExceptionOccurred()) {
+ return NULL;
+ } else if (obj == NULL) {
+ jclass errorClass = env->FindClass("java/lang/AssertionError");
+ int ret = env->ThrowNew(errorClass, "JNI: AllocObject: allocation failed, but no exception thrown");
+ return NULL;
+ }
+ env->CallVoidMethod(action, methodId); // action.run();
+ return obj;
+ }
+
+ JNIEXPORT jobject JNICALL Java_ClassInitBarrier_00024Test_testNewInstanceBJNI(JNIEnv* env, jclass cls, jobject action) {
+ jobject obj = env->AllocObject(test_class_B); // B obj = new B();
+ if (env->ExceptionOccurred()) {
+ return NULL;
+ } else if (obj == NULL) {
+ jclass errorClass = env->FindClass("java/lang/AssertionError");
+ int ret = env->ThrowNew(errorClass, "JNI: AllocObject: allocation failed, but no exception thrown");
+ return NULL;
+ }
+ env->CallVoidMethod(action, methodId); // action.run();
+ return obj;
+ }
+
+ JNIEXPORT jint JNICALL Java_ClassInitBarrier_00024Test_testGetFieldJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
+ jint v = env->GetIntField(recv, test_A_f_id); // int v = recv.f;
+ env->CallVoidMethod(action, methodId); // action.run();
+ return v;
+ }
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testPutFieldJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
+ env->SetIntField(recv, test_A_f_id, 1); // A.staticF = 1;
+ env->CallVoidMethod(action, methodId); // action.run();
+ }
+
+ JNIEXPORT void JNICALL Java_ClassInitBarrier_00024Test_testInvokeVirtualJNI(JNIEnv* env, jclass cls, jobject recv, jobject action) {
+ env->CallVoidMethod(recv, test_A_m_id); // recv.m();
+ if (env->ExceptionOccurred()) {
+ return;
+ }
+ env->CallVoidMethod(action, methodId); // action.run();
+ }
}
Binary file test/jdk/sun/misc/ClassLoaderUtil/test.jar has changed