1 | /* |
2 | * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. |
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/shared/barrierSet.hpp" |
26 | #include "gc/shenandoah/shenandoahForwarding.hpp" |
27 | #include "gc/shenandoah/shenandoahHeap.hpp" |
28 | #include "gc/shenandoah/shenandoahHeuristics.hpp" |
29 | #include "gc/shenandoah/shenandoahRuntime.hpp" |
30 | #include "gc/shenandoah/shenandoahThreadLocalData.hpp" |
31 | #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp" |
32 | #include "gc/shenandoah/c2/shenandoahSupport.hpp" |
33 | #include "opto/arraycopynode.hpp" |
34 | #include "opto/escape.hpp" |
35 | #include "opto/graphKit.hpp" |
36 | #include "opto/idealKit.hpp" |
37 | #include "opto/macro.hpp" |
38 | #include "opto/movenode.hpp" |
39 | #include "opto/narrowptrnode.hpp" |
40 | #include "opto/rootnode.hpp" |
41 | |
42 | ShenandoahBarrierSetC2* ShenandoahBarrierSetC2::bsc2() { |
43 | return reinterpret_cast<ShenandoahBarrierSetC2*>(BarrierSet::barrier_set()->barrier_set_c2()); |
44 | } |
45 | |
46 | ShenandoahBarrierSetC2State::ShenandoahBarrierSetC2State(Arena* comp_arena) |
47 | : _enqueue_barriers(new (comp_arena) GrowableArray<ShenandoahEnqueueBarrierNode*>(comp_arena, 8, 0, NULL)), |
48 | _load_reference_barriers(new (comp_arena) GrowableArray<ShenandoahLoadReferenceBarrierNode*>(comp_arena, 8, 0, NULL)) { |
49 | } |
50 | |
51 | int ShenandoahBarrierSetC2State::enqueue_barriers_count() const { |
52 | return _enqueue_barriers->length(); |
53 | } |
54 | |
55 | ShenandoahEnqueueBarrierNode* ShenandoahBarrierSetC2State::enqueue_barrier(int idx) const { |
56 | return _enqueue_barriers->at(idx); |
57 | } |
58 | |
59 | void ShenandoahBarrierSetC2State::add_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) { |
60 | assert(!_enqueue_barriers->contains(n), "duplicate entry in barrier list" ); |
61 | _enqueue_barriers->append(n); |
62 | } |
63 | |
64 | void ShenandoahBarrierSetC2State::remove_enqueue_barrier(ShenandoahEnqueueBarrierNode * n) { |
65 | if (_enqueue_barriers->contains(n)) { |
66 | _enqueue_barriers->remove(n); |
67 | } |
68 | } |
69 | |
70 | int ShenandoahBarrierSetC2State::load_reference_barriers_count() const { |
71 | return _load_reference_barriers->length(); |
72 | } |
73 | |
74 | ShenandoahLoadReferenceBarrierNode* ShenandoahBarrierSetC2State::load_reference_barrier(int idx) const { |
75 | return _load_reference_barriers->at(idx); |
76 | } |
77 | |
78 | void ShenandoahBarrierSetC2State::add_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) { |
79 | assert(!_load_reference_barriers->contains(n), "duplicate entry in barrier list" ); |
80 | _load_reference_barriers->append(n); |
81 | } |
82 | |
83 | void ShenandoahBarrierSetC2State::remove_load_reference_barrier(ShenandoahLoadReferenceBarrierNode * n) { |
84 | if (_load_reference_barriers->contains(n)) { |
85 | _load_reference_barriers->remove(n); |
86 | } |
87 | } |
88 | |
89 | Node* ShenandoahBarrierSetC2::shenandoah_storeval_barrier(GraphKit* kit, Node* obj) const { |
90 | if (ShenandoahStoreValEnqueueBarrier) { |
91 | obj = shenandoah_enqueue_barrier(kit, obj); |
92 | } |
93 | return obj; |
94 | } |
95 | |
96 | #define __ kit-> |
97 | |
98 | bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr, |
99 | BasicType bt, uint adr_idx) const { |
100 | intptr_t offset = 0; |
101 | Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset); |
102 | AllocateNode* alloc = AllocateNode::Ideal_allocation(base, phase); |
103 | |
104 | if (offset == Type::OffsetBot) { |
105 | return false; // cannot unalias unless there are precise offsets |
106 | } |
107 | |
108 | if (alloc == NULL) { |
109 | return false; // No allocation found |
110 | } |
111 | |
112 | intptr_t size_in_bytes = type2aelembytes(bt); |
113 | |
114 | Node* mem = __ memory(adr_idx); // start searching here... |
115 | |
116 | for (int cnt = 0; cnt < 50; cnt++) { |
117 | |
118 | if (mem->is_Store()) { |
119 | |
120 | Node* st_adr = mem->in(MemNode::Address); |
121 | intptr_t st_offset = 0; |
122 | Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset); |
123 | |
124 | if (st_base == NULL) { |
125 | break; // inscrutable pointer |
126 | } |
127 | |
128 | // Break we have found a store with same base and offset as ours so break |
129 | if (st_base == base && st_offset == offset) { |
130 | break; |
131 | } |
132 | |
133 | if (st_offset != offset && st_offset != Type::OffsetBot) { |
134 | const int MAX_STORE = BytesPerLong; |
135 | if (st_offset >= offset + size_in_bytes || |
136 | st_offset <= offset - MAX_STORE || |
137 | st_offset <= offset - mem->as_Store()->memory_size()) { |
138 | // Success: The offsets are provably independent. |
139 | // (You may ask, why not just test st_offset != offset and be done? |
140 | // The answer is that stores of different sizes can co-exist |
141 | // in the same sequence of RawMem effects. We sometimes initialize |
142 | // a whole 'tile' of array elements with a single jint or jlong.) |
143 | mem = mem->in(MemNode::Memory); |
144 | continue; // advance through independent store memory |
145 | } |
146 | } |
147 | |
148 | if (st_base != base |
149 | && MemNode::detect_ptr_independence(base, alloc, st_base, |
150 | AllocateNode::Ideal_allocation(st_base, phase), |
151 | phase)) { |
152 | // Success: The bases are provably independent. |
153 | mem = mem->in(MemNode::Memory); |
154 | continue; // advance through independent store memory |
155 | } |
156 | } else if (mem->is_Proj() && mem->in(0)->is_Initialize()) { |
157 | |
158 | InitializeNode* st_init = mem->in(0)->as_Initialize(); |
159 | AllocateNode* st_alloc = st_init->allocation(); |
160 | |
161 | // Make sure that we are looking at the same allocation site. |
162 | // The alloc variable is guaranteed to not be null here from earlier check. |
163 | if (alloc == st_alloc) { |
164 | // Check that the initialization is storing NULL so that no previous store |
165 | // has been moved up and directly write a reference |
166 | Node* captured_store = st_init->find_captured_store(offset, |
167 | type2aelembytes(T_OBJECT), |
168 | phase); |
169 | if (captured_store == NULL || captured_store == st_init->zero_memory()) { |
170 | return true; |
171 | } |
172 | } |
173 | } |
174 | |
175 | // Unless there is an explicit 'continue', we must bail out here, |
176 | // because 'mem' is an inscrutable memory state (e.g., a call). |
177 | break; |
178 | } |
179 | |
180 | return false; |
181 | } |
182 | |
183 | #undef __ |
184 | #define __ ideal. |
185 | |
186 | void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit, |
187 | bool do_load, |
188 | Node* obj, |
189 | Node* adr, |
190 | uint alias_idx, |
191 | Node* val, |
192 | const TypeOopPtr* val_type, |
193 | Node* pre_val, |
194 | BasicType bt) const { |
195 | // Some sanity checks |
196 | // Note: val is unused in this routine. |
197 | |
198 | if (do_load) { |
199 | // We need to generate the load of the previous value |
200 | assert(obj != NULL, "must have a base" ); |
201 | assert(adr != NULL, "where are loading from?" ); |
202 | assert(pre_val == NULL, "loaded already?" ); |
203 | assert(val_type != NULL, "need a type" ); |
204 | |
205 | if (ReduceInitialCardMarks |
206 | && satb_can_remove_pre_barrier(kit, &kit->gvn(), adr, bt, alias_idx)) { |
207 | return; |
208 | } |
209 | |
210 | } else { |
211 | // In this case both val_type and alias_idx are unused. |
212 | assert(pre_val != NULL, "must be loaded already" ); |
213 | // Nothing to be done if pre_val is null. |
214 | if (pre_val->bottom_type() == TypePtr::NULL_PTR) return; |
215 | assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here" ); |
216 | } |
217 | assert(bt == T_OBJECT, "or we shouldn't be here" ); |
218 | |
219 | IdealKit ideal(kit, true); |
220 | |
221 | Node* tls = __ thread(); // ThreadLocalStorage |
222 | |
223 | Node* no_base = __ top(); |
224 | Node* zero = __ ConI(0); |
225 | Node* zeroX = __ ConX(0); |
226 | |
227 | float likely = PROB_LIKELY(0.999); |
228 | float unlikely = PROB_UNLIKELY(0.999); |
229 | |
230 | // Offsets into the thread |
231 | const int index_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()); |
232 | const int buffer_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()); |
233 | |
234 | // Now the actual pointers into the thread |
235 | Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset)); |
236 | Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); |
237 | |
238 | // Now some of the values |
239 | Node* marking; |
240 | Node* gc_state = __ AddP(no_base, tls, __ ConX(in_bytes(ShenandoahThreadLocalData::gc_state_offset()))); |
241 | Node* ld = __ load(__ ctrl(), gc_state, TypeInt::BYTE, T_BYTE, Compile::AliasIdxRaw); |
242 | marking = __ AndI(ld, __ ConI(ShenandoahHeap::MARKING)); |
243 | assert(ShenandoahBarrierC2Support::is_gc_state_load(ld), "Should match the shape" ); |
244 | |
245 | // if (!marking) |
246 | __ if_then(marking, BoolTest::ne, zero, unlikely); { |
247 | BasicType index_bt = TypeX_X->basic_type(); |
248 | assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size." ); |
249 | Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); |
250 | |
251 | if (do_load) { |
252 | // load original value |
253 | // alias_idx correct?? |
254 | pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx); |
255 | } |
256 | |
257 | // if (pre_val != NULL) |
258 | __ if_then(pre_val, BoolTest::ne, kit->null()); { |
259 | Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); |
260 | |
261 | // is the queue for this thread full? |
262 | __ if_then(index, BoolTest::ne, zeroX, likely); { |
263 | |
264 | // decrement the index |
265 | Node* next_index = kit->gvn().transform(new SubXNode(index, __ ConX(sizeof(intptr_t)))); |
266 | |
267 | // Now get the buffer location we will log the previous value into and store it |
268 | Node *log_addr = __ AddP(no_base, buffer, next_index); |
269 | __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw, MemNode::unordered); |
270 | // update the index |
271 | __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw, MemNode::unordered); |
272 | |
273 | } __ else_(); { |
274 | |
275 | // logging buffer is full, call the runtime |
276 | const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type(); |
277 | __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), "shenandoah_wb_pre" , pre_val, tls); |
278 | } __ end_if(); // (!index) |
279 | } __ end_if(); // (pre_val != NULL) |
280 | } __ end_if(); // (!marking) |
281 | |
282 | // Final sync IdealKit and GraphKit. |
283 | kit->final_sync(ideal); |
284 | |
285 | if (ShenandoahSATBBarrier && adr != NULL) { |
286 | Node* c = kit->control(); |
287 | Node* call = c->in(1)->in(1)->in(1)->in(0); |
288 | assert(is_shenandoah_wb_pre_call(call), "shenandoah_wb_pre call expected" ); |
289 | call->add_req(adr); |
290 | } |
291 | } |
292 | |
293 | bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) { |
294 | return call->is_CallLeaf() && |
295 | call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry); |
296 | } |
297 | |
298 | bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { |
299 | return call->is_CallLeaf() && |
300 | call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_JRT); |
301 | } |
302 | |
303 | bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) { |
304 | if (n->Opcode() != Op_If) { |
305 | return false; |
306 | } |
307 | |
308 | Node* bol = n->in(1); |
309 | assert(bol->is_Bool(), "" ); |
310 | Node* cmpx = bol->in(1); |
311 | if (bol->as_Bool()->_test._test == BoolTest::ne && |
312 | cmpx->is_Cmp() && cmpx->in(2) == phase->intcon(0) && |
313 | is_shenandoah_state_load(cmpx->in(1)->in(1)) && |
314 | cmpx->in(1)->in(2)->is_Con() && |
315 | cmpx->in(1)->in(2) == phase->intcon(ShenandoahHeap::MARKING)) { |
316 | return true; |
317 | } |
318 | |
319 | return false; |
320 | } |
321 | |
322 | bool ShenandoahBarrierSetC2::is_shenandoah_state_load(Node* n) { |
323 | if (!n->is_Load()) return false; |
324 | const int state_offset = in_bytes(ShenandoahThreadLocalData::gc_state_offset()); |
325 | return n->in(2)->is_AddP() && n->in(2)->in(2)->Opcode() == Op_ThreadLocal |
326 | && n->in(2)->in(3)->is_Con() |
327 | && n->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == state_offset; |
328 | } |
329 | |
330 | void ShenandoahBarrierSetC2::shenandoah_write_barrier_pre(GraphKit* kit, |
331 | bool do_load, |
332 | Node* obj, |
333 | Node* adr, |
334 | uint alias_idx, |
335 | Node* val, |
336 | const TypeOopPtr* val_type, |
337 | Node* pre_val, |
338 | BasicType bt) const { |
339 | if (ShenandoahSATBBarrier) { |
340 | IdealKit ideal(kit); |
341 | kit->sync_kit(ideal); |
342 | |
343 | satb_write_barrier_pre(kit, do_load, obj, adr, alias_idx, val, val_type, pre_val, bt); |
344 | |
345 | ideal.sync_kit(kit); |
346 | kit->final_sync(ideal); |
347 | } |
348 | } |
349 | |
350 | Node* ShenandoahBarrierSetC2::shenandoah_enqueue_barrier(GraphKit* kit, Node* pre_val) const { |
351 | return kit->gvn().transform(new ShenandoahEnqueueBarrierNode(pre_val)); |
352 | } |
353 | |
354 | // Helper that guards and inserts a pre-barrier. |
355 | void ShenandoahBarrierSetC2::insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, |
356 | Node* pre_val, bool need_mem_bar) const { |
357 | // We could be accessing the referent field of a reference object. If so, when G1 |
358 | // is enabled, we need to log the value in the referent field in an SATB buffer. |
359 | // This routine performs some compile time filters and generates suitable |
360 | // runtime filters that guard the pre-barrier code. |
361 | // Also add memory barrier for non volatile load from the referent field |
362 | // to prevent commoning of loads across safepoint. |
363 | |
364 | // Some compile time checks. |
365 | |
366 | // If offset is a constant, is it java_lang_ref_Reference::_reference_offset? |
367 | const TypeX* otype = offset->find_intptr_t_type(); |
368 | if (otype != NULL && otype->is_con() && |
369 | otype->get_con() != java_lang_ref_Reference::referent_offset) { |
370 | // Constant offset but not the reference_offset so just return |
371 | return; |
372 | } |
373 | |
374 | // We only need to generate the runtime guards for instances. |
375 | const TypeOopPtr* btype = base_oop->bottom_type()->isa_oopptr(); |
376 | if (btype != NULL) { |
377 | if (btype->isa_aryptr()) { |
378 | // Array type so nothing to do |
379 | return; |
380 | } |
381 | |
382 | const TypeInstPtr* itype = btype->isa_instptr(); |
383 | if (itype != NULL) { |
384 | // Can the klass of base_oop be statically determined to be |
385 | // _not_ a sub-class of Reference and _not_ Object? |
386 | ciKlass* klass = itype->klass(); |
387 | if ( klass->is_loaded() && |
388 | !klass->is_subtype_of(kit->env()->Reference_klass()) && |
389 | !kit->env()->Object_klass()->is_subtype_of(klass)) { |
390 | return; |
391 | } |
392 | } |
393 | } |
394 | |
395 | // The compile time filters did not reject base_oop/offset so |
396 | // we need to generate the following runtime filters |
397 | // |
398 | // if (offset == java_lang_ref_Reference::_reference_offset) { |
399 | // if (instance_of(base, java.lang.ref.Reference)) { |
400 | // pre_barrier(_, pre_val, ...); |
401 | // } |
402 | // } |
403 | |
404 | float likely = PROB_LIKELY( 0.999); |
405 | float unlikely = PROB_UNLIKELY(0.999); |
406 | |
407 | IdealKit ideal(kit); |
408 | |
409 | Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset); |
410 | |
411 | __ if_then(offset, BoolTest::eq, referent_off, unlikely); { |
412 | // Update graphKit memory and control from IdealKit. |
413 | kit->sync_kit(ideal); |
414 | |
415 | Node* ref_klass_con = kit->makecon(TypeKlassPtr::make(kit->env()->Reference_klass())); |
416 | Node* is_instof = kit->gen_instanceof(base_oop, ref_klass_con); |
417 | |
418 | // Update IdealKit memory and control from graphKit. |
419 | __ sync_kit(kit); |
420 | |
421 | Node* one = __ ConI(1); |
422 | // is_instof == 0 if base_oop == NULL |
423 | __ if_then(is_instof, BoolTest::eq, one, unlikely); { |
424 | |
425 | // Update graphKit from IdeakKit. |
426 | kit->sync_kit(ideal); |
427 | |
428 | // Use the pre-barrier to record the value in the referent field |
429 | satb_write_barrier_pre(kit, false /* do_load */, |
430 | NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */, |
431 | pre_val /* pre_val */, |
432 | T_OBJECT); |
433 | if (need_mem_bar) { |
434 | // Add memory barrier to prevent commoning reads from this field |
435 | // across safepoint since GC can change its value. |
436 | kit->insert_mem_bar(Op_MemBarCPUOrder); |
437 | } |
438 | // Update IdealKit from graphKit. |
439 | __ sync_kit(kit); |
440 | |
441 | } __ end_if(); // _ref_type != ref_none |
442 | } __ end_if(); // offset == referent_offset |
443 | |
444 | // Final sync IdealKit and GraphKit. |
445 | kit->final_sync(ideal); |
446 | } |
447 | |
448 | #undef __ |
449 | |
450 | const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type() { |
451 | const Type **fields = TypeTuple::fields(2); |
452 | fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value |
453 | fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread |
454 | const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); |
455 | |
456 | // create result type (range) |
457 | fields = TypeTuple::fields(0); |
458 | const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); |
459 | |
460 | return TypeFunc::make(domain, range); |
461 | } |
462 | |
463 | const TypeFunc* ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type() { |
464 | const Type **fields = TypeTuple::fields(1); |
465 | fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value |
466 | const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields); |
467 | |
468 | // create result type (range) |
469 | fields = TypeTuple::fields(0); |
470 | const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); |
471 | |
472 | return TypeFunc::make(domain, range); |
473 | } |
474 | |
475 | const TypeFunc* ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type() { |
476 | const Type **fields = TypeTuple::fields(1); |
477 | fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value |
478 | const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields); |
479 | |
480 | // create result type (range) |
481 | fields = TypeTuple::fields(1); |
482 | fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; |
483 | const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+1, fields); |
484 | |
485 | return TypeFunc::make(domain, range); |
486 | } |
487 | |
488 | Node* ShenandoahBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { |
489 | DecoratorSet decorators = access.decorators(); |
490 | |
491 | const TypePtr* adr_type = access.addr().type(); |
492 | Node* adr = access.addr().node(); |
493 | |
494 | bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; |
495 | bool on_heap = (decorators & IN_HEAP) != 0; |
496 | |
497 | if (!access.is_oop() || (!on_heap && !anonymous)) { |
498 | return BarrierSetC2::store_at_resolved(access, val); |
499 | } |
500 | |
501 | if (access.is_parse_access()) { |
502 | C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access); |
503 | GraphKit* kit = parse_access.kit(); |
504 | |
505 | uint adr_idx = kit->C->get_alias_index(adr_type); |
506 | assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); |
507 | Node* value = val.node(); |
508 | value = shenandoah_storeval_barrier(kit, value); |
509 | val.set_node(value); |
510 | shenandoah_write_barrier_pre(kit, true /* do_load */, /*kit->control(),*/ access.base(), adr, adr_idx, val.node(), |
511 | static_cast<const TypeOopPtr*>(val.type()), NULL /* pre_val */, access.type()); |
512 | } else { |
513 | assert(access.is_opt_access(), "only for optimization passes" ); |
514 | assert(((decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0 || !ShenandoahSATBBarrier) && (decorators & C2_ARRAY_COPY) != 0, "unexpected caller of this code" ); |
515 | C2OptAccess& opt_access = static_cast<C2OptAccess&>(access); |
516 | PhaseGVN& gvn = opt_access.gvn(); |
517 | MergeMemNode* mm = opt_access.mem(); |
518 | |
519 | if (ShenandoahStoreValEnqueueBarrier) { |
520 | Node* enqueue = gvn.transform(new ShenandoahEnqueueBarrierNode(val.node())); |
521 | val.set_node(enqueue); |
522 | } |
523 | } |
524 | return BarrierSetC2::store_at_resolved(access, val); |
525 | } |
526 | |
527 | Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { |
528 | DecoratorSet decorators = access.decorators(); |
529 | |
530 | Node* adr = access.addr().node(); |
531 | Node* obj = access.base(); |
532 | |
533 | bool mismatched = (decorators & C2_MISMATCHED) != 0; |
534 | bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0; |
535 | bool on_heap = (decorators & IN_HEAP) != 0; |
536 | bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; |
537 | bool is_unordered = (decorators & MO_UNORDERED) != 0; |
538 | bool need_cpu_mem_bar = !is_unordered || mismatched || !on_heap; |
539 | |
540 | Node* top = Compile::current()->top(); |
541 | |
542 | Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top; |
543 | Node* load = BarrierSetC2::load_at_resolved(access, val_type); |
544 | |
545 | if (access.is_oop()) { |
546 | if (ShenandoahLoadRefBarrier) { |
547 | load = new ShenandoahLoadReferenceBarrierNode(NULL, load); |
548 | if (access.is_parse_access()) { |
549 | load = static_cast<C2ParseAccess &>(access).kit()->gvn().transform(load); |
550 | } else { |
551 | load = static_cast<C2OptAccess &>(access).gvn().transform(load); |
552 | } |
553 | } |
554 | } |
555 | |
556 | // If we are reading the value of the referent field of a Reference |
557 | // object (either by using Unsafe directly or through reflection) |
558 | // then, if SATB is enabled, we need to record the referent in an |
559 | // SATB log buffer using the pre-barrier mechanism. |
560 | // Also we need to add memory barrier to prevent commoning reads |
561 | // from this field across safepoint since GC can change its value. |
562 | bool need_read_barrier = ShenandoahKeepAliveBarrier && |
563 | (on_heap && (on_weak || (unknown && offset != top && obj != top))); |
564 | |
565 | if (!access.is_oop() || !need_read_barrier) { |
566 | return load; |
567 | } |
568 | |
569 | assert(access.is_parse_access(), "entry not supported at optimization time" ); |
570 | C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access); |
571 | GraphKit* kit = parse_access.kit(); |
572 | |
573 | if (on_weak) { |
574 | // Use the pre-barrier to record the value in the referent field |
575 | satb_write_barrier_pre(kit, false /* do_load */, |
576 | NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */, |
577 | load /* pre_val */, T_OBJECT); |
578 | // Add memory barrier to prevent commoning reads from this field |
579 | // across safepoint since GC can change its value. |
580 | kit->insert_mem_bar(Op_MemBarCPUOrder); |
581 | } else if (unknown) { |
582 | // We do not require a mem bar inside pre_barrier if need_mem_bar |
583 | // is set: the barriers would be emitted by us. |
584 | insert_pre_barrier(kit, obj, offset, load, !need_cpu_mem_bar); |
585 | } |
586 | |
587 | return load; |
588 | } |
589 | |
590 | Node* ShenandoahBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, |
591 | Node* new_val, const Type* value_type) const { |
592 | GraphKit* kit = access.kit(); |
593 | if (access.is_oop()) { |
594 | new_val = shenandoah_storeval_barrier(kit, new_val); |
595 | shenandoah_write_barrier_pre(kit, false /* do_load */, |
596 | NULL, NULL, max_juint, NULL, NULL, |
597 | expected_val /* pre_val */, T_OBJECT); |
598 | |
599 | MemNode::MemOrd mo = access.mem_node_mo(); |
600 | Node* mem = access.memory(); |
601 | Node* adr = access.addr().node(); |
602 | const TypePtr* adr_type = access.addr().type(); |
603 | Node* load_store = NULL; |
604 | |
605 | #ifdef _LP64 |
606 | if (adr->bottom_type()->is_ptr_to_narrowoop()) { |
607 | Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop())); |
608 | Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop())); |
609 | if (ShenandoahCASBarrier) { |
610 | load_store = kit->gvn().transform(new ShenandoahCompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo)); |
611 | } else { |
612 | load_store = kit->gvn().transform(new CompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo)); |
613 | } |
614 | } else |
615 | #endif |
616 | { |
617 | if (ShenandoahCASBarrier) { |
618 | load_store = kit->gvn().transform(new ShenandoahCompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo)); |
619 | } else { |
620 | load_store = kit->gvn().transform(new CompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo)); |
621 | } |
622 | } |
623 | |
624 | access.set_raw_access(load_store); |
625 | pin_atomic_op(access); |
626 | |
627 | #ifdef _LP64 |
628 | if (adr->bottom_type()->is_ptr_to_narrowoop()) { |
629 | load_store = kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type())); |
630 | } |
631 | #endif |
632 | load_store = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, load_store)); |
633 | return load_store; |
634 | } |
635 | return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); |
636 | } |
637 | |
638 | Node* ShenandoahBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, |
639 | Node* new_val, const Type* value_type) const { |
640 | GraphKit* kit = access.kit(); |
641 | if (access.is_oop()) { |
642 | new_val = shenandoah_storeval_barrier(kit, new_val); |
643 | shenandoah_write_barrier_pre(kit, false /* do_load */, |
644 | NULL, NULL, max_juint, NULL, NULL, |
645 | expected_val /* pre_val */, T_OBJECT); |
646 | DecoratorSet decorators = access.decorators(); |
647 | MemNode::MemOrd mo = access.mem_node_mo(); |
648 | Node* mem = access.memory(); |
649 | bool is_weak_cas = (decorators & C2_WEAK_CMPXCHG) != 0; |
650 | Node* load_store = NULL; |
651 | Node* adr = access.addr().node(); |
652 | #ifdef _LP64 |
653 | if (adr->bottom_type()->is_ptr_to_narrowoop()) { |
654 | Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop())); |
655 | Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop())); |
656 | if (ShenandoahCASBarrier) { |
657 | if (is_weak_cas) { |
658 | load_store = kit->gvn().transform(new ShenandoahWeakCompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo)); |
659 | } else { |
660 | load_store = kit->gvn().transform(new ShenandoahCompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo)); |
661 | } |
662 | } else { |
663 | if (is_weak_cas) { |
664 | load_store = kit->gvn().transform(new WeakCompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo)); |
665 | } else { |
666 | load_store = kit->gvn().transform(new CompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo)); |
667 | } |
668 | } |
669 | } else |
670 | #endif |
671 | { |
672 | if (ShenandoahCASBarrier) { |
673 | if (is_weak_cas) { |
674 | load_store = kit->gvn().transform(new ShenandoahWeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo)); |
675 | } else { |
676 | load_store = kit->gvn().transform(new ShenandoahCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo)); |
677 | } |
678 | } else { |
679 | if (is_weak_cas) { |
680 | load_store = kit->gvn().transform(new WeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo)); |
681 | } else { |
682 | load_store = kit->gvn().transform(new CompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo)); |
683 | } |
684 | } |
685 | } |
686 | access.set_raw_access(load_store); |
687 | pin_atomic_op(access); |
688 | return load_store; |
689 | } |
690 | return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); |
691 | } |
692 | |
693 | Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* val, const Type* value_type) const { |
694 | GraphKit* kit = access.kit(); |
695 | if (access.is_oop()) { |
696 | val = shenandoah_storeval_barrier(kit, val); |
697 | } |
698 | Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type); |
699 | if (access.is_oop()) { |
700 | result = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, result)); |
701 | shenandoah_write_barrier_pre(kit, false /* do_load */, |
702 | NULL, NULL, max_juint, NULL, NULL, |
703 | result /* pre_val */, T_OBJECT); |
704 | } |
705 | return result; |
706 | } |
707 | |
708 | void ShenandoahBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const { |
709 | assert(!src->is_AddP(), "unexpected input" ); |
710 | BarrierSetC2::clone(kit, src, dst, size, is_array); |
711 | } |
712 | |
713 | // Support for GC barriers emitted during parsing |
714 | bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { |
715 | if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true; |
716 | if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) { |
717 | return false; |
718 | } |
719 | CallLeafNode *call = node->as_CallLeaf(); |
720 | if (call->_name == NULL) { |
721 | return false; |
722 | } |
723 | |
724 | return strcmp(call->_name, "shenandoah_clone_barrier" ) == 0 || |
725 | strcmp(call->_name, "shenandoah_cas_obj" ) == 0 || |
726 | strcmp(call->_name, "shenandoah_wb_pre" ) == 0; |
727 | } |
728 | |
729 | Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const { |
730 | if (c->Opcode() == Op_ShenandoahLoadReferenceBarrier) { |
731 | return c->in(ShenandoahLoadReferenceBarrierNode::ValueIn); |
732 | } |
733 | if (c->Opcode() == Op_ShenandoahEnqueueBarrier) { |
734 | c = c->in(1); |
735 | } |
736 | return c; |
737 | } |
738 | |
739 | bool ShenandoahBarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const { |
740 | return !ShenandoahBarrierC2Support::expand(C, igvn); |
741 | } |
742 | |
743 | bool ShenandoahBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, VectorSet& visited, Node_Stack& nstack, Node_List& worklist) const { |
744 | if (mode == LoopOptsShenandoahExpand) { |
745 | assert(UseShenandoahGC, "only for shenandoah" ); |
746 | ShenandoahBarrierC2Support::pin_and_expand(phase); |
747 | return true; |
748 | } else if (mode == LoopOptsShenandoahPostExpand) { |
749 | assert(UseShenandoahGC, "only for shenandoah" ); |
750 | visited.Clear(); |
751 | ShenandoahBarrierC2Support::optimize_after_expansion(visited, nstack, worklist, phase); |
752 | return true; |
753 | } |
754 | return false; |
755 | } |
756 | |
757 | bool ShenandoahBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, ArrayCopyPhase phase) const { |
758 | bool is_oop = type == T_OBJECT || type == T_ARRAY; |
759 | if (!is_oop) { |
760 | return false; |
761 | } |
762 | if (tightly_coupled_alloc) { |
763 | if (phase == Optimization) { |
764 | return false; |
765 | } |
766 | return !is_clone; |
767 | } |
768 | if (phase == Optimization) { |
769 | return !ShenandoahStoreValEnqueueBarrier; |
770 | } |
771 | return true; |
772 | } |
773 | |
774 | bool ShenandoahBarrierSetC2::clone_needs_postbarrier(ArrayCopyNode *ac, PhaseIterGVN& igvn) { |
775 | Node* src = ac->in(ArrayCopyNode::Src); |
776 | const TypeOopPtr* src_type = igvn.type(src)->is_oopptr(); |
777 | if (src_type->isa_instptr() != NULL) { |
778 | ciInstanceKlass* ik = src_type->klass()->as_instance_klass(); |
779 | if ((src_type->klass_is_exact() || (!ik->is_interface() && !ik->has_subklass())) && !ik->has_injected_fields()) { |
780 | if (ik->has_object_fields()) { |
781 | return true; |
782 | } else { |
783 | if (!src_type->klass_is_exact()) { |
784 | igvn.C->dependencies()->assert_leaf_type(ik); |
785 | } |
786 | } |
787 | } else { |
788 | return true; |
789 | } |
790 | } else if (src_type->isa_aryptr()) { |
791 | BasicType src_elem = src_type->klass()->as_array_klass()->element_type()->basic_type(); |
792 | if (src_elem == T_OBJECT || src_elem == T_ARRAY) { |
793 | return true; |
794 | } |
795 | } else { |
796 | return true; |
797 | } |
798 | return false; |
799 | } |
800 | |
801 | void ShenandoahBarrierSetC2::clone_barrier_at_expansion(ArrayCopyNode* ac, Node* call, PhaseIterGVN& igvn) const { |
802 | assert(ac->is_clonebasic(), "no other kind of arraycopy here" ); |
803 | |
804 | if (!clone_needs_postbarrier(ac, igvn)) { |
805 | BarrierSetC2::clone_barrier_at_expansion(ac, call, igvn); |
806 | return; |
807 | } |
808 | |
809 | const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; |
810 | Node* c = new ProjNode(call,TypeFunc::Control); |
811 | c = igvn.transform(c); |
812 | Node* m = new ProjNode(call, TypeFunc::Memory); |
813 | m = igvn.transform(m); |
814 | |
815 | Node* dest = ac->in(ArrayCopyNode::Dest); |
816 | assert(dest->is_AddP(), "bad input" ); |
817 | Node* barrier_call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type(), |
818 | CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier), |
819 | "shenandoah_clone_barrier" , raw_adr_type); |
820 | barrier_call->init_req(TypeFunc::Control, c); |
821 | barrier_call->init_req(TypeFunc::I_O , igvn.C->top()); |
822 | barrier_call->init_req(TypeFunc::Memory , m); |
823 | barrier_call->init_req(TypeFunc::ReturnAdr, igvn.C->top()); |
824 | barrier_call->init_req(TypeFunc::FramePtr, igvn.C->top()); |
825 | barrier_call->init_req(TypeFunc::Parms+0, dest->in(AddPNode::Base)); |
826 | |
827 | barrier_call = igvn.transform(barrier_call); |
828 | c = new ProjNode(barrier_call,TypeFunc::Control); |
829 | c = igvn.transform(c); |
830 | m = new ProjNode(barrier_call, TypeFunc::Memory); |
831 | m = igvn.transform(m); |
832 | |
833 | Node* out_c = ac->proj_out(TypeFunc::Control); |
834 | Node* out_m = ac->proj_out(TypeFunc::Memory); |
835 | igvn.replace_node(out_c, c); |
836 | igvn.replace_node(out_m, m); |
837 | } |
838 | |
839 | |
840 | // Support for macro expanded GC barriers |
841 | void ShenandoahBarrierSetC2::register_potential_barrier_node(Node* node) const { |
842 | if (node->Opcode() == Op_ShenandoahEnqueueBarrier) { |
843 | state()->add_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node); |
844 | } |
845 | if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) { |
846 | state()->add_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node); |
847 | } |
848 | } |
849 | |
850 | void ShenandoahBarrierSetC2::unregister_potential_barrier_node(Node* node) const { |
851 | if (node->Opcode() == Op_ShenandoahEnqueueBarrier) { |
852 | state()->remove_enqueue_barrier((ShenandoahEnqueueBarrierNode*) node); |
853 | } |
854 | if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) { |
855 | state()->remove_load_reference_barrier((ShenandoahLoadReferenceBarrierNode*) node); |
856 | } |
857 | } |
858 | |
859 | void ShenandoahBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* n) const { |
860 | if (is_shenandoah_wb_pre_call(n)) { |
861 | shenandoah_eliminate_wb_pre(n, ¯o->igvn()); |
862 | } |
863 | } |
864 | |
865 | void ShenandoahBarrierSetC2::shenandoah_eliminate_wb_pre(Node* call, PhaseIterGVN* igvn) const { |
866 | assert(UseShenandoahGC && is_shenandoah_wb_pre_call(call), "" ); |
867 | Node* c = call->as_Call()->proj_out(TypeFunc::Control); |
868 | c = c->unique_ctrl_out(); |
869 | assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?" ); |
870 | c = c->unique_ctrl_out(); |
871 | assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?" ); |
872 | Node* iff = c->in(1)->is_IfProj() ? c->in(1)->in(0) : c->in(2)->in(0); |
873 | assert(iff->is_If(), "expect test" ); |
874 | if (!is_shenandoah_marking_if(igvn, iff)) { |
875 | c = c->unique_ctrl_out(); |
876 | assert(c->is_Region() && c->req() == 3, "where's the pre barrier control flow?" ); |
877 | iff = c->in(1)->is_IfProj() ? c->in(1)->in(0) : c->in(2)->in(0); |
878 | assert(is_shenandoah_marking_if(igvn, iff), "expect marking test" ); |
879 | } |
880 | Node* cmpx = iff->in(1)->in(1); |
881 | igvn->replace_node(cmpx, igvn->makecon(TypeInt::CC_EQ)); |
882 | igvn->rehash_node_delayed(call); |
883 | call->del_req(call->req()-1); |
884 | } |
885 | |
886 | void ShenandoahBarrierSetC2::enqueue_useful_gc_barrier(PhaseIterGVN* igvn, Node* node) const { |
887 | if (node->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(node)) { |
888 | igvn->add_users_to_worklist(node); |
889 | } |
890 | } |
891 | |
892 | void ShenandoahBarrierSetC2::eliminate_useless_gc_barriers(Unique_Node_List &useful, Compile* C) const { |
893 | for (uint i = 0; i < useful.size(); i++) { |
894 | Node* n = useful.at(i); |
895 | if (n->Opcode() == Op_AddP && ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(n)) { |
896 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
897 | C->record_for_igvn(n->fast_out(i)); |
898 | } |
899 | } |
900 | } |
901 | for (int i = state()->enqueue_barriers_count() - 1; i >= 0; i--) { |
902 | ShenandoahEnqueueBarrierNode* n = state()->enqueue_barrier(i); |
903 | if (!useful.member(n)) { |
904 | state()->remove_enqueue_barrier(n); |
905 | } |
906 | } |
907 | for (int i = state()->load_reference_barriers_count() - 1; i >= 0; i--) { |
908 | ShenandoahLoadReferenceBarrierNode* n = state()->load_reference_barrier(i); |
909 | if (!useful.member(n)) { |
910 | state()->remove_load_reference_barrier(n); |
911 | } |
912 | } |
913 | } |
914 | |
915 | void* ShenandoahBarrierSetC2::create_barrier_state(Arena* comp_arena) const { |
916 | return new(comp_arena) ShenandoahBarrierSetC2State(comp_arena); |
917 | } |
918 | |
919 | ShenandoahBarrierSetC2State* ShenandoahBarrierSetC2::state() const { |
920 | return reinterpret_cast<ShenandoahBarrierSetC2State*>(Compile::current()->barrier_set_state()); |
921 | } |
922 | |
923 | // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be |
924 | // expanded later, then now is the time to do so. |
925 | bool ShenandoahBarrierSetC2::expand_macro_nodes(PhaseMacroExpand* macro) const { return false; } |
926 | |
927 | #ifdef ASSERT |
928 | void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const { |
929 | if (ShenandoahVerifyOptoBarriers && phase == BarrierSetC2::BeforeMacroExpand) { |
930 | ShenandoahBarrierC2Support::verify(Compile::current()->root()); |
931 | } else if (phase == BarrierSetC2::BeforeCodeGen) { |
932 | // Verify G1 pre-barriers |
933 | const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()); |
934 | |
935 | ResourceArea *area = Thread::current()->resource_area(); |
936 | Unique_Node_List visited(area); |
937 | Node_List worklist(area); |
938 | // We're going to walk control flow backwards starting from the Root |
939 | worklist.push(compile->root()); |
940 | while (worklist.size() > 0) { |
941 | Node *x = worklist.pop(); |
942 | if (x == NULL || x == compile->top()) continue; |
943 | if (visited.member(x)) { |
944 | continue; |
945 | } else { |
946 | visited.push(x); |
947 | } |
948 | |
949 | if (x->is_Region()) { |
950 | for (uint i = 1; i < x->req(); i++) { |
951 | worklist.push(x->in(i)); |
952 | } |
953 | } else { |
954 | worklist.push(x->in(0)); |
955 | // We are looking for the pattern: |
956 | // /->ThreadLocal |
957 | // If->Bool->CmpI->LoadB->AddP->ConL(marking_offset) |
958 | // \->ConI(0) |
959 | // We want to verify that the If and the LoadB have the same control |
960 | // See GraphKit::g1_write_barrier_pre() |
961 | if (x->is_If()) { |
962 | IfNode *iff = x->as_If(); |
963 | if (iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) { |
964 | CmpNode *cmp = iff->in(1)->in(1)->as_Cmp(); |
965 | if (cmp->Opcode() == Op_CmpI && cmp->in(2)->is_Con() && cmp->in(2)->bottom_type()->is_int()->get_con() == 0 |
966 | && cmp->in(1)->is_Load()) { |
967 | LoadNode *load = cmp->in(1)->as_Load(); |
968 | if (load->Opcode() == Op_LoadB && load->in(2)->is_AddP() && load->in(2)->in(2)->Opcode() == Op_ThreadLocal |
969 | && load->in(2)->in(3)->is_Con() |
970 | && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == marking_offset) { |
971 | |
972 | Node *if_ctrl = iff->in(0); |
973 | Node *load_ctrl = load->in(0); |
974 | |
975 | if (if_ctrl != load_ctrl) { |
976 | // Skip possible CProj->NeverBranch in infinite loops |
977 | if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj) |
978 | && (if_ctrl->in(0)->is_MultiBranch() && if_ctrl->in(0)->Opcode() == Op_NeverBranch)) { |
979 | if_ctrl = if_ctrl->in(0)->in(0); |
980 | } |
981 | } |
982 | assert(load_ctrl != NULL && if_ctrl == load_ctrl, "controls must match" ); |
983 | } |
984 | } |
985 | } |
986 | } |
987 | } |
988 | } |
989 | } |
990 | } |
991 | #endif |
992 | |
993 | Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const { |
994 | if (is_shenandoah_wb_pre_call(n)) { |
995 | uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt(); |
996 | if (n->req() > cnt) { |
997 | Node* addp = n->in(cnt); |
998 | if (has_only_shenandoah_wb_pre_uses(addp)) { |
999 | n->del_req(cnt); |
1000 | if (can_reshape) { |
1001 | phase->is_IterGVN()->_worklist.push(addp); |
1002 | } |
1003 | return n; |
1004 | } |
1005 | } |
1006 | } |
1007 | if (n->Opcode() == Op_CmpP) { |
1008 | Node* in1 = n->in(1); |
1009 | Node* in2 = n->in(2); |
1010 | if (in1->bottom_type() == TypePtr::NULL_PTR) { |
1011 | in2 = step_over_gc_barrier(in2); |
1012 | } |
1013 | if (in2->bottom_type() == TypePtr::NULL_PTR) { |
1014 | in1 = step_over_gc_barrier(in1); |
1015 | } |
1016 | PhaseIterGVN* igvn = phase->is_IterGVN(); |
1017 | if (in1 != n->in(1)) { |
1018 | if (igvn != NULL) { |
1019 | n->set_req_X(1, in1, igvn); |
1020 | } else { |
1021 | n->set_req(1, in1); |
1022 | } |
1023 | assert(in2 == n->in(2), "only one change" ); |
1024 | return n; |
1025 | } |
1026 | if (in2 != n->in(2)) { |
1027 | if (igvn != NULL) { |
1028 | n->set_req_X(2, in2, igvn); |
1029 | } else { |
1030 | n->set_req(2, in2); |
1031 | } |
1032 | return n; |
1033 | } |
1034 | } else if (can_reshape && |
1035 | n->Opcode() == Op_If && |
1036 | ShenandoahBarrierC2Support::is_heap_stable_test(n) && |
1037 | n->in(0) != NULL) { |
1038 | Node* dom = n->in(0); |
1039 | Node* prev_dom = n; |
1040 | int op = n->Opcode(); |
1041 | int dist = 16; |
1042 | // Search up the dominator tree for another heap stable test |
1043 | while (dom->Opcode() != op || // Not same opcode? |
1044 | !ShenandoahBarrierC2Support::is_heap_stable_test(dom) || // Not same input 1? |
1045 | prev_dom->in(0) != dom) { // One path of test does not dominate? |
1046 | if (dist < 0) return NULL; |
1047 | |
1048 | dist--; |
1049 | prev_dom = dom; |
1050 | dom = IfNode::up_one_dom(dom); |
1051 | if (!dom) return NULL; |
1052 | } |
1053 | |
1054 | // Check that we did not follow a loop back to ourselves |
1055 | if (n == dom) { |
1056 | return NULL; |
1057 | } |
1058 | |
1059 | return n->as_If()->dominated_by(prev_dom, phase->is_IterGVN()); |
1060 | } |
1061 | |
1062 | return NULL; |
1063 | } |
1064 | |
1065 | bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) { |
1066 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
1067 | Node* u = n->fast_out(i); |
1068 | if (!is_shenandoah_wb_pre_call(u)) { |
1069 | return false; |
1070 | } |
1071 | } |
1072 | return n->outcnt() > 0; |
1073 | } |
1074 | |
1075 | bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode) const { |
1076 | switch (opcode) { |
1077 | case Op_CallLeaf: |
1078 | case Op_CallLeafNoFP: { |
1079 | assert (n->is_Call(), "" ); |
1080 | CallNode *call = n->as_Call(); |
1081 | if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) { |
1082 | uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt(); |
1083 | if (call->req() > cnt) { |
1084 | assert(call->req() == cnt + 1, "only one extra input" ); |
1085 | Node *addp = call->in(cnt); |
1086 | assert(!ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(addp), "useless address computation?" ); |
1087 | call->del_req(cnt); |
1088 | } |
1089 | } |
1090 | return false; |
1091 | } |
1092 | case Op_ShenandoahCompareAndSwapP: |
1093 | case Op_ShenandoahCompareAndSwapN: |
1094 | case Op_ShenandoahWeakCompareAndSwapN: |
1095 | case Op_ShenandoahWeakCompareAndSwapP: |
1096 | case Op_ShenandoahCompareAndExchangeP: |
1097 | case Op_ShenandoahCompareAndExchangeN: |
1098 | #ifdef ASSERT |
1099 | if( VerifyOptoOopOffsets ) { |
1100 | MemNode* mem = n->as_Mem(); |
1101 | // Check to see if address types have grounded out somehow. |
1102 | const TypeInstPtr *tp = mem->in(MemNode::Address)->bottom_type()->isa_instptr(); |
1103 | ciInstanceKlass *k = tp->klass()->as_instance_klass(); |
1104 | bool oop_offset_is_sane = k->contains_field_offset(tp->offset()); |
1105 | assert( !tp || oop_offset_is_sane, "" ); |
1106 | } |
1107 | #endif |
1108 | return true; |
1109 | case Op_ShenandoahLoadReferenceBarrier: |
1110 | assert(false, "should have been expanded already" ); |
1111 | return true; |
1112 | default: |
1113 | return false; |
1114 | } |
1115 | } |
1116 | |
1117 | bool ShenandoahBarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { |
1118 | switch (opcode) { |
1119 | case Op_ShenandoahCompareAndExchangeP: |
1120 | case Op_ShenandoahCompareAndExchangeN: |
1121 | conn_graph->add_objload_to_connection_graph(n, delayed_worklist); |
1122 | // fallthrough |
1123 | case Op_ShenandoahWeakCompareAndSwapP: |
1124 | case Op_ShenandoahWeakCompareAndSwapN: |
1125 | case Op_ShenandoahCompareAndSwapP: |
1126 | case Op_ShenandoahCompareAndSwapN: |
1127 | conn_graph->add_to_congraph_unsafe_access(n, opcode, delayed_worklist); |
1128 | return true; |
1129 | case Op_StoreP: { |
1130 | Node* adr = n->in(MemNode::Address); |
1131 | const Type* adr_type = gvn->type(adr); |
1132 | // Pointer stores in G1 barriers looks like unsafe access. |
1133 | // Ignore such stores to be able scalar replace non-escaping |
1134 | // allocations. |
1135 | if (adr_type->isa_rawptr() && adr->is_AddP()) { |
1136 | Node* base = conn_graph->get_addp_base(adr); |
1137 | if (base->Opcode() == Op_LoadP && |
1138 | base->in(MemNode::Address)->is_AddP()) { |
1139 | adr = base->in(MemNode::Address); |
1140 | Node* tls = conn_graph->get_addp_base(adr); |
1141 | if (tls->Opcode() == Op_ThreadLocal) { |
1142 | int offs = (int) gvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot); |
1143 | const int buf_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()); |
1144 | if (offs == buf_offset) { |
1145 | return true; // Pre barrier previous oop value store. |
1146 | } |
1147 | } |
1148 | } |
1149 | } |
1150 | return false; |
1151 | } |
1152 | case Op_ShenandoahEnqueueBarrier: |
1153 | conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist); |
1154 | break; |
1155 | case Op_ShenandoahLoadReferenceBarrier: |
1156 | conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), delayed_worklist); |
1157 | return true; |
1158 | default: |
1159 | // Nothing |
1160 | break; |
1161 | } |
1162 | return false; |
1163 | } |
1164 | |
1165 | bool ShenandoahBarrierSetC2::escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const { |
1166 | switch (opcode) { |
1167 | case Op_ShenandoahCompareAndExchangeP: |
1168 | case Op_ShenandoahCompareAndExchangeN: { |
1169 | Node *adr = n->in(MemNode::Address); |
1170 | conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, adr, NULL); |
1171 | // fallthrough |
1172 | } |
1173 | case Op_ShenandoahCompareAndSwapP: |
1174 | case Op_ShenandoahCompareAndSwapN: |
1175 | case Op_ShenandoahWeakCompareAndSwapP: |
1176 | case Op_ShenandoahWeakCompareAndSwapN: |
1177 | return conn_graph->add_final_edges_unsafe_access(n, opcode); |
1178 | case Op_ShenandoahEnqueueBarrier: |
1179 | conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL); |
1180 | return true; |
1181 | case Op_ShenandoahLoadReferenceBarrier: |
1182 | conn_graph->add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(ShenandoahLoadReferenceBarrierNode::ValueIn), NULL); |
1183 | return true; |
1184 | default: |
1185 | // Nothing |
1186 | break; |
1187 | } |
1188 | return false; |
1189 | } |
1190 | |
1191 | bool ShenandoahBarrierSetC2::escape_has_out_with_unsafe_object(Node* n) const { |
1192 | return n->has_out_with(Op_ShenandoahCompareAndExchangeP) || n->has_out_with(Op_ShenandoahCompareAndExchangeN) || |
1193 | n->has_out_with(Op_ShenandoahCompareAndSwapP, Op_ShenandoahCompareAndSwapN, Op_ShenandoahWeakCompareAndSwapP, Op_ShenandoahWeakCompareAndSwapN); |
1194 | |
1195 | } |
1196 | |
1197 | bool ShenandoahBarrierSetC2::escape_is_barrier_node(Node* n) const { |
1198 | return n->Opcode() == Op_ShenandoahLoadReferenceBarrier; |
1199 | } |
1200 | |
1201 | bool ShenandoahBarrierSetC2::matcher_find_shared_post_visit(Matcher* matcher, Node* n, uint opcode) const { |
1202 | switch (opcode) { |
1203 | case Op_ShenandoahCompareAndExchangeP: |
1204 | case Op_ShenandoahCompareAndExchangeN: |
1205 | case Op_ShenandoahWeakCompareAndSwapP: |
1206 | case Op_ShenandoahWeakCompareAndSwapN: |
1207 | case Op_ShenandoahCompareAndSwapP: |
1208 | case Op_ShenandoahCompareAndSwapN: { // Convert trinary to binary-tree |
1209 | Node* newval = n->in(MemNode::ValueIn); |
1210 | Node* oldval = n->in(LoadStoreConditionalNode::ExpectedIn); |
1211 | Node* pair = new BinaryNode(oldval, newval); |
1212 | n->set_req(MemNode::ValueIn,pair); |
1213 | n->del_req(LoadStoreConditionalNode::ExpectedIn); |
1214 | return true; |
1215 | } |
1216 | default: |
1217 | break; |
1218 | } |
1219 | return false; |
1220 | } |
1221 | |
1222 | bool ShenandoahBarrierSetC2::matcher_is_store_load_barrier(Node* x, uint xop) const { |
1223 | return xop == Op_ShenandoahCompareAndExchangeP || |
1224 | xop == Op_ShenandoahCompareAndExchangeN || |
1225 | xop == Op_ShenandoahWeakCompareAndSwapP || |
1226 | xop == Op_ShenandoahWeakCompareAndSwapN || |
1227 | xop == Op_ShenandoahCompareAndSwapN || |
1228 | xop == Op_ShenandoahCompareAndSwapP; |
1229 | } |
1230 | |