1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 class MultipleObject {
18     Object inner;
19     Object inner2;
20 
21     static Object inner_static;
22 }
23 
24 public class Main {
main(String[] args)25     public static void main(String[] args) throws Error {
26         // Several sets, same receiver.
27         $noinline$testInstanceFieldSets(new Main(), new Object(), new Object(), new Object());
28         $noinline$testStaticFieldSets(new Object(), new Object(), new Object());
29         // Object ArraySets can throw since they need a type check so we cannot perform the
30         // optimization.
31         $noinline$testArraySets(new Object[3], new Object(), new Object(), new Object());
32         // If we are swapping elements in the array, no need for a type check.
33         $noinline$testSwapArray(new Object[3]);
34         // If the array and the values have the same RTI, no need for a type check.
35         $noinline$testArraySetsSameRTI();
36 
37         // We cannot rely on `null` sets to perform the optimization.
38         $noinline$testNullInstanceFieldSets(new Main(), new Object());
39         $noinline$testNullStaticFieldSets(new Object());
40         $noinline$testNullArraySets(new Object[3], new Object());
41 
42         // Several sets, multiple receivers. (set obj1, obj2, obj1 and see that the card of obj1
43         // gets eliminated)
44         $noinline$testInstanceFieldSetsMultipleReceivers(
45                 new Main(), new Object(), new Object(), new Object());
46         $noinline$testStaticFieldSetsMultipleReceivers(new Object(), new Object(), new Object());
47         $noinline$testArraySetsMultipleReceiversSameRTI();
48 
49         // The write barrier elimination optimization is blocked by invokes, suspend checks, and
50         // instructions that can throw.
51         $noinline$testInstanceFieldSetsBlocked(
52                 new Main(), new Object(), new Object(), new Object());
53         $noinline$testStaticFieldSetsBlocked(new Main(), new Object(), new Object(), new Object());
54         $noinline$testArraySetsSameRTIBlocked(new Main());
55     }
56 
57     /// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
58     /// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:EmitBeingReliedOn
59     /// CHECK: ; card_table
60     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:DontEmit
61     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
$noinline$testInstanceFieldSets(Main m, Object o, Object o2, Object o3)62     private static Main $noinline$testInstanceFieldSets(Main m, Object o, Object o2, Object o3) {
63         m.inner = o;
64         m.inner2 = o2;
65         m.inner3 = o3;
66         return m;
67     }
68 
69     /// CHECK-START: void Main.$noinline$testStaticFieldSets(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
70     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitBeingReliedOn
71     /// CHECK: ; card_table
72     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:DontEmit
73     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
$noinline$testStaticFieldSets(Object o, Object o2, Object o3)74     private static void $noinline$testStaticFieldSets(Object o, Object o2, Object o3) {
75         inner_static = o;
76         inner_static2 = o2;
77         inner_static3 = o3;
78     }
79 
80     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySets(java.lang.Object[], java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
81     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNotBeingReliedOn
82     /// CHECK: ; card_table
83     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNotBeingReliedOn
84     /// CHECK: ; card_table
85     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNotBeingReliedOn
86     /// CHECK: ; card_table
$noinline$testArraySets( Object[] arr, Object o, Object o2, Object o3)87     private static java.lang.Object[] $noinline$testArraySets(
88             Object[] arr, Object o, Object o2, Object o3) {
89         arr[0] = o;
90         arr[1] = o2;
91         arr[2] = o3;
92         return arr;
93     }
94 
95     /// CHECK-START: java.lang.Object[] Main.$noinline$testSwapArray(java.lang.Object[]) disassembly (after)
96     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitBeingReliedOn
97     /// CHECK: ; card_table
98     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
99     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
$noinline$testSwapArray(Object[] arr)100     private static java.lang.Object[] $noinline$testSwapArray(Object[] arr) {
101         arr[0] = arr[1];
102         arr[1] = arr[2];
103         arr[2] = arr[0];
104         return arr;
105     }
106 
107     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTI() disassembly (after)
108     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitBeingReliedOn
109     /// CHECK: ; card_table
110     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
111     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
$noinline$testArraySetsSameRTI()112     private static java.lang.Object[] $noinline$testArraySetsSameRTI() {
113         Object[] arr = new Object[3];
114         arr[0] = inner_static;
115         arr[1] = inner_static2;
116         arr[2] = inner_static3;
117         return arr;
118     }
119 
120     /// CHECK-START: Main Main.$noinline$testNullInstanceFieldSets(Main, java.lang.Object) disassembly (after)
121     /// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:DontEmit
122     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
123     /// CHECK: ; card_table
124     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
$noinline$testNullInstanceFieldSets(Main m, Object o)125     private static Main $noinline$testNullInstanceFieldSets(Main m, Object o) {
126         m.inner = null;
127         m.inner2 = o;
128         m.inner3 = null;
129         return m;
130     }
131 
132     /// CHECK-START: void Main.$noinline$testNullStaticFieldSets(java.lang.Object) disassembly (after)
133     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:DontEmit
134     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
135     /// CHECK: ; card_table
136     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
$noinline$testNullStaticFieldSets(Object o)137     private static void $noinline$testNullStaticFieldSets(Object o) {
138         inner_static = null;
139         inner_static2 = o;
140         inner_static3 = null;
141     }
142 
143     /// CHECK-START: java.lang.Object[] Main.$noinline$testNullArraySets(java.lang.Object[], java.lang.Object) disassembly (after)
144     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
145     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNotBeingReliedOn
146     /// CHECK: ; card_table
147     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
$noinline$testNullArraySets(Object[] arr, Object o)148     private static Object[] $noinline$testNullArraySets(Object[] arr, Object o) {
149         arr[0] = null;
150         arr[1] = o;
151         arr[2] = null;
152         return arr;
153     }
154 
155     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsMultipleReceivers(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
156     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitBeingReliedOn
157     /// CHECK: ; card_table
158     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
159     /// CHECK: ; card_table
160     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner2 field_type:Reference write_barrier_kind:DontEmit
$noinline$testInstanceFieldSetsMultipleReceivers( Main m, Object o, Object o2, Object o3)161     private static Main $noinline$testInstanceFieldSetsMultipleReceivers(
162             Main m, Object o, Object o2, Object o3) throws Error {
163         m.mo = new MultipleObject();
164         m.mo2 = new MultipleObject();
165 
166         m.mo.inner = o;
167         // This card table for `m.mo2` can't me removed. Note that in `m.mo2 = new
168         // MultipleObject();` above the receiver is `m`, not `m.mo2.
169         m.mo2.inner = o2;
170         // This card table for `m.mo` can me removed.
171         m.mo.inner2 = o3;
172         return m;
173     }
174 
175     /// CHECK-START: void Main.$noinline$testStaticFieldSetsMultipleReceivers(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
176     /// CHECK: StaticFieldSet field_name:MultipleObject.inner_static field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
177     /// CHECK: ; card_table
178     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitBeingReliedOn
179     /// CHECK: ; card_table
180     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
$noinline$testStaticFieldSetsMultipleReceivers( Object o, Object o2, Object o3)181     private static void $noinline$testStaticFieldSetsMultipleReceivers(
182             Object o, Object o2, Object o3) {
183         MultipleObject.inner_static = o;
184         inner_static2 = o2;
185         inner_static3 = o3;
186     }
187 
188     /// CHECK-START: java.lang.Object[][] Main.$noinline$testArraySetsMultipleReceiversSameRTI() disassembly (after)
189     // Initializing the values
190     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitBeingReliedOn
191     /// CHECK: ; card_table
192     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNotBeingReliedOn
193     /// CHECK: ; card_table
194     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
195     // Setting the `array_of_arrays`.
196     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitBeingReliedOn
197     /// CHECK: ; card_table
198     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
$noinline$testArraySetsMultipleReceiversSameRTI()199     private static java.lang.Object[][] $noinline$testArraySetsMultipleReceiversSameRTI() {
200         Object[] arr = new Object[3];
201         Object[] other_arr = new Object[3];
202 
203         arr[0] = inner_static;
204         other_arr[1] = inner_static2;
205         arr[2] = inner_static3;
206 
207         // Return them so that LSE doesn't delete them
208         Object[][] array_of_arrays = {arr, other_arr};
209         return array_of_arrays;
210     }
211 
$noinline$emptyMethod()212     private static void $noinline$emptyMethod() {}
213 
214     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
215     /// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
216     /// CHECK: ; card_table
217     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
218     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
219     /// CHECK: ; card_table
220     /// CHECK: MonitorOperation kind:enter
221     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
222     /// CHECK: ; card_table
$noinline$testInstanceFieldSetsBlocked( Main m, Object o, Object o2, Object o3)223     private static Main $noinline$testInstanceFieldSetsBlocked(
224             Main m, Object o, Object o2, Object o3) {
225         m.inner = o;
226         $noinline$emptyMethod();
227         m.inner2 = o2;
228         synchronized (m) {
229             m.inner3 = o3;
230         }
231         return m;
232     }
233 
234     /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
235     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
236     /// CHECK: ; card_table
237     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
238     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
239     /// CHECK: ; card_table
240     /// CHECK: MonitorOperation kind:enter
241     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:EmitNotBeingReliedOn
242     /// CHECK: ; card_table
$noinline$testStaticFieldSetsBlocked( Main m, Object o, Object o2, Object o3)243     private static void $noinline$testStaticFieldSetsBlocked(
244             Main m, Object o, Object o2, Object o3) {
245         inner_static = o;
246         $noinline$emptyMethod();
247         inner_static2 = o2;
248         synchronized (m) {
249             inner_static3 = o3;
250         }
251     }
252 
253     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked(Main) disassembly (after)
254     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNotBeingReliedOn
255     /// CHECK: ; card_table
256     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
257     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNotBeingReliedOn
258     /// CHECK: ; card_table
259     /// CHECK: MonitorOperation kind:enter
260     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNotBeingReliedOn
261     /// CHECK: ; card_table
$noinline$testArraySetsSameRTIBlocked(Main m)262     private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked(Main m) {
263         Object[] arr = new Object[3];
264         arr[0] = inner_static;
265         $noinline$emptyMethod();
266         arr[1] = inner_static2;
267         synchronized (m) {
268             arr[2] = inner_static3;
269         }
270         return arr;
271     }
272 
273     Object inner;
274     Object inner2;
275     Object inner3;
276 
277     MultipleObject mo;
278     MultipleObject mo2;
279 
280     static Object inner_static;
281     static Object inner_static2;
282     static Object inner_static3;
283 }
284