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