xref: /aosp_15_r20/art/test/1004-checker-volatile-ref-load/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker class Foo {
18*795d594fSAndroid Build Coastguard Worker   volatile Object bar;
19*795d594fSAndroid Build Coastguard Worker }
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker public class Main {
22*795d594fSAndroid Build Coastguard Worker 
main(String[] args)23*795d594fSAndroid Build Coastguard Worker   public static void main(String[] args) {
24*795d594fSAndroid Build Coastguard Worker     Main main = new Main();
25*795d594fSAndroid Build Coastguard Worker     main.test();
26*795d594fSAndroid Build Coastguard Worker     System.out.println("passed");
27*795d594fSAndroid Build Coastguard Worker   }
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker   // Check that no explicit null check is emitted for the field load of volatile
30*795d594fSAndroid Build Coastguard Worker   // field `Foo.bar` before entering the Baker read barrier thunk.
31*795d594fSAndroid Build Coastguard Worker   //
32*795d594fSAndroid Build Coastguard Worker   // Note: We cannot check the ARM64 assembly code of the Baker read barrier
33*795d594fSAndroid Build Coastguard Worker   // thunk code, as it is not emitted in the CFG output.
34*795d594fSAndroid Build Coastguard Worker   //
35*795d594fSAndroid Build Coastguard Worker   /// CHECK-START-ARM64: void Main.test() disassembly (after)
36*795d594fSAndroid Build Coastguard Worker   /// CHECK:       <<Foo:l\d+>> InstanceFieldGet [{{l\d+}}] field_name:Main.foo field_type:Reference loop:<<Loop:B\d+>>
37*795d594fSAndroid Build Coastguard Worker   /// CHECK:       NullCheck [<<Foo>>] dex_pc:<<PC:\d+>> loop:<<Loop>>
38*795d594fSAndroid Build Coastguard Worker   /// CHECK-NEXT:  InstanceFieldGet [<<Foo>>] dex_pc:<<PC>> field_name:Foo.bar field_type:Reference loop:<<Loop>>
39*795d594fSAndroid Build Coastguard Worker   /// CHECK-IF: readBarrierType('baker')
40*795d594fSAndroid Build Coastguard Worker   ///   CHECK-NEXT:      add w<<BaseRegNum:\d+>>, {{w\d+}}, #0x8 (8)
41*795d594fSAndroid Build Coastguard Worker   ///   CHECK-NEXT:      adr lr, #+0x{{c|10}}
42*795d594fSAndroid Build Coastguard Worker   //    The following instruction (generated by
43*795d594fSAndroid Build Coastguard Worker   //    `art::arm64::CodeGeneratorARM64::EmitBakerReadBarrierCbnz`) checks the
44*795d594fSAndroid Build Coastguard Worker   //    Marking Register (X20) and goes into the Baker read barrier thunk if MR is
45*795d594fSAndroid Build Coastguard Worker   //    not null. The null offset (#+0x0) in the CBNZ instruction is a placeholder
46*795d594fSAndroid Build Coastguard Worker   //    for the offset to the Baker read barrier thunk (which is not yet set when
47*795d594fSAndroid Build Coastguard Worker   //    the CFG output is emitted).
48*795d594fSAndroid Build Coastguard Worker   ///   CHECK-NEXT:      cbnz x20, #+0x0
49*795d594fSAndroid Build Coastguard Worker   /// CHECK-ELSE:
50*795d594fSAndroid Build Coastguard Worker   ///   CHECK-NEXT:      add x<<BaseRegNum:\d+>>, {{x\d+}}, #0x8 (8)
51*795d594fSAndroid Build Coastguard Worker   /// CHECK-FI:
52*795d594fSAndroid Build Coastguard Worker   /// CHECK-NEXT:      ldar {{w\d+}}, [x<<BaseRegNum>>]
53*795d594fSAndroid Build Coastguard Worker 
test()54*795d594fSAndroid Build Coastguard Worker   public void test() {
55*795d594fSAndroid Build Coastguard Worker     // Continually check that reading field `foo.bar` throws a
56*795d594fSAndroid Build Coastguard Worker     // NullPointerException while allocating over 64 MiB of memory (with heap
57*795d594fSAndroid Build Coastguard Worker     // size limited to 16 MiB), in order to increase memory pressure and
58*795d594fSAndroid Build Coastguard Worker     // eventually trigger a concurrent garbage collection, which will start by
59*795d594fSAndroid Build Coastguard Worker     // putting the GC in marking mode and enable read barriers (when the
60*795d594fSAndroid Build Coastguard Worker     // Concurrent Copying collector is used).
61*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i != 64 * 1024; ++i) {
62*795d594fSAndroid Build Coastguard Worker       allocateAtLeast1KiB();
63*795d594fSAndroid Build Coastguard Worker       try {
64*795d594fSAndroid Build Coastguard Worker         // Read volatile field `bar` of `foo`, which is null, and is expected
65*795d594fSAndroid Build Coastguard Worker         // to produce a NullPointerException. On ARM64, this is implemented as a
66*795d594fSAndroid Build Coastguard Worker         // load-acquire (LDAR instruction).
67*795d594fSAndroid Build Coastguard Worker         //
68*795d594fSAndroid Build Coastguard Worker         // When the Concurrent Copying GC is marking, read barriers are enabled
69*795d594fSAndroid Build Coastguard Worker         // and the field load executes code from a Baker read barrier thunk.
70*795d594fSAndroid Build Coastguard Worker         // On ARM64, there used to be a bug in this thunk for the load-acquire
71*795d594fSAndroid Build Coastguard Worker         // case, where an explicit null check was missing, triggering an
72*795d594fSAndroid Build Coastguard Worker         // unhandled SIGSEGV when trying to load the lock word from the volatile
73*795d594fSAndroid Build Coastguard Worker         // field (b/140507091).
74*795d594fSAndroid Build Coastguard Worker         Object foo_bar = foo.bar;
75*795d594fSAndroid Build Coastguard Worker       } catch (NullPointerException e) {
76*795d594fSAndroid Build Coastguard Worker         continue;
77*795d594fSAndroid Build Coastguard Worker       }
78*795d594fSAndroid Build Coastguard Worker       // We should not be here.
79*795d594fSAndroid Build Coastguard Worker       throw new Error("Expected NullPointerException");
80*795d594fSAndroid Build Coastguard Worker     }
81*795d594fSAndroid Build Coastguard Worker   }
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker   // Allocate at least 1 KiB of memory on the managed heap.
84*795d594fSAndroid Build Coastguard Worker   // Retain some allocated memory and release old allocations so that the
85*795d594fSAndroid Build Coastguard Worker   // garbage collector has something to do.
allocateAtLeast1KiB()86*795d594fSAndroid Build Coastguard Worker   public static void allocateAtLeast1KiB() {
87*795d594fSAndroid Build Coastguard Worker     memory[allocationIndex] = new Object[1024 / 4];
88*795d594fSAndroid Build Coastguard Worker     ++allocationIndex;
89*795d594fSAndroid Build Coastguard Worker     if (allocationIndex == memory.length) {
90*795d594fSAndroid Build Coastguard Worker       allocationIndex = 0;
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker   public static Object[] memory = new Object[1024];
95*795d594fSAndroid Build Coastguard Worker   public static int allocationIndex = 0;
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker   private Foo foo;
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker }
100