--- old/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp 2015-05-06 19:23:48.249544656 +0300 +++ new/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp 2015-05-06 19:23:48.197548122 +0300 @@ -2888,41 +2888,40 @@ cmp(src1, rscratch1); } -void MacroAssembler::store_check(Register obj) { - // Does a store check for the oop in register obj. The content of - // register obj is destroyed afterwards. - store_check_part_1(obj); - store_check_part_2(obj); -} - void MacroAssembler::store_check(Register obj, Address dst) { store_check(obj); } +void MacroAssembler::store_check(Register obj) { + // Does a store check for the oop in register obj. The content of + // register obj is destroyed afterwards. -// split the store check operation so that other instructions can be scheduled inbetween -void MacroAssembler::store_check_part_1(Register obj) { BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind"); - lsr(obj, obj, CardTableModRefBS::card_shift); -} -void MacroAssembler::store_check_part_2(Register obj) { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind"); - CardTableModRefBS* ct = (CardTableModRefBS*)bs; + CardTableModRefBS* ct = barrier_set_cast(bs); assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); - // The calculation for byte_map_base is as follows: - // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); - // So this essentially converts an address to a displacement and - // it will never need to be relocated. - - // FIXME: It's not likely that disp will fit into an offset so we - // don't bother to check, but it could save an instruction. - intptr_t disp = (intptr_t) ct->byte_map_base; - mov(rscratch1, disp); - strb(zr, Address(obj, rscratch1)); + lsr(obj, obj, CardTableModRefBS::card_shift); + + assert(CardTableModRefBS::dirty_card_val() == 0, "must be"); + + { + ExternalAddress cardtable((address) ct->byte_map_base); + unsigned long offset; + adrp(rscratch1, cardtable, offset); + assert(offset == 0, "byte_map_base is misaligned"); + } + + if (UseCondCardMark) { + Label L_already_dirty; + ldrb(rscratch2, Address(obj, rscratch1)); + cbz(rscratch2, L_already_dirty); + strb(zr, Address(obj, rscratch1)); + bind(L_already_dirty); + } else { + strb(zr, Address(obj, rscratch1)); + } } void MacroAssembler::load_klass(Register dst, Register src) { --- old/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp 2015-05-06 19:23:48.501527846 +0300 +++ new/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp 2015-05-06 19:23:48.449531317 +0300 @@ -704,10 +704,6 @@ #endif // INCLUDE_ALL_GCS - // split store_check(Register obj) to enhance instruction interleaving - void store_check_part_1(Register obj); - void store_check_part_2(Register obj); - // oop manipulations void load_klass(Register dst, Register src); void store_klass(Register dst, Register src); --- old/src/cpu/x86/vm/macroAssembler_x86.cpp 2015-05-06 19:23:48.729512639 +0300 +++ new/src/cpu/x86/vm/macroAssembler_x86.cpp 2015-05-06 19:23:48.673516374 +0300 @@ -4297,31 +4297,24 @@ ////////////////////////////////////////////////////////////////////////////////// -void MacroAssembler::store_check(Register obj) { - // Does a store check for the oop in register obj. The content of - // register obj is destroyed afterwards. - store_check_part_1(obj); - store_check_part_2(obj); -} - void MacroAssembler::store_check(Register obj, Address dst) { store_check(obj); } +void MacroAssembler::store_check(Register obj) { + // Does a store check for the oop in register obj. The content of + // register obj is destroyed afterwards. -// split the store check operation so that other instructions can be scheduled inbetween -void MacroAssembler::store_check_part_1(Register obj) { BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind"); - shrptr(obj, CardTableModRefBS::card_shift); -} -void MacroAssembler::store_check_part_2(Register obj) { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind"); CardTableModRefBS* ct = barrier_set_cast(bs); assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); + shrptr(obj, CardTableModRefBS::card_shift); + + Address card_addr; + // The calculation for byte_map_base is as follows: // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift); // So this essentially converts an address to a displacement and it will @@ -4329,8 +4322,7 @@ // large for a 32bit displacement. intptr_t disp = (intptr_t) ct->byte_map_base; if (is_simm32(disp)) { - Address cardtable(noreg, obj, Address::times_1, disp); - movb(cardtable, 0); + card_addr = Address(noreg, obj, Address::times_1, disp); } else { // By doing it as an ExternalAddress 'disp' could be converted to a rip-relative // displacement and done in a single instruction given favorable mapping and a @@ -4338,7 +4330,18 @@ // entry and that entry is not properly handled by the relocation code. AddressLiteral cardtable((address)ct->byte_map_base, relocInfo::none); Address index(noreg, obj, Address::times_1); - movb(as_Address(ArrayAddress(cardtable, index)), 0); + card_addr = as_Address(ArrayAddress(cardtable, index)); + } + + int dirty = CardTableModRefBS::dirty_card_val(); + if (UseCondCardMark) { + Label L_already_dirty; + cmpb(card_addr, dirty); + jcc(Assembler::equal, L_already_dirty); + movb(card_addr, dirty); + bind(L_already_dirty); + } else { + movb(card_addr, dirty); } } --- old/src/cpu/x86/vm/macroAssembler_x86.hpp 2015-05-06 19:23:48.977496103 +0300 +++ new/src/cpu/x86/vm/macroAssembler_x86.hpp 2015-05-06 19:23:48.925499565 +0300 @@ -315,10 +315,6 @@ #endif // INCLUDE_ALL_GCS - // split store_check(Register obj) to enhance instruction interleaving - void store_check_part_1(Register obj); - void store_check_part_2(Register obj); - // C 'boolean' to Java boolean: x == 0 ? 0 : 1 void c2bool(Register x); --- /dev/null 2015-05-01 17:48:48.457547995 +0300 +++ new/test/gc/CondCardMark/Basic.java 2015-05-06 19:23:49.117486763 +0300 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8076987 + * @bug 8078438 + * @summary Verify UseCondCardMark works + * @library /testlibrary /../../test/lib + * @build Basic + * @run main/othervm -Xint Basic + * @run main/othervm -Xint -XX:+UseCondCardMark Basic + * @run main/othervm -XX:TieredStopAtLevel=1 Basic + * @run main/othervm -XX:TieredStopAtLevel=1 -XX:+UseCondCardMark Basic + * @run main/othervm -XX:TieredStopAtLevel=4 Basic + * @run main/othervm -XX:TieredStopAtLevel=4 -XX:+UseCondCardMark Basic + * @run main/othervm -XX:-TieredCompilation Basic + * @run main/othervm -XX:-TieredCompilation -XX:+UseCondCardMark Basic +*/ +public class Basic { + + static volatile MyObject sink; + + public static void main(String args[]) { + final int COUNT = 10000000; + for (int c = 0; c < COUNT; c++) { + MyObject o = new MyObject(); + o.x = c; + doStore(o); + } + + if (sink.x != COUNT-1) { + throw new IllegalStateException("Failed"); + } + } + + public static void doStore(MyObject o) { + sink = o; + } + + static class MyObject { + int x; + } + +}