1 /*
2  * Copyright (c) 2018, 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 "c1/c1_LIRAssembler.hpp"
26 #include "c1/c1_MacroAssembler.hpp"
27 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
28 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
29 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
30 
31 #define __ masm->masm()->
32 
emit_code(LIR_Assembler * masm)33 void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
34   NOT_LP64(assert(_addr->is_single_cpu(), "must be single");)
35   Register addr = _addr->is_single_cpu() ? _addr->as_register() : _addr->as_register_lo();
36   Register newval = _new_value->as_register();
37   Register cmpval = _cmp_value->as_register();
38   Register tmp1 = _tmp1->as_register();
39   Register tmp2 = _tmp2->as_register();
40   Register result = result_opr()->as_register();
41   assert(cmpval == rax, "wrong register");
42   assert(newval != NULL, "new val must be register");
43   assert(cmpval != newval, "cmp and new values must be in different registers");
44   assert(cmpval != addr, "cmp and addr must be in different registers");
45   assert(newval != addr, "new value and addr must be in different registers");
46 
47   // Apply IU barrier to newval.
48   ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), newval, tmp1);
49 
50 #ifdef _LP64
51   if (UseCompressedOops) {
52     __ encode_heap_oop(cmpval);
53     __ mov(rscratch1, newval);
54     __ encode_heap_oop(rscratch1);
55     newval = rscratch1;
56   }
57 #endif
58 
59   ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), result, Address(addr, 0), cmpval, newval, false, tmp1, tmp2);
60 }
61 
62 #undef __
63 
64 #ifdef ASSERT
65 #define __ gen->lir(__FILE__, __LINE__)->
66 #else
67 #define __ gen->lir()->
68 #endif
69 
atomic_cmpxchg_at_resolved(LIRAccess & access,LIRItem & cmp_value,LIRItem & new_value)70 LIR_Opr ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) {
71 
72   if (access.is_oop()) {
73     LIRGenerator* gen = access.gen();
74     if (ShenandoahSATBBarrier) {
75       pre_barrier(gen, access.access_emit_info(), access.decorators(), access.resolved_addr(),
76                   LIR_OprFact::illegalOpr /* pre_val */);
77     }
78     if (ShenandoahCASBarrier) {
79       cmp_value.load_item_force(FrameMap::rax_oop_opr);
80       new_value.load_item();
81 
82       LIR_Opr t1 = gen->new_register(T_OBJECT);
83       LIR_Opr t2 = gen->new_register(T_OBJECT);
84       LIR_Opr addr = access.resolved_addr()->as_address_ptr()->base();
85       LIR_Opr result = gen->new_register(T_INT);
86 
87       __ append(new LIR_OpShenandoahCompareAndSwap(addr, cmp_value.result(), new_value.result(), t1, t2, result));
88       return result;
89     }
90   }
91   return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value);
92 }
93 
atomic_xchg_at_resolved(LIRAccess & access,LIRItem & value)94 LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) {
95   LIRGenerator* gen = access.gen();
96   BasicType type = access.type();
97 
98   LIR_Opr result = gen->new_register(type);
99   value.load_item();
100   LIR_Opr value_opr = value.result();
101 
102   if (access.is_oop()) {
103     value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators());
104   }
105 
106   // Because we want a 2-arg form of xchg and xadd
107   __ move(value_opr, result);
108 
109   assert(type == T_INT || type == T_OBJECT || type == T_ARRAY LP64_ONLY( || type == T_LONG ), "unexpected type");
110   __ xchg(access.resolved_addr(), result, result, LIR_OprFact::illegalOpr);
111 
112   if (access.is_oop()) {
113     result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0));
114     LIR_Opr tmp = gen->new_register(type);
115     __ move(result, tmp);
116     result = tmp;
117     if (ShenandoahSATBBarrier) {
118       pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr,
119                   result /* pre_val */);
120     }
121   }
122 
123   return result;
124 }
125