1 /*
   2  * Copyright (c) 2018, Red Hat, Inc. and/or its affiliates.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "precompiled.hpp"
  25 #include "gc/shenandoah/brooksPointer.hpp"
  26 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  27 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
  28 #include "gc/shenandoah/shenandoahConnectionMatrix.hpp"
  29 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  30 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  31 #include "interpreter/interpreter.hpp"
  32 #include "interpreter/interp_masm.hpp"
  33 #include "runtime/sharedRuntime.hpp"
  34 #include "runtime/thread.hpp"
  35 
  36 #define __ masm->
  37 
  38 void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
  39                                                        Register addr, Register count, RegSet saved_regs) {
  40   if (is_oop) {
  41     bool dest_uninitialized = (decorators & AS_DEST_NOT_INITIALIZED) != 0;
  42     if (!dest_uninitialized) {
  43       __ push(saved_regs, sp);
  44       if (count == c_rarg0) {
  45         if (addr == c_rarg1) {
  46           // exactly backwards!!
  47           __ mov(rscratch1, c_rarg0);
  48           __ mov(c_rarg0, c_rarg1);
  49           __ mov(c_rarg1, rscratch1);
  50         } else {
  51           __ mov(c_rarg1, count);
  52           __ mov(c_rarg0, addr);
  53         }
  54       } else {
  55         __ mov(c_rarg0, addr);
  56         __ mov(c_rarg1, count);
  57       }
  58       if (UseCompressedOops) {
  59         __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::write_ref_array_pre_narrow_oop_entry), 2);
  60       } else {
  61         __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::write_ref_array_pre_oop_entry), 2);
  62       }
  63       __ pop(saved_regs, sp);
  64     }
  65   }
  66 }
  67 
  68 void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
  69                                                        Register start, Register end, Register scratch, RegSet saved_regs) {
  70   if (is_oop) {
  71     __ push(saved_regs, sp);
  72     // must compute element count unless barrier set interface is changed (other platforms supply count)
  73     assert_different_registers(start, end, scratch);
  74     __ lea(scratch, Address(end, BytesPerHeapOop));
  75     __ sub(scratch, scratch, start);               // subtract start to get #bytes
  76     __ lsr(scratch, scratch, LogBytesPerHeapOop);  // convert to element count
  77     __ mov(c_rarg0, start);
  78     __ mov(c_rarg1, scratch);
  79     __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::write_ref_array_post_entry), 2);
  80     __ pop(saved_regs, sp);
  81   }
  82 }
  83 
  84 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,
  85                                                                  Register obj,
  86                                                                  Register pre_val,
  87                                                                  Register thread,
  88                                                                  Register tmp,
  89                                                                  bool tosca_live,
  90                                                                  bool expand_call) {
  91   if (ShenandoahSATBBarrier) {
  92     satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call);
  93   }
  94 }
  95 
  96 void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
  97                                                            Register obj,
  98                                                            Register pre_val,
  99                                                            Register thread,
 100                                                            Register tmp,
 101                                                            bool tosca_live,
 102                                                            bool expand_call) {
 103   // If expand_call is true then we expand the call_VM_leaf macro
 104   // directly to skip generating the check by
 105   // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
 106 
 107   assert(thread == rthread, "must be");
 108 
 109   Label done;
 110   Label runtime;
 111 
 112   assert_different_registers(obj, pre_val, tmp, rscratch1);
 113   assert(pre_val != noreg &&  tmp != noreg, "expecting a register");
 114 
 115   Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()));
 116   Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
 117   Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
 118 
 119   // Is marking active?
 120   if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
 121     __ ldrw(tmp, in_progress);
 122   } else {
 123     assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
 124     __ ldrb(tmp, in_progress);
 125   }
 126   __ cbzw(tmp, done);
 127 
 128   // Do we need to load the previous value?
 129   if (obj != noreg) {
 130     __ load_heap_oop(pre_val, Address(obj, 0));
 131   }
 132 
 133   // Is the previous value null?
 134   __ cbz(pre_val, done);
 135 
 136   // Can we store original value in the thread's buffer?
 137   // Is index == 0?
 138   // (The index field is typed as size_t.)
 139 
 140   __ ldr(tmp, index);                      // tmp := *index_adr
 141   __ cbz(tmp, runtime);                    // tmp == 0?
 142                                         // If yes, goto runtime
 143 
 144   __ sub(tmp, tmp, wordSize);              // tmp := tmp - wordSize
 145   __ str(tmp, index);                      // *index_adr := tmp
 146   __ ldr(rscratch1, buffer);
 147   __ add(tmp, tmp, rscratch1);             // tmp := tmp + *buffer_adr
 148 
 149   // Record the previous value
 150   __ str(pre_val, Address(tmp, 0));
 151   __ b(done);
 152 
 153   __ bind(runtime);
 154   // save the live input values
 155   RegSet saved = RegSet::of(pre_val);
 156   if (tosca_live) saved += RegSet::of(r0);
 157   if (obj != noreg) saved += RegSet::of(obj);
 158 
 159   __ push(saved, sp);
 160 
 161   // Calling the runtime using the regular call_VM_leaf mechanism generates
 162   // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
 163   // that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.
 164   //
 165   // If we care generating the pre-barrier without a frame (e.g. in the
 166   // intrinsified Reference.get() routine) then ebp might be pointing to
 167   // the caller frame and so this check will most likely fail at runtime.
 168   //
 169   // Expanding the call directly bypasses the generation of the check.
 170   // So when we do not have have a full interpreter frame on the stack
 171   // expand_call should be passed true.
 172 
 173   if (expand_call) {
 174     assert(pre_val != c_rarg1, "smashed arg");
 175     __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
 176   } else {
 177     __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
 178   }
 179 
 180   __ pop(saved, sp);
 181 
 182   __ bind(done);
 183 }
 184 
 185 void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_post(MacroAssembler* masm,
 186                                                                   Register store_addr,
 187                                                                   Register new_val,
 188                                                                   Register thread,
 189                                                                   Register tmp,
 190                                                                   Register tmp2) {
 191   assert(thread == rthread, "must be");
 192   assert(UseShenandoahGC, "expect Shenandoah GC");
 193 
 194   if (! UseShenandoahMatrix) {
 195     // No need for that barrier if not using matrix.
 196     return;
 197   }
 198 
 199   assert_different_registers(store_addr, new_val, thread, tmp, tmp2, rscratch1);
 200 
 201   Label done;
 202   __ cbz(new_val, done);
 203 
 204   ShenandoahConnectionMatrix* matrix = ShenandoahHeap::heap()->connection_matrix();
 205 
 206   // Compute to-region index
 207   __ lsr(tmp, new_val, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 208 
 209   // Compute from-region index
 210   __ lsr(tmp2, store_addr, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 211 
 212   // Compute matrix index
 213   __ mov(rscratch1, matrix->stride_jint());
 214   // Address is _matrix[to * stride + from]
 215   __ madd(tmp, tmp, rscratch1, tmp2);
 216   __ mov(rscratch1, matrix->magic_offset());
 217   Address loc(tmp, rscratch1);
 218 
 219   __ ldrb(tmp2, loc);
 220   __ cbnz(tmp2, done);
 221   __ mov(tmp2, 1);
 222   __ strb(tmp2, loc);
 223   __ bind(done);
 224 }
 225 
 226 void ShenandoahBarrierSetAssembler::read_barrier(MacroAssembler* masm, Register dst) {
 227   if (ShenandoahReadBarrier) {
 228     read_barrier_impl(masm, dst);
 229   }
 230 }
 231 
 232 void ShenandoahBarrierSetAssembler::read_barrier_impl(MacroAssembler* masm, Register dst) {
 233   assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier), "should be enabled");
 234   Label is_null;
 235   __ cbz(dst, is_null);
 236   read_barrier_not_null_impl(masm, dst);
 237   __ bind(is_null);
 238 }
 239 
 240 void ShenandoahBarrierSetAssembler::read_barrier_not_null(MacroAssembler* masm, Register dst) {
 241   if (ShenandoahReadBarrier) {
 242     read_barrier_not_null_impl(masm, dst);
 243   }
 244 }
 245 
 246 
 247 void ShenandoahBarrierSetAssembler::read_barrier_not_null_impl(MacroAssembler* masm, Register dst) {
 248   assert(UseShenandoahGC && (ShenandoahReadBarrier || ShenandoahStoreValReadBarrier), "should be enabled");
 249   __ ldr(dst, Address(dst, BrooksPointer::byte_offset()));
 250 }
 251 
 252 void ShenandoahBarrierSetAssembler::write_barrier(MacroAssembler* masm, Register dst) {
 253   if (ShenandoahWriteBarrier) {
 254     write_barrier_impl(masm, dst);
 255   }
 256 }
 257 
 258 void ShenandoahBarrierSetAssembler::write_barrier_impl(MacroAssembler* masm, Register dst) {
 259   assert(UseShenandoahGC && (ShenandoahWriteBarrier || ShenandoahStoreValEnqueueBarrier), "should be enabled");
 260   assert(dst != rscratch1, "different regs");
 261   assert(dst != rscratch2, "Need rscratch2");
 262 
 263   Label done;
 264 
 265   Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 266   __ ldrb(rscratch1, gc_state);
 267   __ membar(Assembler::LoadLoad);
 268 
 269   // Now check if evacuation is in progress.
 270   read_barrier_not_null(masm, dst);
 271 
 272   __ mov(rscratch2, ShenandoahHeap::EVACUATION | ShenandoahHeap::TRAVERSAL);
 273   __ tst(rscratch1, rscratch2);
 274   __ br(Assembler::EQ, done);
 275 
 276   __ lsr(rscratch1, dst, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 277   __ mov(rscratch2,  ShenandoahHeap::in_cset_fast_test_addr());
 278   __ ldrb(rscratch2, Address(rscratch2, rscratch1));
 279   __ tst(rscratch2, 0x1);
 280   __ br(Assembler::EQ, done);
 281 
 282   // Save possibly live regs.
 283   RegSet live_regs = RegSet::range(r0, r4) - dst;
 284   __ push(live_regs, sp);
 285   __ strd(v0, __ pre(sp, 2 * -wordSize));
 286 
 287   // Call into runtime
 288   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::write_barrier_IRT), dst);
 289 
 290   // Move result into dst reg.
 291   __ mov(dst, r0);
 292 
 293   // Restore possibly live regs.
 294   __ ldrd(v0, __ post(sp, 2 * wordSize));
 295   __ pop(live_regs, sp);
 296 
 297   __ bind(done);
 298 }
 299 
 300 void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) {
 301   if (ShenandoahStoreValEnqueueBarrier) {
 302     Label is_null;
 303     __ cbz(dst, is_null);
 304     write_barrier_impl(masm, dst);
 305     __ bind(is_null);
 306     // Save possibly live regs.
 307     RegSet live_regs = RegSet::range(r0, r4) - dst;
 308     __ push(live_regs, sp);
 309     __ strd(v0, __ pre(sp, 2 * -wordSize));
 310 
 311     satb_write_barrier_pre(masm, noreg, dst, rthread, tmp, true, false);
 312 
 313     // Restore possibly live regs.
 314     __ ldrd(v0, __ post(sp, 2 * wordSize));
 315     __ pop(live_regs, sp);
 316   }
 317   if (ShenandoahStoreValReadBarrier) {
 318     read_barrier_impl(masm, dst);
 319   }
 320 }
 321 
 322 void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
 323                                             Register dst, Address src, Register tmp1, Register tmp_thread) {
 324   bool on_oop = type == T_OBJECT || type == T_ARRAY;
 325   bool in_heap = (decorators & IN_HEAP) != 0;
 326   bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
 327   bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
 328   bool on_reference = on_weak || on_phantom;
 329   BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
 330   if (ShenandoahKeepAliveBarrier && on_oop && on_reference) {
 331     satb_write_barrier_pre(masm /* masm */,
 332                            noreg /* obj */,
 333                            dst /* pre_val */,
 334                            rthread /* thread */,
 335                            tmp1 /* tmp */,
 336                            true /* tosca_live */,
 337                            true /* expand_call */);
 338   }
 339 }
 340 
 341 void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
 342                                              Address dst, Register val, Register tmp1, Register tmp2) {
 343   bool on_oop = type == T_OBJECT || type == T_ARRAY;
 344   if (!on_oop) {
 345     BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
 346     return;
 347   }
 348 
 349   // flatten object address if needed
 350   if (dst.index() == noreg && dst.offset() == 0) {
 351     if (dst.base() != r3) {
 352       __ mov(r3, dst.base());
 353     }
 354   } else {
 355     __ lea(r3, dst);
 356   }
 357 
 358   shenandoah_write_barrier_pre(masm,
 359                                r3 /* obj */,
 360                                tmp2 /* pre_val */,
 361                                rthread /* thread */,
 362                                tmp1  /* tmp */,
 363                                val != noreg /* tosca_live */,
 364                                false /* expand_call */);
 365 
 366   if (val == noreg) {
 367     __ store_heap_oop_null(Address(r3, 0));
 368   } else {
 369     storeval_barrier(masm, val, tmp1);
 370     // G1 barrier needs uncompressed oop for region cross check.
 371     Register new_val = val;
 372     if (UseCompressedOops) {
 373       new_val = rscratch2;
 374       __ mov(new_val, val);
 375     }
 376     __ store_heap_oop(Address(r3, 0), val);
 377     shenandoah_write_barrier_post(masm,
 378                                   r3 /* store_adr */,
 379                                   new_val /* new_val */,
 380                                   rthread /* thread */,
 381                                   tmp1 /* tmp */,
 382                                   tmp2 /* tmp2 */);
 383   }
 384 
 385 }
 386 
 387 void ShenandoahBarrierSetAssembler::obj_equals(MacroAssembler* masm, DecoratorSet decorators, Register op1, Register op2) {
 388   __ cmp(op1, op2);
 389   if (ShenandoahAcmpBarrier) {
 390     Label done;
 391     __ br(Assembler::EQ, done);
 392     // The object may have been evacuated, but we won't see it without a
 393     // membar here.
 394     __ membar(Assembler::LoadStore| Assembler::LoadLoad);
 395     read_barrier(masm, op1);
 396     read_barrier(masm, op2);
 397     __ cmp(op1, op2);
 398     __ bind(done);
 399   }
 400 }
 401 
 402 void ShenandoahBarrierSetAssembler::resolve_for_read(MacroAssembler* masm, DecoratorSet decorators, Register obj) {
 403   bool oop_not_null = (decorators & OOP_NOT_NULL) != 0;
 404   if (oop_not_null) {
 405     read_barrier_not_null(masm, obj);
 406   } else {
 407     read_barrier(masm, obj);
 408   }
 409 }
 410 
 411 void ShenandoahBarrierSetAssembler::resolve_for_write(MacroAssembler* masm, DecoratorSet decorators, Register obj) {
 412   write_barrier(masm, obj);
 413 }