# HG changeset patch # User never # Date 1213727562 25200 # Node ID ffcffaaeb97b494c694ec77029bab0583f855e04 # Parent 44a553b2809d6da2945f7a0fb4793a1c05326c6c# Parent 8b48a7bd2bf7e7f0a4cb1ccfd5fb327d044a1b12 Merge diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -283,6 +283,7 @@ template(cache_field_name, "cache") \ template(value_name, "value") \ template(frontCacheEnabled_name, "frontCacheEnabled") \ + template(stringCacheEnabled_name, "stringCacheEnabled") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/immutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/immutableSpace.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/immutableSpace.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -66,7 +66,7 @@ #endif -void ImmutableSpace::verify(bool allow_dirty) const { +void ImmutableSpace::verify(bool allow_dirty) { HeapWord* p = bottom(); HeapWord* t = end(); HeapWord* prev_p = NULL; diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/immutableSpace.hpp --- a/src/share/vm/gc_implementation/shared/immutableSpace.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/immutableSpace.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -59,5 +59,5 @@ // Debugging virtual void print() const PRODUCT_RETURN; virtual void print_short() const PRODUCT_RETURN; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); }; diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -599,12 +599,28 @@ // Mark the the holes in chunks below the top() as invalid. void MutableNUMASpace::set_top(HeapWord* value) { bool found_top = false; - for (int i = 0; i < lgrp_spaces()->length(); i++) { + for (int i = 0; i < lgrp_spaces()->length();) { LGRPSpace *ls = lgrp_spaces()->at(i); MutableSpace *s = ls->space(); HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom()); if (s->contains(value)) { + // Check if setting the chunk's top to a given value would create a hole less than + // a minimal object; assuming that's not the last chunk in which case we don't care. + if (i < lgrp_spaces()->length() - 1) { + size_t remainder = pointer_delta(s->end(), value); + const size_t minimal_object_size = oopDesc::header_size(); + if (remainder < minimal_object_size && remainder > 0) { + // Add a filler object of a minimal size, it will cross the chunk boundary. + SharedHeap::fill_region_with_object(MemRegion(value, minimal_object_size)); + value += minimal_object_size; + assert(!s->contains(value), "Should be in the next chunk"); + // Restart the loop from the same chunk, since the value has moved + // to the next one. + continue; + } + } + if (!os::numa_has_static_binding() && top < value && top < s->end()) { ls->add_invalid_region(MemRegion(top, value)); } @@ -620,6 +636,7 @@ s->set_top(s->end()); } } + i++; } MutableSpace::set_top(value); } @@ -700,12 +717,14 @@ MutableSpace *s = lgrp_spaces()->at(i)->space(); HeapWord *p = s->cas_allocate(size); if (p != NULL) { - size_t remainder = pointer_delta(s->end(), p); + size_t remainder = pointer_delta(s->end(), p + size); if (remainder < (size_t)oopDesc::header_size() && remainder > 0) { if (s->cas_deallocate(p, size)) { // We were the last to allocate and created a fragment less than // a minimal object. p = NULL; + } else { + guarantee(false, "Deallocation should always succeed"); } } } @@ -761,10 +780,12 @@ } } -void MutableNUMASpace::verify(bool allow_dirty) const { - for (int i = 0; i < lgrp_spaces()->length(); i++) { - lgrp_spaces()->at(i)->space()->verify(allow_dirty); - } +void MutableNUMASpace::verify(bool allow_dirty) { + // This can be called after setting an arbitary value to the space's top, + // so an object can cross the chunk boundary. We ensure the parsablity + // of the space and just walk the objects in linear fashion. + ensure_parsability(); + MutableSpace::verify(allow_dirty); } // Scan pages and gather stats about page placement and size. diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp --- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -192,7 +192,7 @@ // Debugging virtual void print_on(outputStream* st) const; virtual void print_short_on(outputStream* st) const; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); virtual void set_top(HeapWord* value); }; diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/mutableSpace.cpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -118,7 +118,7 @@ bottom(), top(), end()); } -void MutableSpace::verify(bool allow_dirty) const { +void MutableSpace::verify(bool allow_dirty) { HeapWord* p = bottom(); HeapWord* t = top(); HeapWord* prev_p = NULL; diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/gc_implementation/shared/mutableSpace.hpp --- a/src/share/vm/gc_implementation/shared/mutableSpace.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -98,5 +98,5 @@ virtual void print_on(outputStream* st) const; virtual void print_short() const; virtual void print_short_on(outputStream* st) const; - virtual void verify(bool allow_dirty) const; + virtual void verify(bool allow_dirty); }; diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/oops/methodDataOop.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -158,7 +158,6 @@ assert(ProfileTraps, "used only under +ProfileTraps"); uint old_flags = (_header._struct._flags & flag_mask); _header._struct._flags = (new_state << trap_shift) | old_flags; - assert(trap_state() == new_state, "sanity"); } u1 flags() { diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/opto/memnode.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -253,11 +253,17 @@ if (dom == NULL || dom->is_top() || sub == NULL || sub->is_top()) return false; // Conservative answer for dead code - // Check 'dom'. + // Check 'dom'. Skip Proj and CatchProj nodes. dom = dom->find_exact_control(dom); if (dom == NULL || dom->is_top()) return false; // Conservative answer for dead code + if (dom == sub) { + // For the case when, for example, 'sub' is Initialize and the original + // 'dom' is Proj node of the 'sub'. + return false; + } + if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) return true; @@ -271,6 +277,7 @@ sub->is_Region(), "expecting only these nodes"); // Get control edge of 'sub'. + Node* orig_sub = sub; sub = sub->find_exact_control(sub->in(0)); if (sub == NULL || sub->is_top()) return false; // Conservative answer for dead code @@ -296,14 +303,16 @@ for (uint next = 0; next < dom_list.size(); next++) { Node* n = dom_list.at(next); + if (n == orig_sub) + return false; // One of dom's inputs dominated by sub. if (!n->is_CFG() && n->pinned()) { // Check only own control edge for pinned non-control nodes. n = n->find_exact_control(n->in(0)); if (n == NULL || n->is_top()) return false; // Conservative answer for dead code assert(n->is_CFG(), "expecting control"); - } - if (n->is_Con() || n->is_Start() || n->is_Root()) { + dom_list.push(n); + } else if (n->is_Con() || n->is_Start() || n->is_Root()) { only_dominating_controls = true; } else if (n->is_CFG()) { if (n->dominates(sub, nlist)) diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/opto/node.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -1039,6 +1039,9 @@ //--------------------------dominates------------------------------------------ // Helper function for MemNode::all_controls_dominate(). // Check if 'this' control node dominates or equal to 'sub' control node. +// We already know that if any path back to Root or Start reaches 'this', +// then all paths so, so this is a simple search for one example, +// not an exhaustive search for a counterexample. bool Node::dominates(Node* sub, Node_List &nlist) { assert(this->is_CFG(), "expecting control"); assert(sub != NULL && sub->is_CFG(), "expecting control"); @@ -1047,110 +1050,115 @@ int iterations_without_region_limit = DominatorSearchLimit; Node* orig_sub = sub; + Node* dom = this; + bool met_dom = false; nlist.clear(); - bool this_dominates = false; - bool result = false; // Conservative answer - while (sub != NULL) { // walk 'sub' up the chain to 'this' - if (sub == this) { + // Walk 'sub' backward up the chain to 'dom', watching for regions. + // After seeing 'dom', continue up to Root or Start. + // If we hit a region (backward split point), it may be a loop head. + // Keep going through one of the region's inputs. If we reach the + // same region again, go through a different input. Eventually we + // will either exit through the loop head, or give up. + // (If we get confused, break out and return a conservative 'false'.) + while (sub != NULL) { + if (sub->is_top()) break; // Conservative answer for dead code. + if (sub == dom) { if (nlist.size() == 0) { // No Region nodes except loops were visited before and the EntryControl // path was taken for loops: it did not walk in a cycle. - result = true; - break; - } else if (this_dominates) { - result = false; // already met before: walk in a cycle - break; + return true; + } else if (met_dom) { + break; // already met before: walk in a cycle } else { // Region nodes were visited. Continue walk up to Start or Root // to make sure that it did not walk in a cycle. - this_dominates = true; // first time meet + met_dom = true; // first time meet iterations_without_region_limit = DominatorSearchLimit; // Reset } } if (sub->is_Start() || sub->is_Root()) { - result = this_dominates; - break; + // Success if we met 'dom' along a path to Start or Root. + // We assume there are no alternative paths that avoid 'dom'. + // (This assumption is up to the caller to ensure!) + return met_dom; } - Node* up = sub->find_exact_control(sub->in(0)); - if (up == NULL || up->is_top()) { - result = false; // Conservative answer for dead code - break; - } - if (sub == up && (sub->is_Loop() || sub->is_Region() && sub->req() != 3)) { - // Take first valid path on the way up to 'this'. + Node* up = sub->in(0); + // Normalize simple pass-through regions and projections: + up = sub->find_exact_control(up); + // If sub == up, we found a self-loop. Try to push past it. + if (sub == up && sub->is_Loop()) { + // Take loop entry path on the way up to 'dom'. up = sub->in(1); // in(LoopNode::EntryControl); + } else if (sub == up && sub->is_Region() && sub->req() != 3) { + // Always take in(1) path on the way up to 'dom' for clone regions + // (with only one input) or regions which merge > 2 paths + // (usually used to merge fast/slow paths). + up = sub->in(1); } else if (sub == up && sub->is_Region()) { - assert(sub->req() == 3, "sanity"); + // Try both paths for Regions with 2 input paths (it may be a loop head). + // It could give conservative 'false' answer without information + // which region's input is the entry path. iterations_without_region_limit = DominatorSearchLimit; // Reset - // Try both paths for such Regions. - // It is not accurate without regions dominating information. - // With such information the other path should be checked for - // the most dominating Region which was visited before. bool region_was_visited_before = false; - uint i = 1; - uint size = nlist.size(); - if (size == 0) { - // No such Region nodes were visited before. - // Take first valid path on the way up to 'this'. - } else { - // Was this Region node visited before? - intptr_t ni; - int j = size - 1; - for (; j >= 0; j--) { - ni = (intptr_t)nlist.at(j); - if ((Node*)(ni & ~1) == sub) { - if ((ni & 1) != 0) { - break; // Visited 2 paths. Give up. - } else { - // The Region node was visited before only once. - nlist.remove(j); - region_was_visited_before = true; - for (; i < sub->req(); i++) { - Node* in = sub->in(i); - if (in != NULL && !in->is_top() && in != sub) { - break; - } - } - i++; // Take other path. - break; - } + // Was this Region node visited before? + // If so, we have reached it because we accidentally took a + // loop-back edge from 'sub' back into the body of the loop, + // and worked our way up again to the loop header 'sub'. + // So, take the first unexplored path on the way up to 'dom'. + for (int j = nlist.size() - 1; j >= 0; j--) { + intptr_t ni = (intptr_t)nlist.at(j); + Node* visited = (Node*)(ni & ~1); + bool visited_twice_already = ((ni & 1) != 0); + if (visited == sub) { + if (visited_twice_already) { + // Visited 2 paths, but still stuck in loop body. Give up. + return false; } - } - if (j >= 0 && (ni & 1) != 0) { - result = false; // Visited 2 paths. Give up. - break; - } - // The Region node was not visited before. - } - for (; i < sub->req(); i++) { - Node* in = sub->in(i); - if (in != NULL && !in->is_top() && in != sub) { + // The Region node was visited before only once. + // (We will repush with the low bit set, below.) + nlist.remove(j); + // We will find a new edge and re-insert. + region_was_visited_before = true; break; } } - if (i < sub->req()) { - up = sub->in(i); - if (region_was_visited_before && sub != up) { - // Set 0 bit to indicate that both paths were taken. - nlist.push((Node*)((intptr_t)sub + 1)); - } else { - nlist.push(sub); + + // Find an incoming edge which has not been seen yet; walk through it. + assert(up == sub, ""); + uint skip = region_was_visited_before ? 1 : 0; + for (uint i = 1; i < sub->req(); i++) { + Node* in = sub->in(i); + if (in != NULL && !in->is_top() && in != sub) { + if (skip == 0) { + up = in; + break; + } + --skip; // skip this nontrivial input } } + + // Set 0 bit to indicate that both paths were taken. + nlist.push((Node*)((intptr_t)sub + (region_was_visited_before ? 1 : 0))); } - if (sub == up) { - result = false; // some kind of tight cycle - break; + + if (up == sub) { + break; // some kind of tight cycle + } + if (up == orig_sub && met_dom) { + // returned back after visiting 'dom' + break; // some kind of cycle } if (--iterations_without_region_limit < 0) { - result = false; // dead cycle - break; + break; // dead cycle } sub = up; } - return result; + + // Did not meet Root or Start node in pred. chain. + // Conservative answer for dead code. + return false; } //------------------------------remove_dead_region----------------------------- diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/runtime/globals.hpp Tue Jun 17 11:32:42 2008 -0700 @@ -2246,6 +2246,9 @@ product(bool, AggressiveOpts, false, \ "Enable aggressive optimizations - see arguments.cpp") \ \ + product(bool, UseStringCache, false, \ + "Enable String cache capabilities on String.java") \ + \ /* statistics */ \ develop(bool, UseVTune, false, \ "enable support for Intel's VTune profiler") \ diff -r 8b48a7bd2bf7 -r ffcffaaeb97b src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Jun 12 16:13:01 2008 -0700 +++ b/src/share/vm/runtime/thread.cpp Tue Jun 17 11:32:42 2008 -0700 @@ -2926,21 +2926,42 @@ } if (AggressiveOpts) { - // Forcibly initialize java/util/HashMap and mutate the private - // static final "frontCacheEnabled" field before we start creating instances + { + // Forcibly initialize java/util/HashMap and mutate the private + // static final "frontCacheEnabled" field before we start creating instances #ifdef ASSERT - klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); - assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet"); + klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + assert(tmp_k == NULL, "java/util/HashMap should not be loaded yet"); #endif - klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); - KlassHandle k = KlassHandle(THREAD, k_o); - guarantee(k.not_null(), "Must find java/util/HashMap"); - instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); - ik->initialize(CHECK_0); - fieldDescriptor fd; - // Possible we might not find this field; if so, don't break - if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_util_HashMap(), Handle(), Handle(), CHECK_0); + KlassHandle k = KlassHandle(THREAD, k_o); + guarantee(k.not_null(), "Must find java/util/HashMap"); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field; if so, don't break + if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } + } + + if (UseStringCache) { + // Forcibly initialize java/lang/String and mutate the private + // static final "stringCacheEnabled" field before we start creating instances +#ifdef ASSERT + klassOop tmp_k = SystemDictionary::find(vmSymbolHandles::java_lang_String(), Handle(), Handle(), CHECK_0); + assert(tmp_k == NULL, "java/lang/String should not be loaded yet"); +#endif + klassOop k_o = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_String(), Handle(), Handle(), CHECK_0); + KlassHandle k = KlassHandle(THREAD, k_o); + guarantee(k.not_null(), "Must find java/lang/String"); + instanceKlassHandle ik = instanceKlassHandle(THREAD, k()); + ik->initialize(CHECK_0); + fieldDescriptor fd; + // Possible we might not find this field; if so, don't break + if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { + k()->bool_field_put(fd.offset(), true); + } } }