From 6819e3739e487c79e502aecbe95546b44f04fe34 Mon Sep 17 00:00:00 2001 From: Jon Masamitsu Date: Tue, 3 May 2011 10:30:34 -0700 Subject: [PATCH 01/11] 7041789: 30% perf regression with c2/arm following 7017732 Implement a more accurate is_scavengable() Reviewed-by: stefank, jcoomes, ysr --- hotspot/src/share/vm/code/nmethod.cpp | 6 ++-- hotspot/src/share/vm/code/nmethod.hpp | 14 ++++----- .../gc_implementation/g1/g1CollectedHeap.cpp | 31 +++++++++++++++++++ .../gc_implementation/g1/g1CollectedHeap.hpp | 6 ++++ .../parallelScavenge/parallelScavengeHeap.cpp | 15 +++++++++ .../parallelScavenge/parallelScavengeHeap.hpp | 10 ++++++ .../parallelScavengeHeap.inline.hpp | 7 ++++- .../share/vm/gc_interface/collectedHeap.hpp | 13 +++++--- .../src/share/vm/memory/genCollectedHeap.cpp | 28 ++++++++++------- .../src/share/vm/memory/genCollectedHeap.hpp | 16 ++++++++-- hotspot/src/share/vm/memory/sharedHeap.cpp | 18 +++++++++-- .../src/share/vm/oops/instanceRefKlass.cpp | 4 +-- 12 files changed, 132 insertions(+), 36 deletions(-) diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 6ba2cde5b00..92ede9c4a21 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1810,7 +1810,7 @@ public: void maybe_print(oop* p) { if (_print_nm == NULL) return; if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root"); - tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")", + tty->print_cr(""PTR_FORMAT"[offset=%d] detected scavengable oop "PTR_FORMAT" (found at "PTR_FORMAT")", _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm), (intptr_t)(*p), (intptr_t)p); (*p)->print(); @@ -2311,7 +2311,7 @@ public: _nm->print_nmethod(true); _ok = false; } - tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", + tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); (*p)->print(); } @@ -2324,7 +2324,7 @@ void nmethod::verify_scavenge_root_oops() { DebugScavengeRoot debug_scavenge_root(this); oops_do(&debug_scavenge_root); if (!debug_scavenge_root.ok()) - fatal("found an unadvertised bad non-perm oop in the code cache"); + fatal("found an unadvertised bad scavengable oop in the code cache"); } assert(scavenge_root_not_marked(), ""); } diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 36f51ed1264..ae90de6d035 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -109,7 +109,7 @@ class xmlStream; class nmethod : public CodeBlob { friend class VMStructs; friend class NMethodSweeper; - friend class CodeCache; // non-perm oops + friend class CodeCache; // scavengable oops private: // Shared fields for all nmethod's methodOop _method; @@ -466,17 +466,17 @@ public: bool is_at_poll_return(address pc); bool is_at_poll_or_poll_return(address pc); - // Non-perm oop support + // Scavengable oop support bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; } protected: - enum { npl_on_list = 0x01, npl_marked = 0x10 }; - void set_on_scavenge_root_list() { _scavenge_root_state = npl_on_list; } + enum { sl_on_list = 0x01, sl_marked = 0x10 }; + void set_on_scavenge_root_list() { _scavenge_root_state = sl_on_list; } void clear_on_scavenge_root_list() { _scavenge_root_state = 0; } // assertion-checking and pruning logic uses the bits of _scavenge_root_state #ifndef PRODUCT - void set_scavenge_root_marked() { _scavenge_root_state |= npl_marked; } - void clear_scavenge_root_marked() { _scavenge_root_state &= ~npl_marked; } - bool scavenge_root_not_marked() { return (_scavenge_root_state &~ npl_on_list) == 0; } + void set_scavenge_root_marked() { _scavenge_root_state |= sl_marked; } + void clear_scavenge_root_marked() { _scavenge_root_state &= ~sl_marked; } + bool scavenge_root_not_marked() { return (_scavenge_root_state &~ sl_on_list) == 0; } // N.B. there is no positive marked query, and we only use the not_marked query for asserts. #endif //PRODUCT nmethod* scavenge_root_link() const { return _scavenge_root_link; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index af6c28fa7e1..479539ad390 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -428,6 +428,37 @@ void G1CollectedHeap::stop_conc_gc_threads() { _cmThread->stop(); } +#ifdef ASSERT +// A region is added to the collection set as it is retired +// so an address p can point to a region which will be in the +// collection set but has not yet been retired. This method +// therefore is only accurate during a GC pause after all +// regions have been retired. It is used for debugging +// to check if an nmethod has references to objects that can +// be move during a partial collection. Though it can be +// inaccurate, it is sufficient for G1 because the conservative +// implementation of is_scavengable() for G1 will indicate that +// all nmethods must be scanned during a partial collection. +bool G1CollectedHeap::is_in_partial_collection(const void* p) { + HeapRegion* hr = heap_region_containing(p); + return hr != NULL && hr->in_collection_set(); +} +#endif + +// Returns true if the reference points to an object that +// can move in an incremental collecction. +bool G1CollectedHeap::is_scavengable(const void* p) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1CollectorPolicy* g1p = g1h->g1_policy(); + HeapRegion* hr = heap_region_containing(p); + if (hr == NULL) { + // perm gen (or null) + return false; + } else { + return !hr->isHumongous(); + } +} + void G1CollectedHeap::check_ct_logs_at_safepoint() { DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index f2936639c0a..4577b27ed7d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -1254,6 +1254,12 @@ public: return hr != NULL && hr->is_young(); } +#ifdef ASSERT + virtual bool is_in_partial_collection(const void* p); +#endif + + virtual bool is_scavengable(const void* addr); + // We don't need barriers for initializing stores to objects // in the young gen: for the SATB pre-barrier, there is no // pre-value that needs to be remembered; for the remembered-set diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index 98a9c957330..d06b62d63d9 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -339,6 +339,21 @@ bool ParallelScavengeHeap::is_in_reserved(const void* p) const { return false; } +bool ParallelScavengeHeap::is_scavengable(const void* addr) { + return is_in_young((oop)addr); +} + +#ifdef ASSERT +// Don't implement this by using is_in_young(). This method is used +// in some cases to check that is_in_young() is correct. +bool ParallelScavengeHeap::is_in_partial_collection(const void *p) { + assert(is_in_reserved(p) || p == NULL, + "Does not work if address is non-null and outside of the heap"); + // The order of the generations is perm (low addr), old, young (high addr) + return p >= old_gen()->reserved().end(); +} +#endif + // There are two levels of allocation policy here. // // When an allocation request fails, the requesting thread must invoke a VM diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp index 44f6640d0ae..09e0124ed42 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp @@ -127,6 +127,12 @@ CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector // collection. virtual bool is_maximal_no_gc() const; + // Return true if the reference points to an object that + // can be moved in a partial collection. For currently implemented + // generational collectors that means during a collection of + // the young gen. + virtual bool is_scavengable(const void* addr); + // Does this heap support heap inspection? (+PrintClassHistogram) bool supports_heap_inspection() const { return true; } @@ -143,6 +149,10 @@ CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector return perm_gen()->reserved().contains(p); } +#ifdef ASSERT + virtual bool is_in_partial_collection(const void *p); +#endif + bool is_permanent(const void *p) const { // committed part return perm_gen()->is_in(p); } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp index 092a0392d3b..7244c72f16b 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp @@ -51,7 +51,12 @@ inline void ParallelScavengeHeap::invoke_full_gc(bool maximum_compaction) } inline bool ParallelScavengeHeap::is_in_young(oop p) { - return young_gen()->is_in_reserved(p); + // Assumes the the old gen address range is lower than that of the young gen. + const void* loc = (void*) p; + bool result = ((HeapWord*)p) >= young_gen()->reserved().start(); + assert(result == young_gen()->is_in_reserved(p), + err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, (void*)p)); + return result; } inline bool ParallelScavengeHeap::is_in_old_or_perm(oop p) { diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index c6070afb63c..f5082e4d289 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -269,6 +269,13 @@ class CollectedHeap : public CHeapObj { // space). If you need the more conservative answer use is_permanent(). virtual bool is_in_permanent(const void *p) const = 0; + +#ifdef ASSERT + // Returns true if "p" is in the part of the + // heap being collected. + virtual bool is_in_partial_collection(const void *p) = 0; +#endif + bool is_in_permanent_or_null(const void *p) const { return p == NULL || is_in_permanent(p); } @@ -284,11 +291,7 @@ class CollectedHeap : public CHeapObj { // An object is scavengable if its location may move during a scavenge. // (A scavenge is a GC which is not a full GC.) - // Currently, this just means it is not perm (and not null). - // This could change if we rethink what's in perm-gen. - bool is_scavengable(const void *p) const { - return !is_in_permanent_or_null(p); - } + virtual bool is_scavengable(const void *p) = 0; // Returns "TRUE" if "p" is a method oop in the // current heap, with high probability. This predicate diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 4326db2b3d0..940a46c10a2 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -711,15 +711,6 @@ void GenCollectedHeap::set_par_threads(int t) { _gen_process_strong_tasks->set_n_threads(t); } -class AssertIsPermClosure: public OopClosure { -public: - void do_oop(oop* p) { - assert((*p) == NULL || (*p)->is_perm(), "Referent should be perm."); - } - void do_oop(narrowOop* p) { ShouldNotReachHere(); } -}; -static AssertIsPermClosure assert_is_perm_closure; - void GenCollectedHeap:: gen_process_strong_roots(int level, bool younger_gens_as_roots, @@ -962,6 +953,13 @@ void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs, } } +bool GenCollectedHeap::is_in_young(oop p) { + bool result = ((HeapWord*)p) < _gens[_n_gens - 1]->reserved().start(); + assert(result == _gens[0]->is_in_reserved(p), + err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, (void*)p)); + return result; +} + // Returns "TRUE" iff "p" points into the allocated area of the heap. bool GenCollectedHeap::is_in(const void* p) const { #ifndef ASSERT @@ -984,10 +982,16 @@ bool GenCollectedHeap::is_in(const void* p) const { return false; } -// Returns "TRUE" iff "p" points into the allocated area of the heap. -bool GenCollectedHeap::is_in_youngest(void* p) { - return _gens[0]->is_in(p); +#ifdef ASSERT +// Don't implement this by using is_in_young(). This method is used +// in some cases to check that is_in_young() is correct. +bool GenCollectedHeap::is_in_partial_collection(const void* p) { + assert(is_in_reserved(p) || p == NULL, + "Does not work if address is non-null and outside of the heap"); + // The order of the generations is young (low addr), old, perm (high addr) + return p < _gens[_n_gens - 2]->reserved().end() && p != NULL; } +#endif void GenCollectedHeap::oop_iterate(OopClosure* cl) { for (int i = 0; i < _n_gens; i++) { diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.hpp b/hotspot/src/share/vm/memory/genCollectedHeap.hpp index 383936699d6..45f72bae138 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp @@ -216,8 +216,18 @@ public: } } - // Returns "TRUE" iff "p" points into the youngest generation. - bool is_in_youngest(void* p); + // Returns true if the reference is to an object in the reserved space + // for the young generation. + // Assumes the the young gen address range is less than that of the old gen. + bool is_in_young(oop p); + +#ifdef ASSERT + virtual bool is_in_partial_collection(const void* p); +#endif + + virtual bool is_scavengable(const void* addr) { + return is_in_young((oop)addr); + } // Iteration functions. void oop_iterate(OopClosure* cl); @@ -283,7 +293,7 @@ public: // "Check can_elide_initializing_store_barrier() for this collector"); // but unfortunately the flag UseSerialGC need not necessarily always // be set when DefNew+Tenured are being used. - return is_in_youngest((void*)new_obj); + return is_in_young(new_obj); } // Can a compiler elide a store barrier when it writes diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp index 24a2373acec..e386e726993 100644 --- a/hotspot/src/share/vm/memory/sharedHeap.cpp +++ b/hotspot/src/share/vm/memory/sharedHeap.cpp @@ -102,6 +102,17 @@ public: }; static AssertIsPermClosure assert_is_perm_closure; +#ifdef ASSERT +class AssertNonScavengableClosure: public OopClosure { +public: + virtual void do_oop(oop* p) { + assert(!Universe::heap()->is_in_partial_collection(*p), + "Referent should not be scavengable."); } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } +}; +static AssertNonScavengableClosure assert_is_non_scavengable_closure; +#endif + void SharedHeap::change_strong_roots_parity() { // Also set the new collection parity. assert(_strong_roots_parity >= 0 && _strong_roots_parity <= 2, @@ -196,9 +207,10 @@ void SharedHeap::process_strong_roots(bool activate_scope, CodeCache::scavenge_root_nmethods_do(code_roots); } } - // Verify if the code cache contents are in the perm gen - NOT_PRODUCT(CodeBlobToOopClosure assert_code_is_perm(&assert_is_perm_closure, /*do_marking=*/ false)); - NOT_PRODUCT(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_perm)); + // Verify that the code cache contents are not subject to + // movement by a scavenging collection. + DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, /*do_marking=*/ false)); + DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); } if (!collecting_perm_gen) { diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index 4518a9da17b..12c9d3385f2 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -397,7 +397,7 @@ void instanceRefKlass::oop_verify_on(oop obj, outputStream* st) { if (referent != NULL) { guarantee(referent->is_oop(), "referent field heap failed"); - if (gch != NULL && !gch->is_in_youngest(obj)) { + if (gch != NULL && !gch->is_in_young(obj)) { // We do a specific remembered set check here since the referent // field is not part of the oop mask and therefore skipped by the // regular verify code. @@ -415,7 +415,7 @@ void instanceRefKlass::oop_verify_on(oop obj, outputStream* st) { if (next != NULL) { guarantee(next->is_oop(), "next field verify failed"); guarantee(next->is_instanceRef(), "next field verify failed"); - if (gch != NULL && !gch->is_in_youngest(obj)) { + if (gch != NULL && !gch->is_in_young(obj)) { // We do a specific remembered set check here since the next field is // not part of the oop mask and therefore skipped by the regular // verify code. From fc79ef453f0dfaf2932375dabe3c9c1d631aed25 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Sun, 15 May 2011 23:57:15 -0400 Subject: [PATCH 02/11] 7035744: jprt no longer does open-only builds Added Open (OpenJDK) and Emb (Embedded) build flavours to JPRT. Added a few open builds and basic sanity tests to the normal JDK7 JPRT submission job. Reviewed-by: ohair, jcoomes, bobv, kvn --- hotspot/make/jprt.gmk | 20 +++++++++++++++++++- hotspot/make/jprt.properties | 29 +++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/hotspot/make/jprt.gmk b/hotspot/make/jprt.gmk index 8da610d7433..00ee6a22f3e 100644 --- a/hotspot/make/jprt.gmk +++ b/hotspot/make/jprt.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 2011, 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 @@ -33,6 +33,24 @@ else ZIPFLAGS=-q -y endif +jprt_build_productEmb: + $(MAKE) JAVASE_EMBEDDED=true jprt_build_product + +jprt_build_debugEmb: + $(MAKE) JAVASE_EMBEDDED=true jprt_build_debug + +jprt_build_fastdebugEmb: + $(MAKE) JAVASE_EMBEDDED=true jprt_build_fastdebug + +jprt_build_productOpen: + $(MAKE) OPENJDK=true jprt_build_product + +jprt_build_debugOpen: + $(MAKE) OPENJDK=true jprt_build_debug + +jprt_build_fastdebugOpen: + $(MAKE) OPENJDK=true jprt_build_fastdebug + jprt_build_product: all_product copy_product_jdk export_product_jdk ( $(CD) $(JDK_IMAGE_DIR) && \ $(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . ) diff --git a/hotspot/make/jprt.properties b/hotspot/make/jprt.properties index 392db8f6bc6..f4cd5eca836 100644 --- a/hotspot/make/jprt.properties +++ b/hotspot/make/jprt.properties @@ -202,16 +202,21 @@ jprt.build.targets.standard= \ ${jprt.my.windows.i586}-{product|fastdebug|debug}, \ ${jprt.my.windows.x64}-{product|fastdebug|debug} +jprt.build.targets.open= \ + ${jprt.my.solaris.i586}-{productOpen}, \ + ${jprt.my.solaris.x64}-{debugOpen}, \ + ${jprt.my.linux.x64}-{productOpen} + jprt.build.targets.embedded= \ - ${jprt.my.linux.i586}-{product|fastdebug|debug}, \ - ${jprt.my.linux.ppc}-{product|fastdebug}, \ - ${jprt.my.linux.ppcv2}-{product|fastdebug}, \ - ${jprt.my.linux.ppcsflt}-{product|fastdebug}, \ - ${jprt.my.linux.armvfp}-{product|fastdebug}, \ - ${jprt.my.linux.armsflt}-{product|fastdebug} + ${jprt.my.linux.i586}-{productEmb|fastdebugEmb|debugEmb}, \ + ${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \ + ${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb} jprt.build.targets.all=${jprt.build.targets.standard}, \ - ${jprt.build.targets.embedded} + ${jprt.build.targets.embedded}, ${jprt.build.targets.open} jprt.build.targets.jdk7=${jprt.build.targets.all} jprt.build.targets.jdk7temp=${jprt.build.targets.all} @@ -453,6 +458,12 @@ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-product-c2-jbb_G1, \ ${jprt.my.windows.x64}-product-c2-jbb_ParOldGC +# Some basic "smoke" tests for OpenJDK builds +jprt.test.targets.open = \ + ${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98_tiered, \ + ${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98_tiered, \ + ${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98_tiered + # Testing for actual embedded builds is different to standard jprt.my.linux.i586.test.targets.embedded = \ linux_i586_2.6-product-c1-scimark @@ -461,6 +472,7 @@ jprt.my.linux.i586.test.targets.embedded = \ # Note: no PPC or ARM tests at this stage jprt.test.targets.standard = \ + ${jprt.my.linux.i586.test.targets.embedded}, \ ${jprt.my.solaris.sparc.test.targets}, \ ${jprt.my.solaris.sparcv9.test.targets}, \ ${jprt.my.solaris.i586.test.targets}, \ @@ -468,7 +480,8 @@ jprt.test.targets.standard = \ ${jprt.my.linux.i586.test.targets}, \ ${jprt.my.linux.x64.test.targets}, \ ${jprt.my.windows.i586.test.targets}, \ - ${jprt.my.windows.x64.test.targets} + ${jprt.my.windows.x64.test.targets}, \ + ${jprt.test.targets.open} jprt.test.targets.embedded= \ ${jprt.my.linux.i586.test.targets.embedded}, \ From 0e10a5ad613c647f33fef935c5bccc08ef0839c8 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 16 May 2011 14:21:16 -0700 Subject: [PATCH 03/11] 7044725: -XX:-UnrollLimitCheck -Xcomp : Exception: String index out of range: 29488 Fix problems in new RCE code. Reviewed-by: never --- hotspot/src/share/vm/opto/loopTransform.cpp | 195 +++++++++----------- hotspot/src/share/vm/opto/loopnode.hpp | 2 + 2 files changed, 93 insertions(+), 104 deletions(-) diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index f720b79ce63..840a72758a2 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -1453,6 +1453,23 @@ bool IdealLoopTree::dominates_backedge(Node* ctrl) { return _phase->dom_lca_internal(ctrl, backedge) == ctrl; } +//------------------------------adjust_limit----------------------------------- +// Helper function for add_constraint(). +Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl) { + // Compute "I :: (limit-offset)/scale" + Node *con = new (C, 3) SubINode(rc_limit, offset); + register_new_node(con, pre_ctrl); + Node *X = new (C, 3) DivINode(0, con, scale); + register_new_node(X, pre_ctrl); + + // Adjust loop limit + loop_limit = (stride_con > 0) + ? (Node*)(new (C, 3) MinINode(loop_limit, X)) + : (Node*)(new (C, 3) MaxINode(loop_limit, X)); + register_new_node(loop_limit, pre_ctrl); + return loop_limit; +} + //------------------------------add_constraint--------------------------------- // Constrain the main loop iterations so the conditions: // low_limit <= scale_con * I + offset < upper_limit @@ -1469,7 +1486,11 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset // pre-loop must check for underflow and the post-loop for overflow. // Negative stride*scale reverses this; pre-loop checks for overflow and // post-loop for underflow. - if (stride_con*scale_con > 0) { + + Node *scale = _igvn.intcon(scale_con); + set_ctrl(scale, C->root()); + + if ((stride_con^scale_con) >= 0) { // Use XOR to avoid overflow // The overflow limit: scale*I+offset < upper_limit // For main-loop compute // ( if (scale > 0) /* and stride > 0 */ @@ -1478,23 +1499,10 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset // I > (upper_limit-offset)/scale // ) // - // (upper_limit-offset) may overflow when offset < 0. + // (upper_limit-offset) may overflow or underflow. // But it is fine since main loop will either have // less iterations or will be skipped in such case. - Node *con = new (C, 3) SubINode(upper_limit, offset); - register_new_node(con, pre_ctrl); - Node *scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - Node *X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust main-loop last iteration - Node *loop_limit = *main_limit; - loop_limit = (stride_con > 0) // scale > 0 - ? (Node*)(new (C, 3) MinINode(loop_limit, X)) - : (Node*)(new (C, 3) MaxINode(loop_limit, X)); - register_new_node(loop_limit, pre_ctrl); - *main_limit = loop_limit; + *main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl); // The underflow limit: low_limit <= scale*I+offset. // For pre-loop compute @@ -1509,76 +1517,33 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset if (low_limit->get_int() == -max_jint) { if (!RangeLimitCheck) return; // We need this guard when scale*pre_limit+offset >= limit - // due to underflow so we need execute pre-loop until - // scale*I+offset >= min_int. But (low_limit-offset) will - // underflow when offset > 0 and X will be > original_limit. - // To avoid it we replace offset = offset > 0 ? 0 : offset - // and add min(pre_limit, original_limit). + // due to underflow. So we need execute pre-loop until + // scale*I+offset >= min_int. But (min_int-offset) will + // underflow when offset > 0 and X will be > original_limit + // when stride > 0. To avoid it we replace positive offset with 0. + // + // Also (min_int+1 == -max_int) is used instead of min_int here + // to avoid problem with scale == -1 (min_int/(-1) == min_int). Node* shift = _igvn.intcon(31); set_ctrl(shift, C->root()); - Node *neg_off = new (C, 3) RShiftINode(offset, shift); - register_new_node(neg_off, pre_ctrl); - offset = new (C, 3) AndINode(offset, neg_off); + Node* sign = new (C, 3) RShiftINode(offset, shift); + register_new_node(sign, pre_ctrl); + offset = new (C, 3) AndINode(offset, sign); register_new_node(offset, pre_ctrl); } else { assert(low_limit->get_int() == 0, "wrong low limit for range check"); // The only problem we have here when offset == min_int - // since (0-min_int) == min_int. It may be fine for scale > 0 - // but for scale < 0 X will be < original_limit. + // since (0-min_int) == min_int. It may be fine for stride > 0 + // but for stride < 0 X will be < original_limit. To avoid it + // max(pre_limit, original_limit) is used in do_range_check(). } - con = new (C, 3) SubINode(low_limit, offset); - register_new_node(con, pre_ctrl); - scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust pre-loop last iteration - loop_limit = *pre_limit; - loop_limit = (stride_con > 0) // scale > 0 - ? (Node*)(new (C, 3) MaxINode(loop_limit, X)) - : (Node*)(new (C, 3) MinINode(loop_limit, X)); - register_new_node( loop_limit, pre_ctrl ); - *pre_limit = loop_limit; + // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); + *pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl); } else { // stride_con*scale_con < 0 // For negative stride*scale pre-loop checks for overflow and // post-loop for underflow. // - // The underflow limit: low_limit <= scale*I+offset. - // For main-loop compute - // scale*I+offset+1 > low_limit - // ( if (scale < 0) /* and stride > 0 */ - // I < (low_limit-(offset+1))/scale - // else /* scale < 0 and stride < 0 */ - // I > (low_limit-(offset+1))/scale - // ) - - if (low_limit->get_int() == -max_jint) { - if (!RangeLimitCheck) return; - } else { - assert(low_limit->get_int() == 0, "wrong low limit for range check"); - } - - Node *one = _igvn.intcon(1); - set_ctrl(one, C->root()); - Node *plus_one = new (C, 3) AddINode(offset, one); - register_new_node( plus_one, pre_ctrl ); - Node *con = new (C, 3) SubINode(low_limit, plus_one); - register_new_node(con, pre_ctrl); - Node *scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - Node *X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); - - // Adjust main-loop last iteration - Node *loop_limit = *main_limit; - loop_limit = (stride_con > 0) // scale < 0 - ? (Node*)(new (C, 3) MinINode(loop_limit, X)) - : (Node*)(new (C, 3) MaxINode(loop_limit, X)); - register_new_node(loop_limit, pre_ctrl); - *main_limit = loop_limit; - // The overflow limit: scale*I+offset < upper_limit // For pre-loop compute // NOT(scale*I+offset < upper_limit) @@ -1586,26 +1551,55 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset // scale*I+offset+1 > upper_limit // ( if (scale < 0) /* and stride > 0 */ // I < (upper_limit-(offset+1))/scale - // else /* scale < 0 and stride < 0 */ + // else /* scale > 0 and stride < 0 */ // I > (upper_limit-(offset+1))/scale // ) - plus_one = new (C, 3) AddINode(offset, one); + // + // (upper_limit-offset-1) may underflow or overflow. + // To avoid it min(pre_limit, original_limit) is used + // in do_range_check() for stride > 0 and max() for < 0. + Node *one = _igvn.intcon(1); + set_ctrl(one, C->root()); + + Node *plus_one = new (C, 3) AddINode(offset, one); register_new_node( plus_one, pre_ctrl ); - con = new (C, 3) SubINode(upper_limit, plus_one); - register_new_node(con, pre_ctrl); - scale = _igvn.intcon(scale_con); - set_ctrl(scale, C->root()); - X = new (C, 3) DivINode(0, con, scale); - register_new_node(X, pre_ctrl); + // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond); + *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl); - // Adjust pre-loop last iteration - loop_limit = *pre_limit; - loop_limit = (stride_con > 0) // scale < 0 - ? (Node*)(new (C, 3) MaxINode(loop_limit, X)) - : (Node*)(new (C, 3) MinINode(loop_limit, X)); - register_new_node( loop_limit, pre_ctrl ); - *pre_limit = loop_limit; + if (low_limit->get_int() == -max_jint) { + if (!RangeLimitCheck) return; + // We need this guard when scale*main_limit+offset >= limit + // due to underflow. So we need execute main-loop while + // scale*I+offset+1 > min_int. But (min_int-offset-1) will + // underflow when (offset+1) > 0 and X will be < main_limit + // when scale < 0 (and stride > 0). To avoid it we replace + // positive (offset+1) with 0. + // + // Also (min_int+1 == -max_int) is used instead of min_int here + // to avoid problem with scale == -1 (min_int/(-1) == min_int). + Node* shift = _igvn.intcon(31); + set_ctrl(shift, C->root()); + Node* sign = new (C, 3) RShiftINode(plus_one, shift); + register_new_node(sign, pre_ctrl); + plus_one = new (C, 3) AndINode(plus_one, sign); + register_new_node(plus_one, pre_ctrl); + } else { + assert(low_limit->get_int() == 0, "wrong low limit for range check"); + // The only problem we have here when offset == max_int + // since (max_int+1) == min_int and (0-min_int) == min_int. + // But it is fine since main loop will either have + // less iterations or will be skipped in such case. + } + // The underflow limit: low_limit <= scale*I+offset. + // For main-loop compute + // scale*I+offset+1 > low_limit + // ( if (scale < 0) /* and stride > 0 */ + // I < (low_limit-(offset+1))/scale + // else /* scale > 0 and stride < 0 */ + // I > (low_limit-(offset+1))/scale + // ) + *main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl); } } @@ -1869,13 +1863,8 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // The underflow and overflow limits: 0 <= scale*I+offset < limit add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit ); if (!conditional_rc) { - conditional_rc = !loop->dominates_backedge(iff); - // It is also needed if offset->_lo == min_int since - // (0-min_int) == min_int. It may be fine for stride > 0 - // but for stride < 0 pre_limit will be < original_limit. - const TypeInt* offset_t = _igvn.type(offset)->is_int(); - conditional_rc |= RangeLimitCheck && (offset_t->_lo == min_jint) && - (scale_con<0) && (stride_con<0); + // (0-offset)/scale could be outside of loop iterations range. + conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; } } else { #ifndef PRODUCT @@ -1905,16 +1894,14 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { // Fall into LT case case BoolTest::lt: // The underflow and overflow limits: MIN_INT <= scale*I+offset < limit + // Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here + // to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT. add_constraint( stride_con, scale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit ); if (!conditional_rc) { - conditional_rc = !loop->dominates_backedge(iff); - // It is also needed if scale*pre_limit+offset >= limit - // due to underflow so we need execute pre-loop until - // scale*I+offset >= min_int. But (low_limit-offset) will - // underflow when offset > 0 and X will be > original_limit. - const TypeInt* offset_t = _igvn.type(offset)->is_int(); - conditional_rc |= RangeLimitCheck && (offset_t->_hi > 0) && - (scale_con>0) && (stride_con>0); + // ((MIN_INT+1)-offset)/scale could be outside of loop iterations range. + // Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could + // still be outside of loop range. + conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck; } break; default: diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index 5a2f3f7738c..793b4ca2af6 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -932,6 +932,8 @@ public: // the pre-loop or the post-loop until the condition holds true in the main // loop. Scale_con, offset and limit are all loop invariant. void add_constraint( int stride_con, int scale_con, Node *offset, Node *low_limit, Node *upper_limit, Node *pre_ctrl, Node **pre_limit, Node **main_limit ); + // Helper function for add_constraint(). + Node* adjust_limit( int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl ); // Partially peel loop up through last_peel node. bool partial_peel( IdealLoopTree *loop, Node_List &old_new ); From a16e057c0a05fa1fc48469b27fa54f227cf24dfc Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 16 May 2011 22:16:44 -0700 Subject: [PATCH 04/11] 6996747: SIGSEGV in nmethod::cleanup_inline_caches / CompiledIC::verify Reviewed-by: kvn, iveresov --- hotspot/src/share/vm/runtime/globals.hpp | 6 ++ hotspot/src/share/vm/runtime/sweeper.cpp | 122 +++++++++++++++++++++++ hotspot/src/share/vm/runtime/sweeper.hpp | 7 ++ hotspot/src/share/vm/runtime/thread.cpp | 10 ++ hotspot/src/share/vm/runtime/thread.hpp | 17 +++- 5 files changed, 160 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index f0a50abb7f8..a3c1939e2c4 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2909,6 +2909,12 @@ class CommandLineFlags { product(intx, NmethodSweepCheckInterval, 5, \ "Compilers wake up every n seconds to possibly sweep nmethods") \ \ + notproduct(bool, LogSweeper, false, \ + "Keep a ring buffer of sweeper activity") \ + \ + notproduct(intx, SweeperLogEntries, 1024, \ + "Number of records in the ring buffer of sweeper activity") \ + \ notproduct(intx, MemProfilingInterval, 500, \ "Time between each invocation of the MemProfiler") \ \ diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp index 0d980526a38..f9ad79ef676 100644 --- a/hotspot/src/share/vm/runtime/sweeper.cpp +++ b/hotspot/src/share/vm/runtime/sweeper.cpp @@ -37,6 +37,94 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef ASSERT + +#define SWEEP(nm) record_sweep(nm, __LINE__) +// Sweeper logging code +class SweeperRecord { + public: + int traversal; + int invocation; + int compile_id; + long traversal_mark; + int state; + const char* kind; + address vep; + address uep; + int line; + + void print() { + tty->print_cr("traversal = %d invocation = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " + PTR_FORMAT " state = %d traversal_mark %d line = %d", + traversal, + invocation, + compile_id, + kind == NULL ? "" : kind, + uep, + vep, + state, + traversal_mark, + line); + } +}; + +static int _sweep_index = 0; +static SweeperRecord* _records = NULL; + +void NMethodSweeper::report_events(int id, address entry) { + if (_records != NULL) { + for (int i = _sweep_index; i < SweeperLogEntries; i++) { + if (_records[i].uep == entry || + _records[i].vep == entry || + _records[i].compile_id == id) { + _records[i].print(); + } + } + for (int i = 0; i < _sweep_index; i++) { + if (_records[i].uep == entry || + _records[i].vep == entry || + _records[i].compile_id == id) { + _records[i].print(); + } + } + } +} + +void NMethodSweeper::report_events() { + if (_records != NULL) { + for (int i = _sweep_index; i < SweeperLogEntries; i++) { + // skip empty records + if (_records[i].vep == NULL) continue; + _records[i].print(); + } + for (int i = 0; i < _sweep_index; i++) { + // skip empty records + if (_records[i].vep == NULL) continue; + _records[i].print(); + } + } +} + +void NMethodSweeper::record_sweep(nmethod* nm, int line) { + if (_records != NULL) { + _records[_sweep_index].traversal = _traversals; + _records[_sweep_index].traversal_mark = nm->_stack_traversal_mark; + _records[_sweep_index].invocation = _invocations; + _records[_sweep_index].compile_id = nm->compile_id(); + _records[_sweep_index].kind = nm->compile_kind(); + _records[_sweep_index].state = nm->_state; + _records[_sweep_index].vep = nm->verified_entry_point(); + _records[_sweep_index].uep = nm->entry_point(); + _records[_sweep_index].line = line; + + _sweep_index = (_sweep_index + 1) % SweeperLogEntries; + } +} +#else +#define SWEEP(nm) +#endif + + long NMethodSweeper::_traversals = 0; // No. of stack traversals performed nmethod* NMethodSweeper::_current = NULL; // Current nmethod int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache @@ -137,6 +225,13 @@ void NMethodSweeper::possibly_sweep() { if (old != 0) { return; } +#ifdef ASSERT + if (LogSweeper && _records == NULL) { + // Create the ring buffer for the logging code + _records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries); + memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries); + } +#endif if (_invocations > 0) { sweep_code_cache(); _invocations--; @@ -213,10 +308,29 @@ void NMethodSweeper::sweep_code_cache() { } } +class NMethodMarker: public StackObj { + private: + CompilerThread* _thread; + public: + NMethodMarker(nmethod* nm) { + _thread = CompilerThread::current(); + _thread->set_scanned_nmethod(nm); + } + ~NMethodMarker() { + _thread->set_scanned_nmethod(NULL); + } +}; + void NMethodSweeper::process_nmethod(nmethod *nm) { assert(!CodeCache_lock->owned_by_self(), "just checking"); + // Make sure this nmethod doesn't get unloaded during the scan, + // since the locks acquired below might safepoint. + NMethodMarker nmm(nm); + + SWEEP(nm); + // Skip methods that are currently referenced by the VM if (nm->is_locked_by_vm()) { // But still remember to clean-up inline caches for alive nmethods @@ -224,8 +338,10 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); + SWEEP(nm); } else { _locked_seen++; + SWEEP(nm); } return; } @@ -247,6 +363,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { } nm->mark_for_reclamation(); _rescan = true; + SWEEP(nm); } } else if (nm->is_not_entrant()) { // If there is no current activations of this method on the @@ -257,6 +374,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { } nm->make_zombie(); _rescan = true; + SWEEP(nm); } else { // Still alive, clean up its inline caches MutexLocker cl(CompiledIC_lock); @@ -265,6 +383,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { // request a rescan. If this method stays on the stack for a // long time we don't want to keep rescanning the code cache. _not_entrant_seen_on_stack++; + SWEEP(nm); } } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie @@ -273,10 +392,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { if (nm->is_osr_method()) { // No inline caches will ever point to osr methods, so we can just remove it MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + SWEEP(nm); nm->flush(); } else { nm->make_zombie(); _rescan = true; + SWEEP(nm); } } else { assert(nm->is_alive(), "should be alive"); @@ -293,6 +414,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) { // Clean-up all inline caches that points to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); + SWEEP(nm); } } diff --git a/hotspot/src/share/vm/runtime/sweeper.hpp b/hotspot/src/share/vm/runtime/sweeper.hpp index 8758497d76a..f9ccb535333 100644 --- a/hotspot/src/share/vm/runtime/sweeper.hpp +++ b/hotspot/src/share/vm/runtime/sweeper.hpp @@ -57,6 +57,13 @@ class NMethodSweeper : public AllStatic { public: static long traversal_count() { return _traversals; } +#ifdef ASSERT + // Keep track of sweeper activity in the ring buffer + static void record_sweep(nmethod* nm, int line); + static void report_events(int id, address entry); + static void report_events(); +#endif + static void scan_stacks(); // Invoked at the end of each safepoint static void sweep_code_cache(); // Concurrent part of sweep job static void possibly_sweep(); // Compiler threads call this to sweep diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 02f4e7f490a..51c45746dc5 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -2942,12 +2942,22 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters) _queue = queue; _counters = counters; _buffer_blob = NULL; + _scanned_nmethod = NULL; #ifndef PRODUCT _ideal_graph_printer = NULL; #endif } +void CompilerThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { + JavaThread::oops_do(f, cf); + if (_scanned_nmethod != NULL && cf != NULL) { + // Safepoints can occur when the sweeper is scanning an nmethod so + // process it here to make sure it isn't unloaded in the middle of + // a scan. + cf->do_code_blob(_scanned_nmethod); + } +} // ======= Threads ======== diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index eefe93bc7d2..8387ab0f0e6 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -439,7 +439,7 @@ class Thread: public ThreadShadow { // GC support // Apply "f->do_oop" to all root oops in "this". // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames - void oops_do(OopClosure* f, CodeBlobClosure* cf); + virtual void oops_do(OopClosure* f, CodeBlobClosure* cf); // Handles the parallel case for the method below. private: @@ -1381,7 +1381,7 @@ public: void trace_frames() PRODUCT_RETURN; // Print an annotated view of the stack frames - void print_frame_layout(int depth = 0, bool validate_only = false) PRODUCT_RETURN; + void print_frame_layout(int depth = 0, bool validate_only = false) NOT_DEBUG_RETURN; void validate_frame_layout() { print_frame_layout(0, true); } @@ -1698,6 +1698,8 @@ class CompilerThread : public JavaThread { CompileQueue* _queue; BufferBlob* _buffer_blob; + nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper + public: static CompilerThread* current(); @@ -1726,6 +1728,11 @@ class CompilerThread : public JavaThread { _log = log; } + // GC support + // Apply "f->do_oop" to all root oops in "this". + // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames + void oops_do(OopClosure* f, CodeBlobClosure* cf); + #ifndef PRODUCT private: IdealGraphPrinter *_ideal_graph_printer; @@ -1737,6 +1744,12 @@ public: // Get/set the thread's current task CompileTask* task() { return _task; } void set_task(CompileTask* task) { _task = task; } + + // Track the nmethod currently being scanned by the sweeper + void set_scanned_nmethod(nmethod* nm) { + assert(_scanned_nmethod == NULL || nm == NULL, "should reset to NULL before writing a new value"); + _scanned_nmethod = nm; + } }; inline CompilerThread* CompilerThread::current() { From 95548aa2915010d8656a70c6320632a70730e521 Mon Sep 17 00:00:00 2001 From: John Cuthbertson Date: Tue, 17 May 2011 00:56:01 -0700 Subject: [PATCH 05/11] 7041440: G1: assert(obj->is_oop_or_null(true )) failed: Error # During an evacuation pause clear the region fields of any concurrent marking task whose local finger points into the collection set as the values in the region fields will become stale. Clearing these fields causes the concurrent mark task to claim a new region when marking restarts after the pause. Reviewed-by: tonyp, iveresov --- .../gc_implementation/g1/concurrentMark.cpp | 22 +++++++++++++++++++ .../gc_implementation/g1/concurrentMark.hpp | 17 +++++++++++--- .../gc_implementation/g1/g1CollectedHeap.cpp | 13 ++++++++++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 14c855c1b33..95a82dabc75 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -3054,6 +3054,28 @@ void ConcurrentMark::registerCSetRegion(HeapRegion* hr) { _should_gray_objects = true; } +// Resets the region fields of active CMTasks whose values point +// into the collection set. +void ConcurrentMark::reset_active_task_region_fields_in_cset() { + assert(SafepointSynchronize::is_at_safepoint(), "should be in STW"); + assert(parallel_marking_threads() <= _max_task_num, "sanity"); + + for (int i = 0; i < (int)parallel_marking_threads(); i += 1) { + CMTask* task = _tasks[i]; + HeapWord* task_finger = task->finger(); + if (task_finger != NULL) { + assert(_g1h->is_in_g1_reserved(task_finger), "not in heap"); + HeapRegion* finger_region = _g1h->heap_region_containing(task_finger); + if (finger_region->in_collection_set()) { + // The task's current region is in the collection set. + // This region will be evacuated in the current GC and + // the region fields in the task will be stale. + task->giveup_current_region(); + } + } + } +} + // abandon current marking iteration due to a Full GC void ConcurrentMark::abort() { // Clear all marks to force marking thread to do nothing diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 99cf02faa7e..4c75b7ce628 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -809,10 +809,19 @@ public: // It indicates that a new collection set is being chosen. void newCSet(); + // It registers a collection set heap region with CM. This is used // to determine whether any heap regions are located above the finger. void registerCSetRegion(HeapRegion* hr); + // Resets the region fields of any active CMTask whose region fields + // are in the collection set (i.e. the region currently claimed by + // the CMTask will be evacuated and may be used, subsequently, as + // an alloc region). When this happens the region fields in the CMTask + // are stale and, hence, should be cleared causing the worker thread + // to claim a new region. + void reset_active_task_region_fields_in_cset(); + // Registers the maximum region-end associated with a set of // regions with CM. Again this is used to determine whether any // heap regions are located above the finger. @@ -1039,9 +1048,6 @@ private: void setup_for_region(HeapRegion* hr); // it brings up-to-date the limit of the region void update_region_limit(); - // it resets the local fields after a task has finished scanning a - // region - void giveup_current_region(); // called when either the words scanned or the refs visited limit // has been reached @@ -1094,6 +1100,11 @@ public: // exit the termination protocol after it's entered it. virtual bool should_exit_termination(); + // Resets the local region fields after a task has finished scanning a + // region; or when they have become stale as a result of the region + // being evacuated. + void giveup_current_region(); + HeapWord* finger() { return _finger; } bool has_aborted() { return _has_aborted; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 479539ad390..a3b60ef8487 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3323,8 +3323,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { // progress, this will be zero. _cm->set_oops_do_bound(); - if (mark_in_progress()) + if (mark_in_progress()) { concurrent_mark()->newCSet(); + } #if YOUNG_LIST_VERBOSE gclog_or_tty->print_cr("\nBefore choosing collection set.\nYoung_list:"); @@ -3334,6 +3335,16 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->choose_collection_set(target_pause_time_ms); + // We have chosen the complete collection set. If marking is + // active then, we clear the region fields of any of the + // concurrent marking tasks whose region fields point into + // the collection set as these values will become stale. This + // will cause the owning marking threads to claim a new region + // when marking restarts. + if (mark_in_progress()) { + concurrent_mark()->reset_active_task_region_fields_in_cset(); + } + // Nothing to do if we were unable to choose a collection set. #if G1_REM_SET_LOGGING gclog_or_tty->print_cr("\nAfter pause, heap:"); From 4b893d695b0c63048583e298b10b96fdf4ab6634 Mon Sep 17 00:00:00 2001 From: Bertrand Delsart Date: Tue, 17 May 2011 16:50:27 +0200 Subject: [PATCH 06/11] 7045515: ARM assembly code for JSR 292 ricochet frames ARM ricochet port and minor fixes in shared debug code Reviewed-by: jrose, vladidan --- hotspot/src/share/vm/prims/methodHandleWalk.cpp | 3 ++- hotspot/src/share/vm/prims/methodHandles.hpp | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.cpp b/hotspot/src/share/vm/prims/methodHandleWalk.cpp index cc8f8b539df..d087f341561 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp @@ -423,6 +423,7 @@ MethodHandleWalker::walk(TRAPS) { arglist[1+i] = arg; if (!retain_original_args) change_argument(arg_type, slot, T_VOID, ArgToken(tt_void)); + i++; } arglist[1+argc] = ArgToken(); // sentinel oop invoker = java_lang_invoke_MethodTypeForm::vmlayout( @@ -487,7 +488,7 @@ MethodHandleWalker::walk(TRAPS) { arglist[1] = length_arg; // length to check arglist[2] = ArgToken(); // sentinel make_invoke(NULL, vmIntrinsics::_checkSpreadArgument, - Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_(empty)); + Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty)); // Spread out the array elements. Bytecodes::Code aload_op = Bytecodes::_nop; diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp index 66de7efe0f4..cefb8ad3f73 100644 --- a/hotspot/src/share/vm/prims/methodHandles.hpp +++ b/hotspot/src/share/vm/prims/methodHandles.hpp @@ -721,12 +721,10 @@ public: //# include "methodHandles_zero.hpp" #endif #ifdef TARGET_ARCH_arm -#define TARGET_ARCH_NYI_6939861 1 //FIXME -//# include "methodHandles_arm.hpp" +# include "methodHandles_arm.hpp" #endif #ifdef TARGET_ARCH_ppc -#define TARGET_ARCH_NYI_6939861 1 //FIXME -//# include "methodHandles_ppc.hpp" +# include "methodHandles_ppc.hpp" #endif #ifdef TARGET_ARCH_NYI_6939861 From 32ead86b1cdbb924e7279949791cc7222c31ec9e Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Tue, 17 May 2011 12:26:33 -0700 Subject: [PATCH 07/11] 7045570: compiler/5091921/Test7005594.java failed because not enough space for object heap Fixed tests. Reviewed-by: iveresov, never --- hotspot/test/compiler/5091921/Test6890943.sh | 2 +- .../test/compiler/5091921/Test7005594.java | 2 +- hotspot/test/compiler/5091921/Test7005594.sh | 80 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 hotspot/test/compiler/5091921/Test7005594.sh diff --git a/hotspot/test/compiler/5091921/Test6890943.sh b/hotspot/test/compiler/5091921/Test6890943.sh index 0098ee21b5a..b722364afc0 100644 --- a/hotspot/test/compiler/5091921/Test6890943.sh +++ b/hotspot/test/compiler/5091921/Test6890943.sh @@ -52,7 +52,7 @@ cp ${TESTSRC}/Test6890943.sh . ${TESTJAVA}/bin/javac -d . Test6890943.java -${TESTJAVA}/bin/java ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1 +${TESTJAVA}/bin/java -XX:-PrintVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1 diff output6890943.txt test.out diff --git a/hotspot/test/compiler/5091921/Test7005594.java b/hotspot/test/compiler/5091921/Test7005594.java index 568421febe1..828339f1b21 100644 --- a/hotspot/test/compiler/5091921/Test7005594.java +++ b/hotspot/test/compiler/5091921/Test7005594.java @@ -27,7 +27,7 @@ * @bug 7005594 * @summary Array overflow not handled correctly with loop optimzations * - * @run main/othervm -Xms2048m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 + * @run shell Test7005594.sh */ public class Test7005594 { diff --git a/hotspot/test/compiler/5091921/Test7005594.sh b/hotspot/test/compiler/5091921/Test7005594.sh new file mode 100644 index 00000000000..a75c1b9e851 --- /dev/null +++ b/hotspot/test/compiler/5091921/Test7005594.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# +# Copyright (c) 2011, 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. +# +# + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTSRC=${TESTSRC}" +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTJAVA=${TESTJAVA}" +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi +echo "TESTCLASSES=${TESTCLASSES}" +echo "CLASSPATH=${CLASSPATH}" + +set -x + +cp ${TESTSRC}/Test7005594.java . +cp ${TESTSRC}/Test7005594.sh . + +${TESTJAVA}/bin/javac -d . Test7005594.java + +${TESTJAVA}/bin/java ${TESTVMOPTS} -Xms1600m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 + +result=$? + +cat test.out + +if [ $result -eq 95 ] +then + echo "Passed" + exit 0 +fi + +if [ $result -eq 97 ] +then + echo "Failed" + exit 1 +fi + +# The test should pass when no enough space for object heap +grep "Could not reserve enough space for object heap" test.out +if [ $? = 0 ] +then + echo "Passed" + exit 0 +else + echo "Failed" + exit 1 +fi From 807e4b3dcfcff9aa60ee2cc088fd70fca977a0c1 Mon Sep 17 00:00:00 2001 From: John R Rose Date: Tue, 17 May 2011 15:43:46 -0700 Subject: [PATCH 08/11] 7044892: JSR 292: API entry points sometimes throw the wrong exceptions or doesn't throw the expected one Fix to 7042656: JSR292: invokeExact/Generic doesn't throw UnsupportedOperationException if invoked via Method.invoke Reviewed-by: never --- hotspot/src/share/vm/prims/methodHandles.cpp | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 293a2771bb4..b78c96c3629 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -2922,6 +2922,20 @@ JVM_ENTRY(jint, MHN_getMembers(JNIEnv *env, jobject igcls, } JVM_END +JVM_ENTRY(jobject, MH_invoke_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) { + TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL); + THROW_MSG_NULL(UOE_name, "MethodHandle.invoke cannot be invoked reflectively"); + return NULL; +} +JVM_END + +JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) { + TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL); + THROW_MSG_NULL(UOE_name, "MethodHandle.invokeExact cannot be invoked reflectively"); + return NULL; +} +JVM_END + /// JVM_RegisterMethodHandleMethods @@ -2960,6 +2974,12 @@ static JNINativeMethod methods[] = { {CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)} }; +static JNINativeMethod invoke_methods[] = { + // void init(MemberName self, AccessibleObject ref) + {CC"invoke", CC"(["OBJ")"OBJ, FN_PTR(MH_invoke_UOE)}, + {CC"invokeExact", CC"(["OBJ")"OBJ, FN_PTR(MH_invokeExact_UOE)} +}; + // This one function is exported, used by NativeLookup. JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { @@ -2976,6 +2996,12 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod)); + if (!env->ExceptionOccurred()) { + const char* L_MH_name = (JLINV "MethodHandle"); + const char* MH_name = L_MH_name+1; + jclass MH_class = env->FindClass(MH_name); + status = env->RegisterNatives(MH_class, invoke_methods, sizeof(invoke_methods)/sizeof(JNINativeMethod)); + } if (env->ExceptionOccurred()) { MethodHandles::set_enabled(false); warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); From c2f2cb75fc9bac7ef7b17eed81a964292d94d928 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Tue, 17 May 2011 19:11:51 -0700 Subject: [PATCH 09/11] 7045513: JSR 292 inlining causes crashes in methodHandleWalk.cpp Reviewed-by: jrose --- .../sun/jvm/hotspot/CommandProcessor.java | 7 +- .../sun/jvm/hotspot/code/AdapterBlob.java | 58 ++++++++ .../sun/jvm/hotspot/code/CodeBlob.java | 4 +- .../sun/jvm/hotspot/code/CodeCache.java | 4 +- .../sun/jvm/hotspot/code/RicochetBlob.java | 56 +++++++ hotspot/src/cpu/x86/vm/methodHandles_x86.cpp | 2 +- hotspot/src/share/vm/ci/ciMethodHandle.cpp | 2 +- .../share/vm/interpreter/bytecodeTracer.cpp | 13 +- .../src/share/vm/opto/idealGraphPrinter.cpp | 2 + .../src/share/vm/prims/methodHandleWalk.cpp | 138 ++++++++++++++---- .../src/share/vm/prims/methodHandleWalk.hpp | 37 +++-- hotspot/src/share/vm/prims/methodHandles.cpp | 56 ++++++- hotspot/src/share/vm/runtime/globals.hpp | 3 + hotspot/src/share/vm/runtime/thread.cpp | 3 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 7 +- 15 files changed, 331 insertions(+), 61 deletions(-) create mode 100644 hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java create mode 100644 hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java index eacc59d8226..96cfe83e826 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java @@ -1028,7 +1028,12 @@ public class CommandProcessor { if (AddressOps.equal(val, value)) { if (!printed) { printed = true; - blob.printOn(out); + try { + blob.printOn(out); + } catch (Exception e) { + out.println("Exception printing blob at " + base); + e.printStackTrace(); + } } out.println("found at " + base + "\n"); } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java new file mode 100644 index 00000000000..654a733bb2b --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/AdapterBlob.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class AdapterBlob extends CodeBlob { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // Type type = db.lookupType("AdapterBlob"); + + // // FIXME: add any needed fields + } + + public AdapterBlob(Address addr) { + super(addr); + } + + public boolean isAdapterBlob() { + return true; + } + + public String getName() { + return "AdapterBlob: " + super.getName(); + } +} diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java index 937c5ce9628..7ed801eb5b8 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -93,6 +93,8 @@ public class CodeBlob extends VMObject { public boolean isUncommonTrapStub() { return false; } public boolean isExceptionStub() { return false; } public boolean isSafepointStub() { return false; } + public boolean isRicochetBlob() { return false; } + public boolean isAdapterBlob() { return false; } // Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod() public boolean isJavaMethod() { return false; } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java index 1f9fd3f6434..bf7a12f5bb0 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -57,6 +57,8 @@ public class CodeCache { virtualConstructor.addMapping("BufferBlob", BufferBlob.class); virtualConstructor.addMapping("nmethod", NMethod.class); virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class); + virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class); + virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class); virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); if (VM.getVM().isServerCompiler()) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java new file mode 100644 index 00000000000..3f7dd765451 --- /dev/null +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, 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. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +/** RicochetBlob (currently only used by Compiler 2) */ + +public class RicochetBlob extends SingletonBlob { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // Type type = db.lookupType("RicochetBlob"); + + // FIXME: add any needed fields + } + + public RicochetBlob(Address addr) { + super(addr); + } + + public boolean isRicochetBlob() { + return true; + } +} diff --git a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp index 1427d13c2c4..1240cb6b7fe 100644 --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp @@ -389,7 +389,7 @@ void MethodHandles::load_stack_move(MacroAssembler* _masm, } } -#ifndef PRODUCT +#ifdef ASSERT void MethodHandles::RicochetFrame::verify_offsets() { // Check compatibility of this struct with the more generally used offsets of class frame: int ebp_off = sender_link_offset_in_bytes(); // offset from struct base to local rbp value diff --git a/hotspot/src/share/vm/ci/ciMethodHandle.cpp b/hotspot/src/share/vm/ci/ciMethodHandle.cpp index c05b7eedf96..1fbb73f5ad1 100644 --- a/hotspot/src/share/vm/ci/ciMethodHandle.cpp +++ b/hotspot/src/share/vm/ci/ciMethodHandle.cpp @@ -43,7 +43,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const { methodHandle callee(_callee->get_methodOop()); // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. - MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD); + MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD); if (!HAS_PENDING_EXCEPTION) { methodHandle m = mhc.compile(THREAD); if (!HAS_PENDING_EXCEPTION) { diff --git a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp index 1309d0cf9a2..292e19c1eff 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp @@ -203,11 +203,14 @@ void print_oop(oop value, outputStream* st) { if (value == NULL) { st->print_cr(" NULL"); } else if (java_lang_String::is_instance(value)) { - EXCEPTION_MARK; - Handle h_value (THREAD, value); - Symbol* sym = java_lang_String::as_symbol(h_value, CATCH); - print_symbol(sym, st); - sym->decrement_refcount(); + char buf[40]; + int len = java_lang_String::utf8_length(value); + java_lang_String::as_utf8_string(value, buf, sizeof(buf)); + if (len >= (int)sizeof(buf)) { + st->print_cr(" %s...[%d]", buf, len); + } else { + st->print_cr(" %s", buf); + } } else { st->print_cr(" " PTR_FORMAT, (intptr_t) value); } diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 40874ba7ded..829673aa7eb 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -615,6 +615,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) { } } +#ifdef ASSERT if (node->debug_orig() != NULL) { stringStream dorigStream; Node* dorig = node->debug_orig(); @@ -629,6 +630,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) { } print_prop("debug_orig", dorigStream.as_string()); } +#endif if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) { buffer[0] = 0; diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.cpp b/hotspot/src/share/vm/prims/methodHandleWalk.cpp index d087f341561..25bdedc44ef 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp @@ -265,7 +265,7 @@ MethodHandleWalker::walk(TRAPS) { assert(dest == arg_state->_type, ""); ArgToken arg = arg_state->_arg; ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); - assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index"); + assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); break; } @@ -443,8 +443,10 @@ MethodHandleWalker::walk(TRAPS) { ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty)); } } - int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); - change_argument(T_VOID, ret_slot, rtype, ret); + if (rtype != T_VOID) { + int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); + change_argument(T_VOID, ret_slot, rtype, ret); + } break; } @@ -690,9 +692,8 @@ void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, boo // ----------------------------------------------------------------------------- // MethodHandleCompiler -MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS) +MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool is_invokedynamic, TRAPS) : MethodHandleWalker(root, is_invokedynamic, THREAD), - _callee(callee), _invoke_count(invoke_count), _thread(THREAD), _bytecode(THREAD, 50), @@ -706,8 +707,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int (void) _constants.append(NULL); // Set name and signature index. - _name_index = cpool_symbol_put(_callee->name()); - _signature_index = cpool_symbol_put(_callee->signature()); + _name_index = cpool_symbol_put(name); + _signature_index = cpool_symbol_put(signature); // Get return type klass. Handle first_mtype(THREAD, chain().method_type_oop()); @@ -715,7 +716,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int _rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(first_mtype()), &_rklass); if (_rtype == T_ARRAY) _rtype = T_OBJECT; - int params = _callee->size_of_parameters(); // Incoming arguments plus receiver. + ArgumentSizeComputer args(signature); + int params = args.size() + 1; // Incoming arguments plus receiver. _num_params = for_invokedynamic() ? params - 1 : params; // XXX Check if callee is static? } @@ -733,7 +735,7 @@ methodHandle MethodHandleCompiler::compile(TRAPS) { } -void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { +void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index, int args_size) { Bytecodes::check(op); // Are we legal? switch (op) { @@ -809,6 +811,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { case Bytecodes::_d2i: case Bytecodes::_d2l: case Bytecodes::_d2f: + case Bytecodes::_iaload: + case Bytecodes::_laload: + case Bytecodes::_faload: + case Bytecodes::_daload: + case Bytecodes::_aaload: + case Bytecodes::_baload: + case Bytecodes::_caload: + case Bytecodes::_saload: case Bytecodes::_ireturn: case Bytecodes::_lreturn: case Bytecodes::_freturn: @@ -822,9 +832,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { // bi case Bytecodes::_ldc: assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format"); - assert((char) index == index, "index does not fit in 8-bit"); - _bytecode.push(op); - _bytecode.push(index); + if (index == (index & 0xff)) { + _bytecode.push(op); + _bytecode.push(index); + } else { + _bytecode.push(Bytecodes::_ldc_w); + _bytecode.push(index >> 8); + _bytecode.push(index); + } break; case Bytecodes::_iload: @@ -838,9 +853,16 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { case Bytecodes::_dstore: case Bytecodes::_astore: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bi, "wrong bytecode format"); - assert((char) index == index, "index does not fit in 8-bit"); - _bytecode.push(op); - _bytecode.push(index); + if (index == (index & 0xff)) { + _bytecode.push(op); + _bytecode.push(index); + } else { + // doesn't fit in a u2 + _bytecode.push(Bytecodes::_wide); + _bytecode.push(op); + _bytecode.push(index >> 8); + _bytecode.push(index); + } break; // bkk @@ -848,7 +870,7 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { case Bytecodes::_ldc2_w: case Bytecodes::_checkcast: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format"); - assert((short) index == index, "index does not fit in 16-bit"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); _bytecode.push(op); _bytecode.push(index >> 8); _bytecode.push(index); @@ -859,12 +881,23 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) { case Bytecodes::_invokespecial: case Bytecodes::_invokevirtual: assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format"); - assert((short) index == index, "index does not fit in 16-bit"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); _bytecode.push(op); _bytecode.push(index >> 8); _bytecode.push(index); break; + case Bytecodes::_invokeinterface: + assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format"); + assert((unsigned short) index == index, "index does not fit in 16-bit"); + assert(args_size > 0, "valid args_size"); + _bytecode.push(op); + _bytecode.push(index >> 8); + _bytecode.push(index); + _bytecode.push(args_size); + _bytecode.push(0); + break; + default: ShouldNotReachHere(); } @@ -983,7 +1016,8 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co const ArgToken& src, TRAPS) { BasicType srctype = src.basic_type(); - int index = src.index(); + TokenType tt = src.token_type(); + int index = -1; switch (op) { case Bytecodes::_i2l: @@ -1004,18 +1038,31 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co case Bytecodes::_d2i: case Bytecodes::_d2l: case Bytecodes::_d2f: - emit_load(srctype, index); + if (tt == tt_constant) { + emit_load_constant(src); + } else { + emit_load(srctype, src.index()); + } stack_pop(srctype); // pop the src type emit_bc(op); stack_push(type); // push the dest value - if (srctype != type) + if (tt != tt_constant) + index = src.index(); + if (srctype != type || index == -1) index = new_local_index(type); emit_store(type, index); break; case Bytecodes::_checkcast: - emit_load(srctype, index); + if (tt == tt_constant) { + emit_load_constant(src); + } else { + emit_load(srctype, src.index()); + index = src.index(); + } emit_bc(op, cpool_klass_put(tk)); + if (index == -1) + index = new_local_index(type); emit_store(srctype, index); break; @@ -1058,6 +1105,11 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, Symbol* name = m->name(); Symbol* signature = m->signature(); + // Count the number of arguments, not the size + ArgumentCount asc(signature); + assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1), + "argc mismatch"); + if (tailcall) { // Actually, in order to make these methods more recognizable, // let's put them in holder class MethodHandle. That way stack @@ -1106,9 +1158,13 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, case Bytecodes::_invokevirtual: emit_bc(op, methodref_index); break; - case Bytecodes::_invokeinterface: - Unimplemented(); + + case Bytecodes::_invokeinterface: { + ArgumentSizeComputer asc(signature); + emit_bc(op, methodref_index, asc.size() + 1); break; + } + default: ShouldNotReachHere(); } @@ -1117,6 +1173,7 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, // Otherwise, make a recursive call to some helper routine. BasicType rbt = m->result_type(); if (rbt == T_ARRAY) rbt = T_OBJECT; + stack_push(rbt); // The return value is already pushed onto the stack. ArgToken ret; if (tailcall) { if (rbt != _rtype) { @@ -1171,7 +1228,6 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid, ret = ArgToken(); // Dummy return value. } else { - stack_push(rbt); // The return value is already pushed onto the stack. int index = new_local_index(rbt); switch (rbt) { case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT: @@ -1196,8 +1252,32 @@ MethodHandleCompiler::make_fetch(BasicType type, klassOop tk, Bytecodes::Code op const MethodHandleWalker::ArgToken& base, const MethodHandleWalker::ArgToken& offset, TRAPS) { - Unimplemented(); - return ArgToken(); + switch (base.token_type()) { + case tt_parameter: + case tt_temporary: + emit_load(base.basic_type(), base.index()); + break; + case tt_constant: + emit_load_constant(base); + break; + default: + ShouldNotReachHere(); + } + switch (offset.token_type()) { + case tt_parameter: + case tt_temporary: + emit_load(offset.basic_type(), offset.index()); + break; + case tt_constant: + emit_load_constant(offset); + break; + default: + ShouldNotReachHere(); + } + emit_bc(op); + int index = new_local_index(type); + emit_store(type, index); + return ArgToken(tt_temporary, type, index); } @@ -1372,12 +1452,10 @@ private: return s; } ArgToken token(const char* str) { - jvalue string_con; - string_con.j = (intptr_t) str; - return ArgToken(tt_symbolic, T_LONG, string_con); + return ArgToken(str); } const char* string(ArgToken token) { - return (const char*) (intptr_t) token.get_jlong(); + return token.str(); } void start_params() { _param_state <<= 1; diff --git a/hotspot/src/share/vm/prims/methodHandleWalk.hpp b/hotspot/src/share/vm/prims/methodHandleWalk.hpp index df2fe278f8c..5695d7481ae 100644 --- a/hotspot/src/share/vm/prims/methodHandleWalk.hpp +++ b/hotspot/src/share/vm/prims/methodHandleWalk.hpp @@ -126,26 +126,34 @@ public: Handle _handle; public: - ArgToken(TokenType tt = tt_illegal) : _tt(tt) {} - ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {} + ArgToken(TokenType tt = tt_illegal) : _tt(tt) { + assert(tt == tt_illegal || tt == tt_void, "invalid token type"); + } ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) { + assert(_tt == tt_parameter || _tt == tt_temporary, "must have index"); _value.i = index; } - ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) { - _handle = value; + ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) {} + ArgToken(BasicType bt, Handle value) : _tt(tt_constant), _bt(bt), _handle(value) {} + + + ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) { + _value.j = (intptr_t)str; } TokenType token_type() const { return _tt; } BasicType basic_type() const { return _bt; } - int index() const { return _value.i; } - Handle object() const { return _handle; } + bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; } + int index() const { assert(has_index(), "must have index");; return _value.i; } + Handle object() const { assert(_tt == tt_constant, "value type"); return _handle; } + const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)_value.j; } - jint get_jint() const { return _value.i; } - jlong get_jlong() const { return _value.j; } - jfloat get_jfloat() const { return _value.f; } - jdouble get_jdouble() const { return _value.d; } + jint get_jint() const { assert(_tt == tt_constant, "value types"); return _value.i; } + jlong get_jlong() const { assert(_tt == tt_constant, "value types"); return _value.j; } + jfloat get_jfloat() const { assert(_tt == tt_constant, "value types"); return _value.f; } + jdouble get_jdouble() const { assert(_tt == tt_constant, "value types"); return _value.d; } }; // Abstract interpretation state: @@ -256,7 +264,6 @@ public: // The IR happens to be JVM bytecodes. class MethodHandleCompiler : public MethodHandleWalker { private: - methodHandle _callee; int _invoke_count; // count the original call site has been executed KlassHandle _rklass; // Return type for casting. BasicType _rtype; @@ -404,7 +411,7 @@ private: return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index); } - void emit_bc(Bytecodes::Code op, int index = 0); + void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); void emit_load(BasicType bt, int index); void emit_store(BasicType bt, int index); void emit_load_constant(ArgToken arg); @@ -414,10 +421,10 @@ private: } virtual ArgToken make_oop_constant(oop con, TRAPS) { Handle h(THREAD, con); - return ArgToken(tt_constant, T_OBJECT, h); + return ArgToken(T_OBJECT, h); } virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { - return ArgToken(tt_constant, type, *con); + return ArgToken(type, *con); } virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); @@ -431,7 +438,7 @@ private: methodHandle get_method_oop(TRAPS) const; public: - MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS); + MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS); // Compile the given MH chain into bytecode. methodHandle compile(TRAPS); diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 293a2771bb4..daf7bfdefe6 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -25,9 +25,11 @@ #include "precompiled.hpp" #include "classfile/symbolTable.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/oopMapCache.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "prims/methodHandles.hpp" +#include "prims/methodHandleWalk.hpp" #include "runtime/javaCalls.hpp" #include "runtime/reflection.hpp" #include "runtime/signature.hpp" @@ -2599,6 +2601,50 @@ void MethodHandles::ensure_vmlayout_field(Handle target, TRAPS) { } } +#ifdef ASSERT + +extern "C" +void print_method_handle(oop mh); + +static void stress_method_handle_walk_impl(Handle mh, TRAPS) { + if (StressMethodHandleWalk) { + // Exercise the MethodHandleWalk code in various ways and validate + // the resulting method oop. Some of these produce output so they + // are guarded under Verbose. + ResourceMark rm; + HandleMark hm; + if (Verbose) { + print_method_handle(mh()); + } + TempNewSymbol name = SymbolTable::new_symbol("invoke", CHECK); + Handle mt = java_lang_invoke_MethodHandle::type(mh()); + TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK); + MethodHandleCompiler mhc(mh, name, signature, 10000, false, CHECK); + methodHandle m = mhc.compile(CHECK); + if (Verbose) { + m->print_codes(); + } + InterpreterOopMap mask; + OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask); + } +} + +static void stress_method_handle_walk(Handle mh, TRAPS) { + stress_method_handle_walk_impl(mh, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop ex = PENDING_EXCEPTION; + CLEAR_PENDING_EXCEPTION; + tty->print("StressMethodHandleWalk: "); + java_lang_Throwable::print(ex, tty); + tty->cr(); + } +} +#else + +static void stress_method_handle_walk(Handle mh, TRAPS) {} + +#endif + // // Here are the native methods on sun.invoke.MethodHandleImpl. // They are the private interface between this JVM and the HotSpot-specific @@ -2666,6 +2712,7 @@ JVM_ENTRY(void, MHN_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh, } MethodHandles::init_DirectMethodHandle(mh, m, (do_dispatch != JNI_FALSE), CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END @@ -2694,11 +2741,11 @@ JVM_ENTRY(void, MHN_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh, receiver_limit, decode_flags, CHECK); - return; + } else { + // Build a BMH on top of a DMH or another BMH: + MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK); } - - // Build a BMH on top of a DMH or another BMH: - MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END @@ -2716,6 +2763,7 @@ JVM_ENTRY(void, MHN_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh, assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null"); MethodHandles::init_AdapterMethodHandle(mh, target, argnum, CHECK); + stress_method_handle_walk(mh, CHECK); } JVM_END diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index a3c1939e2c4..da18b1370c9 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3724,6 +3724,9 @@ class CommandLineFlags { diagnostic(bool, OptimizeMethodHandles, true, \ "when constructing method handles, try to improve them") \ \ + develop(bool, StressMethodHandleWalk, false, \ + "Process all method handles with MethodHandleWalk") \ + \ diagnostic(bool, UseRicochetFrames, true, \ "use ricochet stack frames for method handle combination, " \ "if the platform supports them") \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 51c45746dc5..97b55ead15f 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -2861,6 +2861,7 @@ void JavaThread::trace_frames() { } +#ifdef ASSERT // Print or validate the layout of stack frames void JavaThread::print_frame_layout(int depth, bool validate_only) { ResourceMark rm; @@ -2878,7 +2879,7 @@ void JavaThread::print_frame_layout(int depth, bool validate_only) { values.print(); } } - +#endif void JavaThread::trace_stack_from(vframe* start_vf) { ResourceMark rm; diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 9f577dd9bbe..6924e47c4a5 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -783,6 +783,7 @@ static inline uint64_t cast_uint64_t(size_t x) nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ + nonstatic_field(nmethod, _state, unsigned char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ @@ -800,6 +801,8 @@ static inline uint64_t cast_uint64_t(size_t x) nonstatic_field(nmethod, _osr_entry_point, address) \ nonstatic_field(nmethod, _lock_count, jint) \ nonstatic_field(nmethod, _stack_traversal_mark, long) \ + nonstatic_field(nmethod, _compile_id, int) \ + nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ @@ -1310,11 +1313,13 @@ static inline uint64_t cast_uint64_t(size_t x) \ declare_toplevel_type(CodeBlob) \ declare_type(BufferBlob, CodeBlob) \ - declare_type(nmethod, CodeBlob) \ + declare_type(AdapterBlob, BufferBlob) \ + declare_type(nmethod, CodeBlob) \ declare_type(RuntimeStub, CodeBlob) \ declare_type(SingletonBlob, CodeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ + declare_type(RicochetBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ declare_c2_type(UncommonTrapBlob, CodeBlob) \ \ From 81013a98d01e67776b8fe9eab00370e634af5a4a Mon Sep 17 00:00:00 2001 From: Erik Trimble Date: Fri, 20 May 2011 05:24:46 -0700 Subject: [PATCH 10/11] 7040781: Bump the HS21 build number to 14 Update the HS21 build number to 14 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 452ad051644..116bb49712f 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011 HS_MAJOR_VER=21 HS_MINOR_VER=0 -HS_BUILD_NUMBER=13 +HS_BUILD_NUMBER=14 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 From 88f5cae01f19ec393f9a3e78016aae2318407911 Mon Sep 17 00:00:00 2001 From: Erik Trimble Date: Tue, 24 May 2011 14:02:47 -0700 Subject: [PATCH 11/11] Added tag hs21-b13 for changeset c59e039b8a59 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 8b20d73be2a..4956b9c0f63 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -172,3 +172,4 @@ d283b82966712b353fa307845a1316da42a355f4 hs21-b10 3aea9e9feb073f5500e031be6186666bcae89aa2 hs21-b11 9ad1548c6b63d596c411afc35147ffd5254426d9 jdk7-b142 9ad1548c6b63d596c411afc35147ffd5254426d9 hs21-b12 +c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13