1 /*
  2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "asm/macroAssembler.inline.hpp"
 27 #include "gc/g1/g1BarrierSet.hpp"
 28 #include "gc/g1/g1BarrierSetAssembler.hpp"
 29 #include "gc/g1/g1CardTable.hpp"
 30 #include "gc/g1/g1ThreadLocalData.hpp"
 31 #include "gc/g1/heapRegion.hpp"
 32 #include "interpreter/interp_masm.hpp"
 33 #include "runtime/sharedRuntime.hpp"
 34 
 35 #define __ masm->
 36 
 37 void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
 38                                                             Register addr, Register count, RegSet saved_regs) {
 39   bool dest_uninitialized = (decorators & AS_DEST_NOT_INITIALIZED) != 0;
 40   if (!dest_uninitialized) {
 41     __ push(saved_regs, sp);
 42     if (count == c_rarg0) {
 43       if (addr == c_rarg1) {
 44         // exactly backwards!!
 45         __ mov(rscratch1, c_rarg0);
 46         __ mov(c_rarg0, c_rarg1);
 47         __ mov(c_rarg1, rscratch1);
 48       } else {
 49         __ mov(c_rarg1, count);
 50         __ mov(c_rarg0, addr);
 51       }
 52     } else {
 53       __ mov(c_rarg0, addr);
 54       __ mov(c_rarg1, count);
 55     }
 56     if (UseCompressedOops) {
 57       __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSet::write_ref_array_pre_narrow_oop_entry), 2);
 58     } else {
 59       __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSet::write_ref_array_pre_oop_entry), 2);
 60     }
 61     __ pop(saved_regs, sp);
 62   }
 63 }
 64 
 65 void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
 66                                                              Register start, Register end, Register scratch, RegSet saved_regs) {
 67   __ push(saved_regs, sp);
 68   // must compute element count unless barrier set interface is changed (other platforms supply count)
 69   assert_different_registers(start, end, scratch);
 70   __ lea(scratch, Address(end, BytesPerHeapOop));
 71   __ sub(scratch, scratch, start);               // subtract start to get #bytes
 72   __ lsr(scratch, scratch, LogBytesPerHeapOop);  // convert to element count
 73   __ mov(c_rarg0, start);
 74   __ mov(c_rarg1, scratch);
 75   __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSet::write_ref_array_post_entry), 2);
 76   __ pop(saved_regs, sp);
 77 }
 78 
 79 void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
 80                                                  Register obj,
 81                                                  Register pre_val,
 82                                                  Register thread,
 83                                                  Register tmp,
 84                                                  bool tosca_live,
 85                                                  bool expand_call) {
 86   // If expand_call is true then we expand the call_VM_leaf macro
 87   // directly to skip generating the check by
 88   // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
 89 
 90   assert(thread == rthread, "must be");
 91 
 92   Label done;
 93   Label runtime;
 94 
 95   assert_different_registers(obj, pre_val, tmp, rscratch1);
 96   assert(pre_val != noreg &&  tmp != noreg, "expecting a register");
 97 
 98   Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
 99   Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
100   Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
101 
102   // Is marking active?
103   if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
104     __ ldrw(tmp, in_progress);
105   } else {
106     assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
107     __ ldrb(tmp, in_progress);
108   }
109   __ cbzw(tmp, done);
110 
111   // Do we need to load the previous value?
112   if (obj != noreg) {
113     __ load_heap_oop(pre_val, Address(obj, 0));
114   }
115 
116   // Is the previous value null?
117   __ cbz(pre_val, done);
118 
119   // Can we store original value in the thread's buffer?
120   // Is index == 0?
121   // (The index field is typed as size_t.)
122 
123   __ ldr(tmp, index);                      // tmp := *index_adr
124   __ cbz(tmp, runtime);                    // tmp == 0?
125                                         // If yes, goto runtime
126 
127   __ sub(tmp, tmp, wordSize);              // tmp := tmp - wordSize
128   __ str(tmp, index);                      // *index_adr := tmp
129   __ ldr(rscratch1, buffer);
130   __ add(tmp, tmp, rscratch1);             // tmp := tmp + *buffer_adr
131 
132   // Record the previous value
133   __ str(pre_val, Address(tmp, 0));
134   __ b(done);
135 
136   __ bind(runtime);
137   // save the live input values
138   RegSet saved = RegSet::of(pre_val);
139   if (tosca_live) saved += RegSet::of(r0);
140   if (obj != noreg) saved += RegSet::of(obj);
141 
142   __ push(saved, sp);
143 
144   // Calling the runtime using the regular call_VM_leaf mechanism generates
145   // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
146   // that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.
147   //
148   // If we care generating the pre-barrier without a frame (e.g. in the
149   // intrinsified Reference.get() routine) then ebp might be pointing to
150   // the caller frame and so this check will most likely fail at runtime.
151   //
152   // Expanding the call directly bypasses the generation of the check.
153   // So when we do not have have a full interpreter frame on the stack
154   // expand_call should be passed true.
155 
156   if (expand_call) {
157     assert(pre_val != c_rarg1, "smashed arg");
158     __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
159   } else {
160     __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
161   }
162 
163   __ pop(saved, sp);
164 
165   __ bind(done);
166 
167 }
168 
169 void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
170                                                   Register store_addr,
171                                                   Register new_val,
172                                                   Register thread,
173                                                   Register tmp,
174                                                   Register tmp2) {
175   assert(thread == rthread, "must be");
176   assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
177                              rscratch1);
178   assert(store_addr != noreg && new_val != noreg && tmp != noreg
179          && tmp2 != noreg, "expecting a register");
180 
181   Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
182   Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
183 
184   BarrierSet* bs = BarrierSet::barrier_set();
185   CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
186   CardTable* ct = ctbs->card_table();
187   assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
188 
189   Label done;
190   Label runtime;
191 
192   // Does store cross heap regions?
193 
194   __ eor(tmp, store_addr, new_val);
195   __ lsr(tmp, tmp, HeapRegion::LogOfHRGrainBytes);
196   __ cbz(tmp, done);
197 
198   // crosses regions, storing NULL?
199 
200   __ cbz(new_val, done);
201 
202   // storing region crossing non-NULL, is card already dirty?
203 
204   ExternalAddress cardtable((address) ct->byte_map_base());
205   assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
206   const Register card_addr = tmp;
207 
208   __ lsr(card_addr, store_addr, CardTable::card_shift);
209 
210   // get the address of the card
211   __ load_byte_map_base(tmp2);
212   __ add(card_addr, card_addr, tmp2);
213   __ ldrb(tmp2, Address(card_addr));
214   __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val());
215   __ br(Assembler::EQ, done);
216 
217   assert((int)CardTable::dirty_card_val() == 0, "must be 0");
218 
219   __ membar(Assembler::StoreLoad);
220 
221   __ ldrb(tmp2, Address(card_addr));
222   __ cbzw(tmp2, done);
223 
224   // storing a region crossing, non-NULL oop, card is clean.
225   // dirty card and log.
226 
227   __ strb(zr, Address(card_addr));
228 
229   __ ldr(rscratch1, queue_index);
230   __ cbz(rscratch1, runtime);
231   __ sub(rscratch1, rscratch1, wordSize);
232   __ str(rscratch1, queue_index);
233 
234   __ ldr(tmp2, buffer);
235   __ str(card_addr, Address(tmp2, rscratch1));
236   __ b(done);
237 
238   __ bind(runtime);
239   // save the live input values
240   RegSet saved = RegSet::of(store_addr, new_val);
241   __ push(saved, sp);
242   __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
243   __ pop(saved, sp);
244 
245   __ bind(done);
246 }
247 
248 void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
249                                     Register dst, Address src, Register tmp1, Register tmp_thread) {
250   bool on_oop = type == T_OBJECT || type == T_ARRAY;
251   bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
252   bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
253   bool on_reference = on_weak || on_phantom;
254   ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
255   if (on_oop && on_reference) {
256     // Generate the G1 pre-barrier code to log the value of
257     // the referent field in an SATB buffer.
258     g1_write_barrier_pre(masm /* masm */,
259                          noreg /* obj */,
260                          dst /* pre_val */,
261                          rthread /* thread */,
262                          tmp1 /* tmp */,
263                          true /* tosca_live */,
264                          true /* expand_call */);
265   }
266 }
267 
268 void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
269                                          Address dst, Register val, Register tmp1, Register tmp2) {
270   // flatten object address if needed
271   if (dst.index() == noreg && dst.offset() == 0) {
272     if (dst.base() != r3) {
273       __ mov(r3, dst.base());
274     }
275   } else {
276     __ lea(r3, dst);
277   }
278 
279   g1_write_barrier_pre(masm,
280                        r3 /* obj */,
281                        tmp2 /* pre_val */,
282                        rthread /* thread */,
283                        tmp1  /* tmp */,
284                        val != noreg /* tosca_live */,
285                        false /* expand_call */);
286 
287   if (val == noreg) {
288     __ store_heap_oop_null(Address(r3, 0));
289   } else {
290     // G1 barrier needs uncompressed oop for region cross check.
291     Register new_val = val;
292     if (UseCompressedOops) {
293       new_val = rscratch2;
294       __ mov(new_val, val);
295     }
296     __ store_heap_oop(Address(r3, 0), val);
297     g1_write_barrier_post(masm,
298                           r3 /* store_adr */,
299                           new_val /* new_val */,
300                           rthread /* thread */,
301                           tmp1 /* tmp */,
302                           tmp2 /* tmp2 */);
303   }
304 
305 }
306 
307 #undef __