blob: 76fb05a2c02cd79e9487d083013acbd4fe8b92e1 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class MultipleObject {
Object inner;
Object inner2;
static Object inner_static;
}
public class Main {
public static void main(String[] args) throws Error {
// Several sets, same receiver.
$noinline$testInstanceFieldSets(new Main(), new Object(), new Object(), new Object());
$noinline$testStaticFieldSets(new Object(), new Object(), new Object());
// Object ArraySets can throw since they need a type check so we cannot perform the
// optimization.
$noinline$testArraySets(new Object[3], new Object(), new Object(), new Object());
// If we are swapping elements in the array, no need for a type check.
$noinline$testSwapArray(new Object[3]);
// If the array and the values have the same RTI, no need for a type check.
$noinline$testArraySetsSameRTI();
// We cannot rely on `null` sets to perform the optimization.
$noinline$testNullInstanceFieldSets(new Main(), new Object());
$noinline$testNullStaticFieldSets(new Object());
$noinline$testNullArraySets(new Object[3], new Object());
// Several sets, multiple receivers. (set obj1, obj2, obj1 and see that the card of obj1
// gets eliminated)
$noinline$testInstanceFieldSetsMultipleReceivers(
new Main(), new Object(), new Object(), new Object());
$noinline$testStaticFieldSetsMultipleReceivers(new Object(), new Object(), new Object());
$noinline$testArraySetsMultipleReceiversSameRTI();
// The write barrier elimination optimization is blocked by invokes, suspend checks, and
// instructions that can throw.
$noinline$testInstanceFieldSetsBlocked(
new Main(), new Object(), new Object(), new Object());
$noinline$testStaticFieldSetsBlocked(new Object(), new Object(), new Object());
$noinline$testArraySetsSameRTIBlocked();
}
/// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:EmitNoNullCheck
/// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:DontEmit
/// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
/// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static Main $noinline$testInstanceFieldSets(Main m, Object o, Object o2, Object o3) {
m.inner = o;
m.inner2 = o2;
m.inner3 = o3;
return m;
}
/// CHECK-START: void Main.$noinline$testStaticFieldSets(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitNoNullCheck
/// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:DontEmit
/// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
/// CHECK-START: void Main.$noinline$testStaticFieldSets(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static void $noinline$testStaticFieldSets(Object o, Object o2, Object o3) {
inner_static = o;
inner_static2 = o2;
inner_static3 = o3;
}
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySets(java.lang.Object[], java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySets(java.lang.Object[], java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static java.lang.Object[] $noinline$testArraySets(
Object[] arr, Object o, Object o2, Object o3) {
arr[0] = o;
arr[1] = o2;
arr[2] = o3;
return arr;
}
/// CHECK-START: java.lang.Object[] Main.$noinline$testSwapArray(java.lang.Object[]) disassembly (after)
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK-START: java.lang.Object[] Main.$noinline$testSwapArray(java.lang.Object[]) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static java.lang.Object[] $noinline$testSwapArray(Object[] arr) {
arr[0] = arr[1];
arr[1] = arr[2];
arr[2] = arr[0];
return arr;
}
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTI() disassembly (after)
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTI() disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static java.lang.Object[] $noinline$testArraySetsSameRTI() {
Object[] arr = new Object[3];
arr[0] = inner_static;
arr[1] = inner_static2;
arr[2] = inner_static3;
return arr;
}
/// CHECK-START: Main Main.$noinline$testNullInstanceFieldSets(Main, java.lang.Object) disassembly (after)
/// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:DontEmit
/// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:DontEmit
/// CHECK-START: Main Main.$noinline$testNullInstanceFieldSets(Main, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static Main $noinline$testNullInstanceFieldSets(Main m, Object o) {
m.inner = null;
m.inner2 = o;
m.inner3 = null;
return m;
}
/// CHECK-START: void Main.$noinline$testNullStaticFieldSets(java.lang.Object) disassembly (after)
/// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:DontEmit
/// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
/// CHECK-START: void Main.$noinline$testNullStaticFieldSets(java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static void $noinline$testNullStaticFieldSets(Object o) {
inner_static = null;
inner_static2 = o;
inner_static3 = null;
}
/// CHECK-START: java.lang.Object[] Main.$noinline$testNullArraySets(java.lang.Object[], java.lang.Object) disassembly (after)
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK: ArraySet needs_type_check:true can_trigger_gc:true write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK-START: java.lang.Object[] Main.$noinline$testNullArraySets(java.lang.Object[], java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static Object[] $noinline$testNullArraySets(Object[] arr, Object o) {
arr[0] = null;
arr[1] = o;
arr[2] = null;
return arr;
}
/// CHECK-START: Main Main.$noinline$testInstanceFieldSetsMultipleReceivers(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
// There are two extra card_tables for the initialization of the MultipleObject.
/// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitNoNullCheck
/// CHECK: InstanceFieldSet field_name:MultipleObject.inner field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: InstanceFieldSet field_name:MultipleObject.inner2 field_type:Reference write_barrier_kind:DontEmit
// Each one of the two NewInstance instructions have their own `card_table` reference.
/// CHECK-START: Main Main.$noinline$testInstanceFieldSetsMultipleReceivers(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static Main $noinline$testInstanceFieldSetsMultipleReceivers(
Main m, Object o, Object o2, Object o3) throws Error {
m.mo = new MultipleObject();
m.mo2 = new MultipleObject();
m.mo.inner = o;
// This card table for `m.mo2` can't me removed. Note that in `m.mo2 = new
// MultipleObject();` above the receiver is `m`, not `m.mo2.
m.mo2.inner = o2;
// This card table for `m.mo` can me removed.
m.mo.inner2 = o3;
return m;
}
/// CHECK-START: void Main.$noinline$testStaticFieldSetsMultipleReceivers(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: StaticFieldSet field_name:MultipleObject.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitNoNullCheck
/// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:DontEmit
/// CHECK-START: void Main.$noinline$testStaticFieldSetsMultipleReceivers(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static void $noinline$testStaticFieldSetsMultipleReceivers(
Object o, Object o2, Object o3) {
MultipleObject.inner_static = o;
inner_static2 = o2;
inner_static3 = o3;
}
/// CHECK-START: java.lang.Object[][] Main.$noinline$testArraySetsMultipleReceiversSameRTI() disassembly (after)
// Initializing the values
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
// Setting the `array_of_arrays`.
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:DontEmit
/// CHECK-START: java.lang.Object[][] Main.$noinline$testArraySetsMultipleReceiversSameRTI() disassembly (after)
// Two array sets can't eliminate the write barrier
/// CHECK: ; card_table
/// CHECK: ; card_table
// One write barrier for the array of arrays' sets
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static java.lang.Object[][] $noinline$testArraySetsMultipleReceiversSameRTI() {
Object[] arr = new Object[3];
Object[] other_arr = new Object[3];
arr[0] = inner_static;
other_arr[1] = inner_static2;
arr[2] = inner_static3;
// Return them so that LSE doesn't delete them
Object[][] array_of_arrays = {arr, other_arr};
return array_of_arrays;
}
private static void $noinline$emptyMethod() {}
/// CHECK-START: Main Main.$noinline$testInstanceFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: InstanceFieldSet field_name:Main.inner field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
/// CHECK: InstanceFieldSet field_name:Main.inner2 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: MonitorOperation kind:enter
/// CHECK: InstanceFieldSet field_name:Main.inner3 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK-START: Main Main.$noinline$testInstanceFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static Main $noinline$testInstanceFieldSetsBlocked(
Main m, Object o, Object o2, Object o3) {
m.inner = o;
$noinline$emptyMethod();
m.inner2 = o2;
synchronized (m) {
m.inner3 = o3;
}
return m;
}
/// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
/// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK: MonitorOperation kind:enter
/// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:EmitWithNullCheck
/// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static void $noinline$testStaticFieldSetsBlocked(Object o, Object o2, Object o3) {
inner_static = o;
$noinline$emptyMethod();
inner_static2 = o2;
Main m = new Main();
synchronized (m) {
inner_static3 = o3;
}
}
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after)
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK: MonitorOperation kind:enter
/// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck
/// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after)
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK: ; card_table
/// CHECK-NOT: ; card_table
private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked() {
Object[] arr = new Object[3];
arr[0] = inner_static;
$noinline$emptyMethod();
arr[1] = inner_static2;
Main m = new Main();
synchronized (m) {
arr[2] = inner_static3;
}
return arr;
}
Object inner;
Object inner2;
Object inner3;
MultipleObject mo;
MultipleObject mo2;
static Object inner_static;
static Object inner_static2;
static Object inner_static3;
}