--- old/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp 2016-05-23 12:17:53.259404608 +0200 +++ new/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp 2016-05-23 12:17:53.187404611 +0200 @@ -109,7 +109,7 @@ _old_set.remove(hr); } -// It dirties the cards that cover the block so that so that the post +// It dirties the cards that cover the block so that the post // write barrier never queues anything when updating objects on this // block. It is assumed (and in fact we assert) that the block // belongs to a young region. --- old/src/share/vm/gc/shared/collectedHeap.cpp 2016-05-23 12:17:53.495404597 +0200 +++ new/src/share/vm/gc/shared/collectedHeap.cpp 2016-05-23 12:17:53.427404600 +0200 @@ -386,7 +386,7 @@ // initialized by this point, a fact that we assert when doing the // card-mark.) // (c) G1CollectedHeap(G1) uses two kinds of write barriers. When a -// G1 concurrent marking is in progress an SATB (pre-write-)barrier is +// G1 concurrent marking is in progress an SATB (pre-write-)barrier // is used to remember the pre-value of any store. Initializing // stores will not need this barrier, so we need not worry about // compensating for the missing pre-barrier here. Turning now --- old/src/share/vm/opto/arraycopynode.cpp 2016-05-23 12:17:53.739404585 +0200 +++ new/src/share/vm/opto/arraycopynode.cpp 2016-05-23 12:17:53.671404589 +0200 @@ -222,6 +222,7 @@ Node* dest = in(ArrayCopyNode::Dest); const Type* src_type = phase->type(src); const TypeAryPtr* ary_src = src_type->isa_aryptr(); + assert(ary_src != NULL, "should be an array copy/clone"); if (is_arraycopy() || is_copyofrange() || is_copyof()) { const Type* dest_type = phase->type(dest); @@ -523,6 +524,12 @@ return mem; } + if (phase->type(in(ArrayCopyNode::Src))->isa_aryptr() == NULL) { + // Non-array Object.clone() with card marks is not handled by 'try_clone_instance'. + assert(!GraphKit::use_ReduceInitialCardMarks(), "can only happen with card marking"); + return NULL; + } + Node* adr_src = NULL; Node* base_src = NULL; Node* adr_dest = NULL; --- old/src/share/vm/opto/graphKit.cpp 2016-05-23 12:17:53.995404573 +0200 +++ new/src/share/vm/opto/graphKit.cpp 2016-05-23 12:17:53.919404577 +0200 @@ -4198,8 +4198,16 @@ Node* val, BasicType bt, bool use_precise) { - // If we are writing a NULL then we need no post barrier + if (val == NULL) { + // The Object.clone() intrinsic uses this path if !ReduceInitialCardMarks. + // We don't need a barrier here because the destination is a newly allocated object + // in Eden. Otherwise, GC verification breaks because we assume that cards in Eden + // are set to 'g1_young_gen' (see G1SATBCardTableModRefBS::verify_g1_young_region()). + assert(!use_ReduceInitialCardMarks(), "can only happen with card marking"); + return; + } + // If we are writing a NULL then we need no post barrier if (val != NULL && val->is_Con() && val->bottom_type() == TypePtr::NULL_PTR) { // Must be NULL const Type* t = val->bottom_type(); @@ -4274,41 +4282,34 @@ // If we know the value being stored does it cross regions? - if (val != NULL) { - // Does the store cause us to cross regions? - - // Should be able to do an unsigned compare of region_size instead of - // and extra shift. Do we have an unsigned compare?? - // Node* region_size = __ ConI(1 << HeapRegion::LogOfHRGrainBytes); - Node* xor_res = __ URShiftX ( __ XorX( cast, __ CastPX(__ ctrl(), val)), __ ConI(HeapRegion::LogOfHRGrainBytes)); - - // if (xor_res == 0) same region so skip - __ if_then(xor_res, BoolTest::ne, zeroX); { - - // No barrier if we are storing a NULL - __ if_then(val, BoolTest::ne, null(), unlikely); { - - // Ok must mark the card if not already dirty - - // load the original value of the card - Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - - __ if_then(card_val, BoolTest::ne, young_card); { - sync_kit(ideal); - insert_store_load_for_barrier(); - __ sync_kit(this); - - Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val_reload, BoolTest::ne, dirty_card); { - g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } __ end_if(); + // Should be able to do an unsigned compare of region_size instead of + // and extra shift. Do we have an unsigned compare?? + // Node* region_size = __ ConI(1 << HeapRegion::LogOfHRGrainBytes); + Node* xor_res = __ URShiftX ( __ XorX( cast, __ CastPX(__ ctrl(), val)), __ ConI(HeapRegion::LogOfHRGrainBytes)); + + // if (xor_res == 0) same region so skip + __ if_then(xor_res, BoolTest::ne, zeroX); { + + // No barrier if we are storing a NULL + __ if_then(val, BoolTest::ne, null(), unlikely); { + + // Ok must mark the card if not already dirty + + // load the original value of the card + Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); + + __ if_then(card_val, BoolTest::ne, young_card); { + sync_kit(ideal); + insert_store_load_for_barrier(); + __ sync_kit(this); + + Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); + __ if_then(card_val_reload, BoolTest::ne, dirty_card); { + g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); } __ end_if(); } __ end_if(); } __ end_if(); - } else { - // Object.clone() instrinsic uses this path. - g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } + } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); --- old/test/compiler/arraycopy/TestInstanceCloneAsLoadsStores.java 2016-05-23 12:17:54.283404560 +0200 +++ new/test/compiler/arraycopy/TestInstanceCloneAsLoadsStores.java 2016-05-23 12:17:54.211404563 +0200 @@ -23,12 +23,12 @@ /* * @test - * @bug 6700100 + * @bug 6700100 8156760 * @summary small instance clone as loads/stores * @compile TestInstanceCloneAsLoadsStores.java TestInstanceCloneUtils.java * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* TestInstanceCloneAsLoadsStores * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode TestInstanceCloneAsLoadsStores - * + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* -XX:+IgnoreUnrecognizedVMOptions -XX:-ReduceInitialCardMarks TestInstanceCloneAsLoadsStores */ public class TestInstanceCloneAsLoadsStores extends TestInstanceCloneUtils {