# HG changeset patch # User asaha # Date 1452011281 28800 # Node ID c3091ebd28118acf1e5fdba27aa4006ec1dcb6e5 # Parent f796867c1bcb37c7ec8f8095c7d1cc38511e075c# Parent 80959a760b85781672c1ceb76bfa860eae46ba34 Merge diff -r f796867c1bcb -r c3091ebd2811 .hgtags --- a/.hgtags Tue Dec 15 22:59:18 2015 -0800 +++ b/.hgtags Tue Jan 05 08:28:01 2016 -0800 @@ -792,3 +792,5 @@ b8e7dd0e21173ad829b40361763d27cb6ac532e9 jdk8u72-b12 a8e4754b89aecc388623394a20f6d43d4c58f083 jdk8u72-b13 d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00 +c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01 +218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02 diff -r f796867c1bcb -r c3091ebd2811 agent/src/os/linux/LinuxDebuggerLocal.c --- a/agent/src/os/linux/LinuxDebuggerLocal.c Tue Dec 15 22:59:18 2015 -0800 +++ b/agent/src/os/linux/LinuxDebuggerLocal.c Tue Jan 05 08:28:01 2016 -0800 @@ -209,9 +209,12 @@ verifyBitness(env, (char *) &buf); CHECK_EXCEPTION; + char err_buf[200]; struct ps_prochandle* ph; - if ( (ph = Pgrab(jpid)) == NULL) { - THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process"); + if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) { + char msg[230]; + snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf); + THROW_NEW_DEBUGGER_EXCEPTION(msg); } (*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph); fillThreadsAndLoadObjects(env, this_obj, ph); diff -r f796867c1bcb -r c3091ebd2811 agent/src/os/linux/libproc.h --- a/agent/src/os/linux/libproc.h Tue Dec 15 22:59:18 2015 -0800 +++ b/agent/src/os/linux/libproc.h Tue Jan 05 08:28:01 2016 -0800 @@ -69,6 +69,7 @@ #if defined(sparc) || defined(sparcv9) || defined(ppc64) +#include #define user_regs_struct pt_regs #endif @@ -82,7 +83,7 @@ struct ps_prochandle; // attach to a process -struct ps_prochandle* Pgrab(pid_t pid); +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len); // attach to a core dump struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile); diff -r f796867c1bcb -r c3091ebd2811 agent/src/os/linux/ps_proc.c --- a/agent/src/os/linux/ps_proc.c Tue Dec 15 22:59:18 2015 -0800 +++ b/agent/src/os/linux/ps_proc.c Tue Jan 05 08:28:01 2016 -0800 @@ -215,9 +215,12 @@ } // attach to a process/thread specified by "pid" -static bool ptrace_attach(pid_t pid) { +static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) { if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { - print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); + char buf[200]; + char* msg = strerror_r(errno, buf, sizeof(buf)); + snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg); + print_debug("%s\n", err_buf); return false; } else { return ptrace_waitpid(pid); @@ -339,16 +342,17 @@ }; // attach to the process. One and only one exposed stuff -struct ps_prochandle* Pgrab(pid_t pid) { +struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { struct ps_prochandle* ph = NULL; thread_info* thr = NULL; if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { - print_debug("can't allocate memory for ps_prochandle\n"); + snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); + print_debug("%s\n", err_buf); return NULL; } - if (ptrace_attach(pid) != true) { + if (ptrace_attach(pid, err_buf, err_buf_len) != true) { free(ph); return NULL; } @@ -371,7 +375,7 @@ thr = ph->threads; while (thr) { // don't attach to the main thread again - if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) { + if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) { // even if one attach fails, we get return NULL Prelease(ph); return NULL; diff -r f796867c1bcb -r c3091ebd2811 make/linux/Makefile --- a/make/linux/Makefile Tue Dec 15 22:59:18 2015 -0800 +++ b/make/linux/Makefile Tue Jan 05 08:28:01 2016 -0800 @@ -67,8 +67,12 @@ endif endif # C1 is not ported on ppc64, so we cannot build a tiered VM: -ifeq ($(ARCH),ppc64) - FORCE_TIERED=0 +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + FORCE_TIERED=0 + endif endif ifdef LP64 diff -r f796867c1bcb -r c3091ebd2811 make/linux/makefiles/defs.make --- a/make/linux/makefiles/defs.make Tue Dec 15 22:59:18 2015 -0800 +++ b/make/linux/makefiles/defs.make Tue Jan 05 08:28:01 2016 -0800 @@ -69,7 +69,7 @@ endif # sparc -ifeq ($(ARCH), sparc64) +ifneq (,$(findstring $(ARCH), sparc)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 @@ -83,39 +83,35 @@ HS_ARCH = sparc endif -# amd64/x86_64 -ifneq (,$(findstring $(ARCH), amd64 x86_64)) +# i686/i586 and amd64/x86_64 +ifneq (,$(findstring $(ARCH), amd64 x86_64 i686 i586)) ifeq ($(ARCH_DATA_MODEL), 64) ARCH_DATA_MODEL = 64 MAKE_ARGS += LP64=1 PLATFORM = linux-amd64 VM_PLATFORM = linux_amd64 - HS_ARCH = x86 else ARCH_DATA_MODEL = 32 PLATFORM = linux-i586 VM_PLATFORM = linux_i486 - HS_ARCH = x86 - # We have to reset ARCH to i686 since SRCARCH relies on it - ARCH = i686 endif + HS_ARCH = x86 endif -# i686/i586 ie 32-bit x86 -ifneq (,$(findstring $(ARCH), i686 i586)) - ARCH_DATA_MODEL = 32 - PLATFORM = linux-i586 - VM_PLATFORM = linux_i486 - HS_ARCH = x86 -endif - -# PPC64 -ifeq ($(ARCH), ppc64) - ARCH_DATA_MODEL = 64 - MAKE_ARGS += LP64=1 - PLATFORM = linux-ppc64 - VM_PLATFORM = linux_ppc64 - HS_ARCH = ppc +# PPC +# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but +# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! +ifneq (,$(findstring $(ARCH), ppc ppc64)) + ifeq ($(ARCH_DATA_MODEL), 64) + MAKE_ARGS += LP64=1 + PLATFORM = linux-ppc64 + VM_PLATFORM = linux_ppc64 + else + ARCH_DATA_MODEL = 32 + PLATFORM = linux-ppc + VM_PLATFORM = linux_ppc + endif + HS_ARCH = ppc endif # On 32 bit linux we build server and client, on 64 bit just server. diff -r f796867c1bcb -r c3091ebd2811 src/cpu/sparc/vm/frame_sparc.cpp --- a/src/cpu/sparc/vm/frame_sparc.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/cpu/sparc/vm/frame_sparc.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -447,32 +447,6 @@ } #endif // CC_INTERP - -#ifdef ASSERT -// Debugging aid -static frame nth_sender(int n) { - frame f = JavaThread::current()->last_frame(); - - for(int i = 0; i < n; ++i) - f = f.sender((RegisterMap*)NULL); - - printf("first frame %d\n", f.is_first_frame() ? 1 : 0); - printf("interpreted frame %d\n", f.is_interpreted_frame() ? 1 : 0); - printf("java frame %d\n", f.is_java_frame() ? 1 : 0); - printf("entry frame %d\n", f.is_entry_frame() ? 1 : 0); - printf("native frame %d\n", f.is_native_frame() ? 1 : 0); - if (f.is_compiled_frame()) { - if (f.is_deoptimized_frame()) - printf("deoptimized frame 1\n"); - else - printf("compiled frame 1\n"); - } - - return f; -} -#endif - - frame frame::sender_for_entry_frame(RegisterMap *map) const { assert(map != NULL, "map must be set"); // Java frame called from C; skip all C frames and return top C diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/c1/c1_ValueType.cpp --- a/src/share/vm/c1/c1_ValueType.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/c1/c1_ValueType.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -153,7 +153,19 @@ case T_FLOAT : return new FloatConstant (value.as_float ()); case T_DOUBLE : return new DoubleConstant(value.as_double()); case T_ARRAY : // fall through (ciConstant doesn't have an array accessor) - case T_OBJECT : return new ObjectConstant(value.as_object()); + case T_OBJECT : { + // TODO: Common the code with GraphBuilder::load_constant? + ciObject* obj = value.as_object(); + if (obj->is_null_object()) + return objectNull; + if (obj->is_loaded()) { + if (obj->is_array()) + return new ArrayConstant(obj->as_array()); + else if (obj->is_instance()) + return new InstanceConstant(obj->as_instance()); + } + return new ObjectConstant(obj); + } } ShouldNotReachHere(); return illegalType; diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -2331,6 +2331,7 @@ case GCCause::_java_lang_system_gc: return ExplicitGCInvokesConcurrent; case GCCause::_g1_humongous_allocation: return true; case GCCause::_update_allocation_context_stats_inc: return true; + case GCCause::_wb_conc_mark: return true; default: return false; } } diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -90,12 +90,8 @@ void VM_G1IncCollectionPause::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - assert(!_should_initiate_conc_mark || - ((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) || - (_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent) || - _gc_cause == GCCause::_g1_humongous_allocation || - _gc_cause == GCCause::_update_allocation_context_stats_inc), - "only a GC locker, a System.gc(), stats update or a hum allocation induced GC should start a cycle"); + assert(!_should_initiate_conc_mark || g1h->should_do_concurrent_full_gc(_gc_cause), + "only a GC locker, a System.gc(), stats update, whitebox, or a hum allocation induced GC should start a cycle"); if (_word_size > 0) { // An allocation has been requested. So, try to do that first. diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/gc_interface/gcCause.cpp --- a/src/share/vm/gc_interface/gcCause.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/gc_interface/gcCause.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -54,6 +54,9 @@ case _wb_young_gc: return "WhiteBox Initiated Young GC"; + case _wb_conc_mark: + return "WhiteBox Initiated Concurrent Mark"; + case _update_allocation_context_stats_inc: case _update_allocation_context_stats_full: return "Update Allocation Context Stats"; diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/gc_interface/gcCause.hpp --- a/src/share/vm/gc_interface/gcCause.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/gc_interface/gcCause.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -47,6 +47,7 @@ _heap_inspection, _heap_dump, _wb_young_gc, + _wb_conc_mark, _update_allocation_context_stats_inc, _update_allocation_context_stats_full, diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -205,6 +205,9 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseCountedLoopSafepoints, false, \ + "Force counted loops to keep a safepoint") \ + \ product(bool, UseLoopPredicate, true, \ "Generate a predicate to select fast/slow loop versions") \ \ @@ -669,6 +672,9 @@ product_pd(bool, TrapBasedRangeChecks, \ "Generate code for range checks that uses a cmp and trap " \ "instruction raising SIGTRAP. Used on PPC64.") \ + \ + develop(bool, RenumberLiveNodes, true, \ + "Renumber live nodes") \ C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/compile.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -2093,6 +2093,20 @@ // so keep only the actual candidates for optimizations. cleanup_expensive_nodes(igvn); + if (!failing() && RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) { + NOT_PRODUCT(Compile::TracePhase t2("", &_t_renumberLive, TimeCompiler);) + initial_gvn()->replace_with(&igvn); + for_igvn()->clear(); + Unique_Node_List new_worklist(C->comp_arena()); + { + ResourceMark rm; + PhaseRenumberLive prl = PhaseRenumberLive(initial_gvn(), for_igvn(), &new_worklist); + } + set_for_igvn(&new_worklist); + igvn = PhaseIterGVN(initial_gvn()); + igvn.optimize(); + } + // Perform escape analysis if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { if (has_loops()) { diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/loopnode.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -685,14 +685,16 @@ } // LoopLimitCheck - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); + if (!UseCountedLoopSafepoints) { + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt); + } + loop->_tail = iftrue; } - loop->_tail = iftrue; } // Build a canonical trip test. @@ -781,12 +783,14 @@ lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceding SafePoint and remove - Node *sfpt2 = le->in(0); - if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + if (!UseCountedLoopSafepoints) { + // Check for immediately preceding SafePoint and remove + Node *sfpt2 = le->in(0); + if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { + lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt2); + } } } @@ -1806,6 +1810,37 @@ } } +void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { + Node* keep = NULL; + if (keep_one) { + // Look for a safepoint on the idom-path. + for (Node* i = tail(); i != _head; i = phase->idom(i)) { + if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { + keep = i; + break; // Found one + } + } + } + + // Don't remove any safepoints if it is requested to keep a single safepoint and + // no safepoint was found on idom-path. It is not safe to remove any safepoint + // in this case since there's no safepoint dominating all paths in the loop body. + bool prune = !keep_one || keep != NULL; + + // Delete other safepoints in this loop. + Node_List* sfpts = _safepts; + if (prune && sfpts != NULL) { + assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); + for (uint i = 0; i < sfpts->size(); i++) { + Node* n = sfpts->at(i); + assert(phase->get_loop(n) == this, ""); + if (n != keep && phase->is_deleteable_safept(n)) { + phase->lazy_replace(n, n->in(TypeFunc::Control)); + } + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { @@ -1817,42 +1852,23 @@ if (_head->is_CountedLoop() || phase->is_counted_loop(_head, this)) { - _has_sfpt = 1; // Indicate we do not need a safepoint here - - // Look for safepoints to remove. - Node_List* sfpts = _safepts; - if (sfpts != NULL) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } + + if (!UseCountedLoopSafepoints) { + // Indicate we do not need a safepoint here + _has_sfpt = 1; } + // Remove safepoints + bool keep_one_sfpt = !(_has_call || _has_sfpt); + remove_safepoints(phase, keep_one_sfpt); + // Look for induction variables phase->replace_parallel_iv(this); } else if (_parent != NULL && !_irreducible) { - // Not a counted loop. - // Look for a safepoint on the idom-path. - Node* sfpt = tail(); - for (; sfpt != _head; sfpt = phase->idom(sfpt)) { - if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this) - break; // Found one - } - // Delete other safepoints in this loop. - Node_List* sfpts = _safepts; - if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (n != sfpt && phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } - } + // Not a counted loop. Keep one safepoint. + bool keep_one_sfpt = true; + remove_safepoints(phase, keep_one_sfpt); } // Recursively @@ -1906,6 +1922,15 @@ if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); } + if (_has_call) tty->print(" has_call"); + if (_has_sfpt) tty->print(" has_sfpt"); + if (_rce_candidate) tty->print(" rce"); + if (_safepts != NULL && _safepts->size() > 0) { + tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); + } + if (_required_safept != NULL && _required_safept->size() > 0) { + tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); + } tty->cr(); } diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/loopnode.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -403,6 +403,9 @@ // encountered. void allpaths_check_safepts(VectorSet &visited, Node_List &stack); + // Remove safepoints from loop. Optionally keeping one. + void remove_safepoints(PhaseIdealLoop* phase, bool keep_one); + // Convert to counted loops where possible void counted_loop( PhaseIdealLoop *phase ); diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/node.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -325,6 +325,9 @@ // Create a Node, with a given number of required edges. Node::Node(uint req) : _idx(IDX_INIT(req)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { assert( req < Compile::current()->max_node_limit() - NodeLimitFudgeFactor, "Input limit exceeded" ); debug_only( verify_construction() ); @@ -344,6 +347,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0) : _idx(IDX_INIT(1)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -356,6 +362,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1) : _idx(IDX_INIT(2)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -370,6 +379,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2) : _idx(IDX_INIT(3)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -386,6 +398,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3) : _idx(IDX_INIT(4)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -404,6 +419,9 @@ //------------------------------Node------------------------------------------- Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4) : _idx(IDX_INIT(5)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -425,6 +443,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5) : _idx(IDX_INIT(6)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -448,6 +469,9 @@ Node::Node(Node *n0, Node *n1, Node *n2, Node *n3, Node *n4, Node *n5, Node *n6) : _idx(IDX_INIT(7)) +#ifdef ASSERT + , _parse_idx(_idx) +#endif { debug_only( verify_construction() ); NOT_PRODUCT(nodes_created++); @@ -2083,6 +2107,17 @@ #endif } +void Node_List::dump_simple() const { +#ifndef PRODUCT + for( uint i = 0; i < _cnt; i++ ) + if( _nodes[i] ) { + tty->print(" %d", _nodes[i]->_idx); + } else { + tty->print(" NULL"); + } +#endif +} + //============================================================================= //------------------------------remove----------------------------------------- void Unique_Node_List::remove( Node *n ) { diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/node.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -294,10 +294,16 @@ public: // Each Node is assigned a unique small/dense number. This number is used - // to index into auxiliary arrays of data and bitvectors. - // It is declared const to defend against inadvertant assignment, - // since it is used by clients as a naked field. + // to index into auxiliary arrays of data and bit vectors. + // The field _idx is declared constant to defend against inadvertent assignments, + // since it is used by clients as a naked field. However, the field's value can be + // changed using the set_idx() method. + // + // The PhaseRenumberLive phase renumbers nodes based on liveness information. + // Therefore, it updates the value of the _idx field. The parse-time _idx is + // preserved in _parse_idx. const node_idx_t _idx; + DEBUG_ONLY(const node_idx_t _parse_idx;) // Get the (read-only) number of input edges uint req() const { return _cnt; } @@ -1368,6 +1374,7 @@ void clear() { _cnt = 0; Node_Array::clear(); } // retain storage uint size() const { return _cnt; } void dump() const; + void dump_simple() const; }; //------------------------------Unique_Node_List------------------------------- diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/phase.cpp --- a/src/share/vm/opto/phase.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/phase.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -67,6 +67,8 @@ elapsedTimer Phase::_t_iterGVN; elapsedTimer Phase::_t_iterGVN2; elapsedTimer Phase::_t_incrInline; +elapsedTimer Phase::_t_renumberLive; + // Subtimers for _t_registerAllocation elapsedTimer Phase::_t_ctorChaitin; @@ -115,13 +117,14 @@ } tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds()); tty->print_cr (" incrInline : %3.3f sec", Phase::_t_incrInline.seconds()); + tty->print_cr (" renumberLive : %3.3f sec", Phase::_t_renumberLive.seconds()); tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds()); tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds()); tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds()); tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds()); tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds()); tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds()); - double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + + double optimizer_subtotal = Phase::_t_iterGVN.seconds() + Phase::_t_iterGVN2.seconds() + Phase::_t_renumberLive.seconds() + Phase::_t_escapeAnalysis.seconds() + Phase::_t_macroEliminate.seconds() + Phase::_t_idealLoop.seconds() + Phase::_t_ccp.seconds() + Phase::_t_macroExpand.seconds() + Phase::_t_graphReshaping.seconds(); diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/phase.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -40,22 +40,23 @@ class Phase : public StackObj { public: enum PhaseNumber { - Compiler, // Top-level compiler phase - Parser, // Parse bytecodes - Remove_Useless, // Remove useless nodes - Optimistic, // Optimistic analysis phase - GVN, // Pessimistic global value numbering phase - Ins_Select, // Instruction selection phase - CFG, // Build a CFG - BlockLayout, // Linear ordering of blocks - Register_Allocation, // Register allocation, duh - LIVE, // Dragon-book LIVE range problem - StringOpts, // StringBuilder related optimizations - Interference_Graph, // Building the IFG - Coalesce, // Coalescing copies - Ideal_Loop, // Find idealized trip-counted loops - Macro_Expand, // Expand macro nodes - Peephole, // Apply peephole optimizations + Compiler, // Top-level compiler phase + Parser, // Parse bytecodes + Remove_Useless, // Remove useless nodes + Remove_Useless_And_Renumber_Live, // First, remove useless nodes from the graph. Then, renumber live nodes. + Optimistic, // Optimistic analysis phase + GVN, // Pessimistic global value numbering phase + Ins_Select, // Instruction selection phase + CFG, // Build a CFG + BlockLayout, // Linear ordering of blocks + Register_Allocation, // Register allocation, duh + LIVE, // Dragon-book LIVE range problem + StringOpts, // StringBuilder related optimizations + Interference_Graph, // Building the IFG + Coalesce, // Coalescing copies + Ideal_Loop, // Find idealized trip-counted loops + Macro_Expand, // Expand macro nodes + Peephole, // Apply peephole optimizations last_phase }; protected: @@ -102,6 +103,7 @@ static elapsedTimer _t_iterGVN; static elapsedTimer _t_iterGVN2; static elapsedTimer _t_incrInline; + static elapsedTimer _t_renumberLive; // Subtimers for _t_registerAllocation static elapsedTimer _t_ctorChaitin; diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/phaseX.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -398,7 +398,7 @@ //============================================================================= //------------------------------PhaseRemoveUseless----------------------------- // 1) Use a breadthfirst walk to collect useful nodes reachable from root. -PhaseRemoveUseless::PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ) : Phase(Remove_Useless), +PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num) : Phase(phase_num), _useful(Thread::current()->resource_area()) { // Implementation requires 'UseLoopSafepoints == true' and an edge from root @@ -435,6 +435,82 @@ } } +//============================================================================= +//------------------------------PhaseRenumberLive------------------------------ +// First, remove useless nodes (equivalent to identifying live nodes). +// Then, renumber live nodes. +// +// The set of live nodes is returned by PhaseRemoveUseless in the _useful structure. +// If the number of live nodes is 'x' (where 'x' == _useful.size()), then the +// PhaseRenumberLive updates the node ID of each node (the _idx field) with a unique +// value in the range [0, x). +// +// At the end of the PhaseRenumberLive phase, the compiler's count of unique nodes is +// updated to 'x' and the list of dead nodes is reset (as there are no dead nodes). +// +// The PhaseRenumberLive phase updates two data structures with the new node IDs. +// (1) The worklist is used by the PhaseIterGVN phase to identify nodes that must be +// processed. A new worklist (with the updated node IDs) is returned in 'new_worklist'. +// (2) Type information (the field PhaseGVN::_types) maps type information to each +// node ID. The mapping is updated to use the new node IDs as well. Updated type +// information is returned in PhaseGVN::_types. +// +// The PhaseRenumberLive phase does not preserve the order of elements in the worklist. +// +// Other data structures used by the compiler are not updated. The hash table for value +// numbering (the field PhaseGVN::_table) is not updated because computing the hash +// values is not based on node IDs. The field PhaseGVN::_nodes is not updated either +// because it is empty wherever PhaseRenumberLive is used. +PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num) : + PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live) { + + assert(RenumberLiveNodes, "RenumberLiveNodes must be set to true for node renumbering to take place"); + assert(C->live_nodes() == _useful.size(), "the number of live nodes must match the number of useful nodes"); + assert(gvn->nodes_size() == 0, "GVN must not contain any nodes at this point"); + + uint old_unique_count = C->unique(); + uint live_node_count = C->live_nodes(); + uint worklist_size = worklist->size(); + + // Storage for the updated type information. + Type_Array new_type_array(C->comp_arena()); + + // Iterate over the set of live nodes. + uint current_idx = 0; // The current new node ID. Incremented after every assignment. + for (uint i = 0; i < _useful.size(); i++) { + Node* n = _useful.at(i); + const Type* type = gvn->type_or_null(n); + new_type_array.map(current_idx, type); + + bool in_worklist = false; + if (worklist->member(n)) { + in_worklist = true; + } + + n->set_idx(current_idx); // Update node ID. + + if (in_worklist) { + new_worklist->push(n); + } + + current_idx++; + } + + assert(worklist_size == new_worklist->size(), "the new worklist must have the same size as the original worklist"); + assert(live_node_count == current_idx, "all live nodes must be processed"); + + // Replace the compiler's type information with the updated type information. + gvn->replace_types(new_type_array); + + // Update the unique node count of the compilation to the number of currently live nodes. + C->set_unique(live_node_count); + + // Set the dead node count to 0 and reset dead node list. + C->reset_dead_node_list(); +} + //============================================================================= //------------------------------PhaseTransform--------------------------------- diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/opto/phaseX.hpp Tue Jan 05 08:28:01 2016 -0800 @@ -148,11 +148,21 @@ Unique_Node_List _useful; // Nodes reachable from root // list is allocated from current resource area public: - PhaseRemoveUseless( PhaseGVN *gvn, Unique_Node_List *worklist ); + PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num = Remove_Useless); Unique_Node_List *get_useful() { return &_useful; } }; +//------------------------------PhaseRenumber---------------------------------- +// Phase that first performs a PhaseRemoveUseless, then it renumbers compiler +// structures accordingly. +class PhaseRenumberLive : public PhaseRemoveUseless { +public: + PhaseRenumberLive(PhaseGVN* gvn, + Unique_Node_List* worklist, Unique_Node_List* new_worklist, + PhaseNumber phase_num = Remove_Useless_And_Renumber_Live); +}; + //------------------------------PhaseTransform--------------------------------- // Phases that analyze, then transform. Constructing the Phase object does any @@ -162,7 +172,7 @@ class PhaseTransform : public Phase { protected: Arena* _arena; - Node_Array _nodes; // Map old node indices to new nodes. + Node_List _nodes; // Map old node indices to new nodes. Type_Array _types; // Map old node indices to Types. // ConNode caches: @@ -187,7 +197,13 @@ Arena* arena() { return _arena; } Type_Array& types() { return _types; } + void replace_types(Type_Array new_types) { + _types = new_types; + } // _nodes is used in varying ways by subclasses, which define local accessors + uint nodes_size() { + return _nodes.size(); + } public: // Get a previously recorded type for the node n. diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/prims/whitebox.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -45,6 +45,7 @@ #if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp" #include "gc_implementation/g1/concurrentMark.hpp" +#include "gc_implementation/g1/concurrentMarkThread.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #endif // INCLUDE_ALL_GCS @@ -323,8 +324,16 @@ WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); - ConcurrentMark* cm = g1->concurrent_mark(); - return cm->concurrent_marking_in_progress(); + return g1->concurrent_mark()->cmThread()->during_cycle(); +WB_END + +WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o)) + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + if (!g1h->concurrent_mark()->cmThread()->during_cycle()) { + g1h->collect(GCCause::_wb_conc_mark); + return true; + } + return false; WB_END WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) @@ -1031,6 +1040,7 @@ {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, + {CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle }, {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;", (void*)&WB_G1AuxiliaryMemoryUsage }, #endif // INCLUDE_ALL_GCS diff -r f796867c1bcb -r c3091ebd2811 src/share/vm/runtime/safepoint.cpp --- a/src/share/vm/runtime/safepoint.cpp Tue Dec 15 22:59:18 2015 -0800 +++ b/src/share/vm/runtime/safepoint.cpp Tue Jan 05 08:28:01 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -739,80 +739,12 @@ // ------------------------------------------------------------------------------------------------------ // Exception handlers -#ifndef PRODUCT - -#ifdef SPARC - -#ifdef _LP64 -#define PTR_PAD "" -#else -#define PTR_PAD " " -#endif - -static void print_ptrs(intptr_t oldptr, intptr_t newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR_FORMAT PTR_PAD " %s %c " PTR_FORMAT PTR_PAD " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_longs(jlong oldptr, jlong newptr, bool wasoop) { - bool is_oop = newptr ? (cast_to_oop(newptr))->is_oop() : false; - tty->print_cr(PTR64_FORMAT " %s %c " PTR64_FORMAT " %s %s", - oldptr, wasoop?"oop":" ", oldptr == newptr ? ' ' : '!', - newptr, is_oop?"oop":" ", (wasoop && !is_oop) ? "STALE" : ((wasoop==false&&is_oop==false&&oldptr !=newptr)?"STOMP":" ")); -} - -static void print_me(intptr_t *new_sp, intptr_t *old_sp, bool *was_oops) { -#ifdef _LP64 - tty->print_cr("--------+------address-----+------before-----------+-------after----------+"); - const int incr = 1; // Increment to skip a long, in units of intptr_t -#else - tty->print_cr("--------+--address-+------before-----------+-------after----------+"); - const int incr = 2; // Increment to skip a long, in units of intptr_t -#endif - tty->print_cr("---SP---|"); - for( int i=0; i<16; i++ ) { - tty->print("blob %c%d |"PTR_FORMAT" ","LO"[i>>3],i&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print_cr("--------|"); - for( int i1=0; i1print("argv pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->print(" pad|"PTR_FORMAT" ",new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); - tty->print_cr("--------|"); - tty->print(" G1 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G3 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G4 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print(" G5 |"PTR_FORMAT" ",new_sp); print_longs(*(jlong*)old_sp,*(jlong*)new_sp,was_oops[incr-1]); old_sp += incr; new_sp += incr; was_oops += incr; - tty->print_cr(" FSR |"PTR_FORMAT" "PTR64_FORMAT" "PTR64_FORMAT,new_sp,*(jlong*)old_sp,*(jlong*)new_sp); - old_sp += incr; new_sp += incr; was_oops += incr; - // Skip the floats - tty->print_cr("--Float-|"PTR_FORMAT,new_sp); - tty->print_cr("---FP---|"); - old_sp += incr*32; new_sp += incr*32; was_oops += incr*32; - for( int i2=0; i2<16; i2++ ) { - tty->print("call %c%d |"PTR_FORMAT" ","LI"[i2>>3],i2&7,new_sp); print_ptrs(*old_sp++,*new_sp++,*was_oops++); } - tty->cr(); -} -#endif // SPARC -#endif // PRODUCT - void SafepointSynchronize::handle_polling_page_exception(JavaThread *thread) { assert(thread->is_Java_thread(), "polling reference encountered by VM thread"); assert(thread->thread_state() == _thread_in_Java, "should come from Java code"); assert(SafepointSynchronize::is_synchronizing(), "polling encountered outside safepoint synchronization"); - // Uncomment this to get some serious before/after printing of the - // Sparc safepoint-blob frame structure. - /* - intptr_t* sp = thread->last_Java_sp(); - intptr_t stack_copy[150]; - for( int i=0; i<150; i++ ) stack_copy[i] = sp[i]; - bool was_oops[150]; - for( int i=0; i<150; i++ ) - was_oops[i] = stack_copy[i] ? ((oop)stack_copy[i])->is_oop() : false; - */ - if (ShowSafepointMsgs) { tty->print("handle_polling_page_exception: "); } @@ -824,7 +756,6 @@ ThreadSafepointState* state = thread->safepoint_state(); state->handle_polling_page_exception(); - // print_me(sp,stack_copy,was_oops); } diff -r f796867c1bcb -r c3091ebd2811 test/compiler/loopopts/UseCountedLoopSafepoints.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/UseCountedLoopSafepoints.java Tue Jan 05 08:28:01 2016 -0800 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 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 + * @bug 6869327 + * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop + * @library /testlibrary + * @run main UseCountedLoopSafepoints + */ + +import java.util.concurrent.atomic.AtomicLong; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class UseCountedLoopSafepoints { + private static final AtomicLong _num = new AtomicLong(0); + + // Uses the fact that an EnableBiasedLocking vmop will be started + // after 500ms, while we are still in the loop. If there is a + // safepoint in the counted loop, then we will reach safepoint + // very quickly. Otherwise SafepointTimeout will be hit. + public static void main (String args[]) throws Exception { + if (args.length == 1) { + final int loops = Integer.parseInt(args[0]); + for (int i = 0; i < loops; i++) { + _num.addAndGet(1); + } + } else { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", + "-XX:+UseBiasedLocking", + "-XX:BiasedLockingStartupDelay=500", + "-XX:+SafepointTimeout", + "-XX:SafepointTimeoutDelay=2000", + "-XX:+UseCountedLoopSafepoints", + "UseCountedLoopSafepoints", + "2000000000" + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Timeout detected"); + output.shouldHaveExitValue(0); + } + } +} diff -r f796867c1bcb -r c3091ebd2811 test/gc/whitebox/TestConcMarkCycleWB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/whitebox/TestConcMarkCycleWB.java Tue Jan 05 08:28:01 2016 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, 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 TestConMarkCycleWB + * @bug 8065579 + * @requires vm.gc=="null" | vm.gc=="G1" + * @library /testlibrary /testlibrary/whitebox + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.WhiteBox TestConcMarkCycleWB + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC TestConcMarkCycleWB + * @summary Verifies that ConcurrentMarking-related WB works properly + */ +import static com.oracle.java.testlibrary.Asserts.assertFalse; +import static com.oracle.java.testlibrary.Asserts.assertTrue; +import sun.hotspot.WhiteBox; + +public class TestConcMarkCycleWB { + + public static void main(String[] args) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + + wb.youngGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + + wb.fullGC(); + assertTrue(wb.g1StartConcMarkCycle()); + while (wb.g1InConcurrentMark()) { + Thread.sleep(5); + } + assertTrue(wb.g1StartConcMarkCycle()); + } +} diff -r f796867c1bcb -r c3091ebd2811 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Dec 15 22:59:18 2015 -0800 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Jan 05 08:28:01 2016 -0800 @@ -174,12 +174,16 @@ public native long incMetaspaceCapacityUntilGC(long increment); public native long metaspaceCapacityUntilGC(); - // force Young GC + // Force Young GC public native void youngGC(); - // force Full GC + // Force Full GC public native void fullGC(); + // Method tries to start concurrent mark cycle. + // It returns false if CM Thread is always in concurrent cycle. + public native boolean g1StartConcMarkCycle(); + // Tests on ReservedSpace/VirtualSpace classes public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); public native void runMemoryUnitTests();