--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp Wed Apr 11 10:05:02 2018 -0400
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp Wed Apr 11 16:07:42 2018 +0200
@@ -98,3 +98,245 @@
__ addi(R1_SP, R1_SP, frame_size); // pop_frame();
__ restore_LR_CR(R0);
}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators, Register obj, RegisterOrConstant ind_or_offs, Register pre_val,
+ Register tmp1, Register tmp2, bool needs_frame) {
+ bool not_null = (decorators & OOP_NOT_NULL) != 0,
+ preloaded = obj == noreg;
+ Register nv_save = noreg;
+
+ if (preloaded) {
+ // We are not loading the previous value so make
+ // sure that we don't trash the value in pre_val
+ // with the code below.
+ assert_different_registers(pre_val, tmp1, tmp2);
+ if (pre_val->is_volatile()) {
+ nv_save = !tmp1->is_volatile() ? tmp1 : tmp2;
+ assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register");
+ }
+ }
+
+ Label runtime, filtered;
+
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ lwz(tmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
+ } else {
+ guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ lbz(tmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
+ }
+ __ cmpdi(CCR0, tmp1, 0);
+ __ beq(CCR0, filtered);
+
+ // Do we need to load the previous value?
+ if (!preloaded) {
+ // Load the previous value...
+ if (UseCompressedOops) {
+ __ lwz(pre_val, ind_or_offs, obj);
+ } else {
+ __ ld(pre_val, ind_or_offs, obj);
+ }
+ // Previous value has been loaded into Rpre_val.
+ }
+ assert(pre_val != noreg, "must have a real register");
+
+ // Is the previous value null?
+ if (preloaded && not_null) {
+#ifdef ASSERT
+ __ cmpdi(CCR0, pre_val, 0);
+ __ asm_assert_ne("null oop not allowed (G1 pre)", 0x321); // Checked by caller.
+#endif
+ } else {
+ __ cmpdi(CCR0, pre_val, 0);
+ __ beq(CCR0, filtered);
+ }
+
+ if (!preloaded && UseCompressedOops) {
+ __ decode_heap_oop_not_null(pre_val);
+ }
+
+ // OK, it's not filtered, so we'll need to call enqueue. In the normal
+ // case, pre_val will be a scratch G-reg, but there are some cases in
+ // which it's an O-reg. In the first case, do a normal call. In the
+ // latter, do a save here and call the frameless version.
+
+ // Can we store original value in the thread's buffer?
+ // Is index == 0?
+ // (The index field is typed as size_t.)
+ const Register Rbuffer = tmp1, Rindex = tmp2;
+
+ __ ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread);
+ __ cmpdi(CCR0, Rindex, 0);
+ __ beq(CCR0, runtime); // If index == 0, goto runtime.
+ __ ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()), R16_thread);
+
+ __ addi(Rindex, Rindex, -wordSize); // Decrement index.
+ __ std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread);
+
+ // Record the previous value.
+ __ stdx(pre_val, Rbuffer, Rindex);
+ __ b(filtered);
+
+ __ bind(runtime);
+
+ // May need to preserve LR. Also needed if current frame is not compatible with C calling convention.
+ if (needs_frame) {
+ __ save_LR_CR(tmp1);
+ __ push_frame_reg_args(0, tmp2);
+ }
+
+ if (pre_val->is_volatile() && preloaded) { __ mr(nv_save, pre_val); } // Save pre_val across C call if it was preloaded.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, R16_thread);
+ if (pre_val->is_volatile() && preloaded) { __ mr(pre_val, nv_save); } // restore
+
+ if (needs_frame) {
+ __ pop_frame();
+ __ restore_LR_CR(tmp1);
+ }
+
+ __ bind(filtered);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register store_addr, Register new_val,
+ Register tmp1, Register tmp2, Register tmp3) {
+ bool not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ Label runtime, filtered;
+ assert_different_registers(store_addr, new_val, tmp1, tmp2);
+
+ CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ // Does store cross heap regions?
+ if (G1RSBarrierRegionFilter) {
+ __ xorr(tmp1, store_addr, new_val);
+ __ srdi_(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
+ __ beq(CCR0, filtered);
+ }
+
+ // Crosses regions, storing NULL?
+ if (not_null) {
+#ifdef ASSERT
+ __ cmpdi(CCR0, new_val, 0);
+ __ asm_assert_ne("null oop not allowed (G1 post)", 0x322); // Checked by caller.
+#endif
+ } else {
+ __ cmpdi(CCR0, new_val, 0);
+ __ beq(CCR0, filtered);
+ }
+
+ // Storing region crossing non-NULL, is card already dirty?
+ const Register Rcard_addr = tmp1;
+ Register Rbase = tmp2;
+ __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3);
+
+ __ srdi(Rcard_addr, store_addr, CardTable::card_shift);
+
+ // Get the address of the card.
+ __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr);
+ __ cmpwi(CCR0, tmp3, (int)G1CardTable::g1_young_card_val());
+ __ beq(CCR0, filtered);
+
+ __ membar(Assembler::StoreLoad);
+ __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); // Reload after membar.
+ __ cmpwi(CCR0, tmp3 /* card value */, (int)G1CardTable::dirty_card_val());
+ __ beq(CCR0, filtered);
+
+ // Storing a region crossing, non-NULL oop, card is clean.
+ // Dirty card and log.
+ __ li(tmp3, (int)G1CardTable::dirty_card_val());
+ //release(); // G1: oops are allowed to get visible after dirty marking.
+ __ stbx(tmp3, Rbase, Rcard_addr);
+
+ __ add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued.
+ Rbase = noreg; // end of lifetime
+
+ const Register Rqueue_index = tmp2,
+ Rqueue_buf = tmp3;
+ __ ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread);
+ __ cmpdi(CCR0, Rqueue_index, 0);
+ __ beq(CCR0, runtime); // index == 0 then jump to runtime
+ __ ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf()), R16_thread);
+
+ __ addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index
+ __ std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread);
+
+ __ stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card
+ __ b(filtered);
+
+ __ bind(runtime);
+
+ // Save the live input values.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), Rcard_addr, R16_thread);
+
+ __ bind(filtered);
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+ // Load and record the previous value.
+ g1_write_barrier_pre(masm, decorators, base, ind_or_offs,
+ tmp1, tmp2, tmp3, needs_frame);
+
+ BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+
+ // No need for post barrier if storing NULL
+ if (val != noreg) {
+ if (precise) {
+ if (ind_or_offs.is_constant()) {
+ __ add_const_optimized(base, base, ind_or_offs.as_constant(), tmp1);
+ } else {
+ __ add(base, ind_or_offs.as_register(), base);
+ }
+ }
+ g1_write_barrier_post(masm, decorators, base, val, tmp1, tmp2, tmp3);
+ }
+}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register dst,
+ Register tmp1, Register tmp2, bool needs_frame, Label *is_null) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ Label done;
+ if (on_oop && on_reference && is_null == NULL) { is_null = &done; }
+ // Load the value of the referent field.
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, tmp1, tmp2, needs_frame, is_null);
+ if (on_oop && on_reference) {
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer. Note with
+ // these parameters the pre-barrier does not generate
+ // the load of the previous value
+ // We only reach here if value is not null.
+ g1_write_barrier_pre(masm, decorators | OOP_NOT_NULL, noreg /* obj */, (intptr_t)0, dst /* pre_val */,
+ tmp1, tmp2, needs_frame);
+ }
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, bool needs_frame) {
+ Label done, not_weak;
+ __ cmpdi(CCR0, value, 0);
+ __ beq(CCR0, done); // Use NULL as-is.
+
+ __ clrrdi(tmp1, value, JNIHandles::weak_tag_size);
+ __ andi_(tmp2, value, JNIHandles::weak_tag_mask);
+ __ ld(value, 0, tmp1); // Resolve (untagged) jobject.
+
+ __ beq(CCR0, not_weak); // Test for jweak tag.
+ __ verify_oop(value);
+ g1_write_barrier_pre(masm, IN_ROOT | ON_PHANTOM_OOP_REF,
+ noreg, noreg, value,
+ tmp1, tmp2, needs_frame);
+ __ bind(not_weak);
+ __ verify_oop(value);
+ __ bind(done);
+}
+
+#undef __