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