• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 public class Main {
18 
19   public static class InnerInitialized {
20     static int staticValue1 = 0;
21     static int staticValue2 = 1;
22 
$noinline$runHotMethod(boolean doComputation)23     static int $noinline$runHotMethod(boolean doComputation) {
24       if (doComputation) {
25         for (int i = 0; i < 100000; i++) {
26           staticValue1 += staticValue2;
27         }
28       }
29       return staticValue1;
30     }
31 
32     static {
33       // Make $noinline$runHotMethod hot so it gets compiled. The
34       // regression used to be that the JIT would incorrectly update the
35       // resolution entrypoint of the method. The entrypoint needs to stay
36       // the resolution entrypoint otherwise other threads may incorrectly
37       // execute static methods of the class while the class is still being
38       // initialized.
39       for (int i = 0; i < 10; i++) {
40         $noinline$runHotMethod(true);
41       }
42 
43       // Start another thread that will invoke a static method of InnerInitialized.
44       new Thread(new Runnable() {
45         public void run() {
46           for (int i = 0; i < 100000; i++) {
47             $noinline$runInternalHotMethod(false);
48           }
49           // Give some time for the JIT compiler to compile $noinline$runInternalHotMethod.
50           // Only compiled code invoke the entrypoint of an ArtMethod.
51           try {
52             Thread.sleep(1000);
53           } catch (Exception e) {
54           }
55           int value = $noinline$runInternalHotMethod(true);
56           if (value != 42) {
57             throw new Error("Expected 42, got " + value);
58           }
59         }
60 
61         public int $noinline$runInternalHotMethod(boolean invokeStaticMethod) {
62           if (invokeStaticMethod) {
63             // The bug used to be here: the compiled code of $noinline$runInternalHotMethod
64             // would invoke the entrypoint of $noinline$runHotMethod, which was incorrectly
65             // updated to the JIT entrypoint and therefore not hitting the resolution
66             // trampoline which would have waited for the class to be initialized.
67             return $noinline$runHotMethod(false);
68           }
69           return 0;
70         }
71 
72       }).start();
73       // Give some time for the JIT compiler to compile runHotMethod, and also for the
74       // other thread to invoke $noinline$runHotMethod.
75       // This wait should be longer than the other thread's wait to make sure the other
76       // thread hits the $noinline$runHotMethod call before the initialization of
77       // InnerInitialized is finished.
78       try {
79         Thread.sleep(5000);
80       } catch (Exception e) {
81       }
82       staticValue1 = 42;
83     }
84   }
85 
main(String[] args)86   public static void main(String[] args) throws Exception {
87     System.out.println(InnerInitialized.staticValue1);
88   }
89 }
90