• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Object(), new Object(), new Object());
54         $noinline$testArraySetsSameRTIBlocked();
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:EmitNoNullCheck
59     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:DontEmit
60     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
61 
62     /// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
63     /// CHECK: ; card_table
64     /// CHECK-NOT: ; card_table
$noinline$testInstanceFieldSets(Main m, Object o, Object o2, Object o3)65     private static Main $noinline$testInstanceFieldSets(Main m, Object o, Object o2, Object o3) {
66         m.inner = o;
67         m.inner2 = o2;
68         m.inner3 = o3;
69         return m;
70     }
71 
72     /// CHECK-START: void Main.$noinline$testStaticFieldSets(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
73     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitNoNullCheck
74     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:DontEmit
75     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
76 
77     /// CHECK-START: void Main.$noinline$testStaticFieldSets(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
78     /// CHECK: ; card_table
79     /// CHECK-NOT: ; card_table
$noinline$testStaticFieldSets(Object o, Object o2, Object o3)80     private static void $noinline$testStaticFieldSets(Object o, Object o2, Object o3) {
81         inner_static = o;
82         inner_static2 = o2;
83         inner_static3 = o3;
84     }
85 
86     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySets(java.lang.Object[], java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
87     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
88     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
89     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
90 
91     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySets(java.lang.Object[], java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
92     /// CHECK: ; card_table
93     /// CHECK: ; card_table
94     /// CHECK: ; card_table
95     /// CHECK-NOT: ; card_table
$noinline$testArraySets( Object[] arr, Object o, Object o2, Object o3)96     private static java.lang.Object[] $noinline$testArraySets(
97             Object[] arr, Object o, Object o2, Object o3) {
98         arr[0] = o;
99         arr[1] = o2;
100         arr[2] = o3;
101         return arr;
102     }
103 
104     /// CHECK-START: java.lang.Object[] Main.$noinline$testSwapArray(java.lang.Object[]) disassembly (after)
105     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
106     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
107     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
108 
109     /// CHECK-START: java.lang.Object[] Main.$noinline$testSwapArray(java.lang.Object[]) disassembly (after)
110     /// CHECK: ; card_table
111     /// CHECK-NOT: ; card_table
$noinline$testSwapArray(Object[] arr)112     private static java.lang.Object[] $noinline$testSwapArray(Object[] arr) {
113         arr[0] = arr[1];
114         arr[1] = arr[2];
115         arr[2] = arr[0];
116         return arr;
117     }
118 
119     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTI() disassembly (after)
120     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
121     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
122     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
123 
124     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTI() disassembly (after)
125     /// CHECK: ; card_table
126     /// CHECK-NOT: ; card_table
$noinline$testArraySetsSameRTI()127     private static java.lang.Object[] $noinline$testArraySetsSameRTI() {
128         Object[] arr = new Object[3];
129         arr[0] = inner_static;
130         arr[1] = inner_static2;
131         arr[2] = inner_static3;
132         return arr;
133     }
134 
135     /// CHECK-START: Main Main.$noinline$testNullInstanceFieldSets(Main, java.lang.Object) disassembly (after)
136     /// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:DontEmit
137     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitWithNullCheck
138     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
139 
140     /// CHECK-START: Main Main.$noinline$testNullInstanceFieldSets(Main, java.lang.Object) disassembly (after)
141     /// CHECK: ; card_table
142     /// CHECK-NOT: ; card_table
$noinline$testNullInstanceFieldSets(Main m, Object o)143     private static Main $noinline$testNullInstanceFieldSets(Main m, Object o) {
144         m.inner = null;
145         m.inner2 = o;
146         m.inner3 = null;
147         return m;
148     }
149 
150     /// CHECK-START: void Main.$noinline$testNullStaticFieldSets(java.lang.Object) disassembly (after)
151     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:DontEmit
152     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck
153     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
154 
155     /// CHECK-START: void Main.$noinline$testNullStaticFieldSets(java.lang.Object) disassembly (after)
156     /// CHECK: ; card_table
157     /// CHECK-NOT: ; card_table
$noinline$testNullStaticFieldSets(Object o)158     private static void $noinline$testNullStaticFieldSets(Object o) {
159         inner_static = null;
160         inner_static2 = o;
161         inner_static3 = null;
162     }
163 
164     /// CHECK-START: java.lang.Object[] Main.$noinline$testNullArraySets(java.lang.Object[], java.lang.Object) disassembly (after)
165     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
166     /// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
167     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
168 
169     /// CHECK-START: java.lang.Object[] Main.$noinline$testNullArraySets(java.lang.Object[], java.lang.Object) disassembly (after)
170     /// CHECK: ; card_table
171     /// CHECK-NOT: ; card_table
$noinline$testNullArraySets(Object[] arr, Object o)172     private static Object[] $noinline$testNullArraySets(Object[] arr, Object o) {
173         arr[0] = null;
174         arr[1] = o;
175         arr[2] = null;
176         return arr;
177     }
178 
179     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsMultipleReceivers(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
180     // There are two extra card_tables for the initialization of the MultipleObject.
181     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitNoNullCheck
182     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitWithNullCheck
183     /// CHECK: InstanceFieldSet field_name:MultipleObject.inner2 field_type:Reference write_barrier_kind:DontEmit
184 
185     // Each one of the two NewInstance instructions have their own `card_table` reference.
186     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsMultipleReceivers(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
187     /// CHECK: ; card_table
188     /// CHECK: ; card_table
189     /// CHECK: ; card_table
190     /// CHECK: ; card_table
191     /// CHECK-NOT: ; card_table
$noinline$testInstanceFieldSetsMultipleReceivers( Main m, Object o, Object o2, Object o3)192     private static Main $noinline$testInstanceFieldSetsMultipleReceivers(
193             Main m, Object o, Object o2, Object o3) throws Error {
194         m.mo = new MultipleObject();
195         m.mo2 = new MultipleObject();
196 
197         m.mo.inner = o;
198         // This card table for `m.mo2` can't me removed. Note that in `m.mo2 = new
199         // MultipleObject();` above the receiver is `m`, not `m.mo2.
200         m.mo2.inner = o2;
201         // This card table for `m.mo` can me removed.
202         m.mo.inner2 = o3;
203         return m;
204     }
205 
206     /// CHECK-START: void Main.$noinline$testStaticFieldSetsMultipleReceivers(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
207     /// CHECK: StaticFieldSet field_name:MultipleObject.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck
208     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitNoNullCheck
209     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
210 
211     /// CHECK-START: void Main.$noinline$testStaticFieldSetsMultipleReceivers(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
212     /// CHECK: ; card_table
213     /// CHECK: ; card_table
214     /// CHECK-NOT: ; card_table
$noinline$testStaticFieldSetsMultipleReceivers( Object o, Object o2, Object o3)215     private static void $noinline$testStaticFieldSetsMultipleReceivers(
216             Object o, Object o2, Object o3) {
217         MultipleObject.inner_static = o;
218         inner_static2 = o2;
219         inner_static3 = o3;
220     }
221 
222     /// CHECK-START: java.lang.Object[][] Main.$noinline$testArraySetsMultipleReceiversSameRTI() disassembly (after)
223     // Initializing the values
224     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
225     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
226     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
227     // Setting the `array_of_arrays`.
228     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
229     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
230 
231     /// CHECK-START: java.lang.Object[][] Main.$noinline$testArraySetsMultipleReceiversSameRTI() disassembly (after)
232     // Two array sets can't eliminate the write barrier
233     /// CHECK: ; card_table
234     /// CHECK: ; card_table
235     // One write barrier for the array of arrays' sets
236     /// CHECK: ; card_table
237     /// CHECK-NOT: ; card_table
$noinline$testArraySetsMultipleReceiversSameRTI()238     private static java.lang.Object[][] $noinline$testArraySetsMultipleReceiversSameRTI() {
239         Object[] arr = new Object[3];
240         Object[] other_arr = new Object[3];
241 
242         arr[0] = inner_static;
243         other_arr[1] = inner_static2;
244         arr[2] = inner_static3;
245 
246         // Return them so that LSE doesn't delete them
247         Object[][] array_of_arrays = {arr, other_arr};
248         return array_of_arrays;
249     }
250 
$noinline$emptyMethod()251     private static void $noinline$emptyMethod() {}
252 
253     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
254     /// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:EmitWithNullCheck
255     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
256     /// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitWithNullCheck
257     /// CHECK: MonitorOperation kind:enter
258     /// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:EmitWithNullCheck
259 
260     /// CHECK-START: Main Main.$noinline$testInstanceFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
261     /// CHECK: ; card_table
262     /// CHECK: ; card_table
263     /// CHECK: ; card_table
264     /// CHECK-NOT: ; card_table
$noinline$testInstanceFieldSetsBlocked( Main m, Object o, Object o2, Object o3)265     private static Main $noinline$testInstanceFieldSetsBlocked(
266             Main m, Object o, Object o2, Object o3) {
267         m.inner = o;
268         $noinline$emptyMethod();
269         m.inner2 = o2;
270         synchronized (m) {
271             m.inner3 = o3;
272         }
273         return m;
274     }
275 
276     /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
277     /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck
278     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
279     /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck
280     /// CHECK: MonitorOperation kind:enter
281     /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:EmitWithNullCheck
282 
283     /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
284     /// CHECK: ; card_table
285     /// CHECK: ; card_table
286     /// CHECK: ; card_table
287     /// CHECK-NOT: ; card_table
$noinline$testStaticFieldSetsBlocked(Object o, Object o2, Object o3)288     private static void $noinline$testStaticFieldSetsBlocked(Object o, Object o2, Object o3) {
289         inner_static = o;
290         $noinline$emptyMethod();
291         inner_static2 = o2;
292         Main m = new Main();
293         synchronized (m) {
294             inner_static3 = o3;
295         }
296     }
297 
298     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after)
299     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
300     /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
301     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
302     /// CHECK: MonitorOperation kind:enter
303     /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
304 
305     /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after)
306     /// CHECK: ; card_table
307     /// CHECK: ; card_table
308     /// CHECK: ; card_table
309     /// CHECK-NOT: ; card_table
$noinline$testArraySetsSameRTIBlocked()310     private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked() {
311         Object[] arr = new Object[3];
312         arr[0] = inner_static;
313         $noinline$emptyMethod();
314         arr[1] = inner_static2;
315         Main m = new Main();
316         synchronized (m) {
317             arr[2] = inner_static3;
318         }
319         return arr;
320     }
321 
322     Object inner;
323     Object inner2;
324     Object inner3;
325 
326     MultipleObject mo;
327     MultipleObject mo2;
328 
329     static Object inner_static;
330     static Object inner_static2;
331     static Object inner_static3;
332 }
333