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