xref: /aosp_15_r20/art/test/717-integer-value-of/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2018 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 import java.lang.reflect.Field;
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker public class Main {
main(String[] args)20*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
21*795d594fSAndroid Build Coastguard Worker         if (!isDalvik) {
22*795d594fSAndroid Build Coastguard Worker           // This test is ART-specific. Just fake the expected output.
23*795d594fSAndroid Build Coastguard Worker           System.out.println("JNI_OnLoad called");
24*795d594fSAndroid Build Coastguard Worker           return;
25*795d594fSAndroid Build Coastguard Worker         }
26*795d594fSAndroid Build Coastguard Worker         System.loadLibrary(args[0]);
27*795d594fSAndroid Build Coastguard Worker         if (!hasJit()) {
28*795d594fSAndroid Build Coastguard Worker           return;
29*795d594fSAndroid Build Coastguard Worker         }
30*795d594fSAndroid Build Coastguard Worker         testValueOfArg();
31*795d594fSAndroid Build Coastguard Worker         testValueOfConst();
32*795d594fSAndroid Build Coastguard Worker     }
33*795d594fSAndroid Build Coastguard Worker 
testValueOfArg()34*795d594fSAndroid Build Coastguard Worker     public static void testValueOfArg() throws Exception {
35*795d594fSAndroid Build Coastguard Worker         final VolatileFlag start_end = new VolatileFlag();
36*795d594fSAndroid Build Coastguard Worker         Thread t = new Thread() {
37*795d594fSAndroid Build Coastguard Worker             @Override
38*795d594fSAndroid Build Coastguard Worker             public void run() {
39*795d594fSAndroid Build Coastguard Worker                 try {
40*795d594fSAndroid Build Coastguard Worker                     Class<?> integerCacheClass = Class.forName("java.lang.Integer$IntegerCache");
41*795d594fSAndroid Build Coastguard Worker                     Field cacheField = integerCacheClass.getDeclaredField("cache");
42*795d594fSAndroid Build Coastguard Worker                     cacheField.setAccessible(true);
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker                     Integer[] cache = (Integer[]) cacheField.get(integerCacheClass);
45*795d594fSAndroid Build Coastguard Worker                     Integer[] alt_cache = new Integer[cache.length];
46*795d594fSAndroid Build Coastguard Worker                     System.arraycopy(cache, 0, alt_cache, 0, cache.length);
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker                     // Let the main thread know that everything is set up.
49*795d594fSAndroid Build Coastguard Worker                     synchronized (start_end) {
50*795d594fSAndroid Build Coastguard Worker                         start_end.notify();
51*795d594fSAndroid Build Coastguard Worker                     }
52*795d594fSAndroid Build Coastguard Worker                     while (!start_end.flag) {
53*795d594fSAndroid Build Coastguard Worker                         cacheField.set(integerCacheClass, alt_cache);
54*795d594fSAndroid Build Coastguard Worker                         cacheField.set(integerCacheClass, cache);
55*795d594fSAndroid Build Coastguard Worker                     }
56*795d594fSAndroid Build Coastguard Worker                 } catch (Throwable t) {
57*795d594fSAndroid Build Coastguard Worker                     throw new Error(t);
58*795d594fSAndroid Build Coastguard Worker                 }
59*795d594fSAndroid Build Coastguard Worker             }
60*795d594fSAndroid Build Coastguard Worker         };
61*795d594fSAndroid Build Coastguard Worker         synchronized (start_end) {
62*795d594fSAndroid Build Coastguard Worker             t.start();
63*795d594fSAndroid Build Coastguard Worker             start_end.wait();  // Wait for the thread to start.
64*795d594fSAndroid Build Coastguard Worker         }
65*795d594fSAndroid Build Coastguard Worker         // Previously, this may have used an invalid IntegerValueOfInfo (because of seeing
66*795d594fSAndroid Build Coastguard Worker         // the `alt_cache` which is not in the boot image) when asked to emit code after
67*795d594fSAndroid Build Coastguard Worker         // using a valid info (using `cache`) when requesting locations.
68*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "getAsInteger");
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker         start_end.flag = true;
71*795d594fSAndroid Build Coastguard Worker         t.join();
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker         Runtime.getRuntime().gc();  // Collect the `alt_cache`.
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker         // If `getAsInteger()` was miscompiled, it shall try to retrieve an Integer reference
76*795d594fSAndroid Build Coastguard Worker         // from a collected array (low = 0, high = 0 means that this happens only for value 0),
77*795d594fSAndroid Build Coastguard Worker         // reading from a bogus location. Depending on the GC type, this bogus memory access may
78*795d594fSAndroid Build Coastguard Worker         // yield SIGSEGV or `null` or even a valid reference.
79*795d594fSAndroid Build Coastguard Worker         Integer new0 = getAsInteger(0);
80*795d594fSAndroid Build Coastguard Worker         int value = (int) new0;
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker         if (value != 0) {
83*795d594fSAndroid Build Coastguard Worker             throw new Error("value is " + value);
84*795d594fSAndroid Build Coastguard Worker         }
85*795d594fSAndroid Build Coastguard Worker     }
86*795d594fSAndroid Build Coastguard Worker 
testValueOfConst()87*795d594fSAndroid Build Coastguard Worker     public static void testValueOfConst() throws Exception {
88*795d594fSAndroid Build Coastguard Worker         Class<?> integerCacheClass = Class.forName("java.lang.Integer$IntegerCache");
89*795d594fSAndroid Build Coastguard Worker         Field cacheField = integerCacheClass.getDeclaredField("cache");
90*795d594fSAndroid Build Coastguard Worker         cacheField.setAccessible(true);
91*795d594fSAndroid Build Coastguard Worker         Field lowField = integerCacheClass.getDeclaredField("low");
92*795d594fSAndroid Build Coastguard Worker         lowField.setAccessible(true);
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker         Integer[] cache = (Integer[]) cacheField.get(integerCacheClass);
95*795d594fSAndroid Build Coastguard Worker         int low = (int) lowField.get(integerCacheClass);
96*795d594fSAndroid Build Coastguard Worker         Integer old42 = cache[42 - low];
97*795d594fSAndroid Build Coastguard Worker         cache[42 - low] = new Integer(42);
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker         // This used to hit
100*795d594fSAndroid Build Coastguard Worker         //     DCHECK(boxed != nullptr &&
101*795d594fSAndroid Build Coastguard Worker         //            Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
102*795d594fSAndroid Build Coastguard Worker         // when compiling the intrinsic.
103*795d594fSAndroid Build Coastguard Worker         ensureJitCompiled(Main.class, "get42AsInteger");
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker         cache[42 - low] = old42;
106*795d594fSAndroid Build Coastguard Worker         Runtime.getRuntime().gc();
107*795d594fSAndroid Build Coastguard Worker         Integer new42 = get42AsInteger();
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker         // If the DCHECK() was removed, MterpInvokeVirtualQuick() used to crash here.
110*795d594fSAndroid Build Coastguard Worker         // (Note: Our fault handler on x86-64 then also crashed.)
111*795d594fSAndroid Build Coastguard Worker         int value = (int) new42;
112*795d594fSAndroid Build Coastguard Worker 
113*795d594fSAndroid Build Coastguard Worker         if (value != (int) old42) {
114*795d594fSAndroid Build Coastguard Worker             throw new Error("value is " + value);
115*795d594fSAndroid Build Coastguard Worker         }
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     private static class VolatileFlag {
119*795d594fSAndroid Build Coastguard Worker         public volatile boolean flag = false;
120*795d594fSAndroid Build Coastguard Worker     }
121*795d594fSAndroid Build Coastguard Worker 
get42AsInteger()122*795d594fSAndroid Build Coastguard Worker     public static Integer get42AsInteger() {
123*795d594fSAndroid Build Coastguard Worker         return Integer.valueOf(42);
124*795d594fSAndroid Build Coastguard Worker     }
125*795d594fSAndroid Build Coastguard Worker 
getAsInteger(int value)126*795d594fSAndroid Build Coastguard Worker     public static Integer getAsInteger(int value) {
127*795d594fSAndroid Build Coastguard Worker         return Integer.valueOf(value);
128*795d594fSAndroid Build Coastguard Worker     }
129*795d594fSAndroid Build Coastguard Worker 
hasJit()130*795d594fSAndroid Build Coastguard Worker     private native static boolean hasJit();
ensureJitCompiled(Class<?> itf, String method_name)131*795d594fSAndroid Build Coastguard Worker     private static native void ensureJitCompiled(Class<?> itf, String method_name);
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker     private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik");
134*795d594fSAndroid Build Coastguard Worker }
135