1/*
2 * Copyright (C) 2018 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
17import java.lang.reflect.InvocationHandler;
18import java.lang.reflect.Method;
19import java.lang.reflect.Proxy;
20import java.util.ArrayList;
21
22class OOMEHelper {
23    int nullField;
24}
25
26/**
27 * Test that null field access under an OOME situation works.
28 *
29 * The test relies on compile-time verification. This class is compile-time verifiable, so when
30 * loaded at runtime will not transitively load referenced types eagerly. In that case, our code
31 * to give descriptive NullPointerExceptions for the field access to the null "instance" of
32 * OOMEHelper in nullAccess() will be the first attempting to load the class, and, under the
33 * induced low-memory situation, will throw itself an OutOfMemoryError.
34 */
35public class OOMEOnNullAccess {
36
37    static ArrayList<Object> storage = new ArrayList<>(100000);
38
39    public static void main(String[] args) {
40        // Stop the JIT to be sure nothing is running that could be resolving classes or causing
41        // verification.
42        Main.stopJit();
43        Main.waitForCompilation();
44
45        int l = 1024 * 1024;
46        while (l > 8) {
47          try {
48            storage.add(new byte[l]);
49          } catch (OutOfMemoryError e) {
50            l = l/2;
51          }
52        }
53
54        try {
55            nullAccess(null);
56            storage.clear();
57            throw new RuntimeException("Did not receive exception!");
58        } catch (OutOfMemoryError oome) {
59            storage.clear();
60            System.err.println("Received OOME");
61        } finally {
62            // Even if it's an unexpected error, clear so that we can print things later.
63            storage.clear();
64        }
65
66        Main.startJit();
67    }
68
69    public static int nullAccess(OOMEHelper nullInstance) {
70        // Under AOT, this access is the first one to actually load the OOMEHelper class, so
71        // we can pretty print the name and such.
72        return nullInstance.nullField;
73    }
74}
75