1 /*
2  * Copyright (C) 2015 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 {
main(String[] args)18     public static void main(String[] args) {
19         new Main().run();
20         testPreserveFloat();
21         testPreserveDouble();
22         System.out.println("finish");
23     }
24 
run()25     public void run() {
26         double a[][] = new double[200][201];
27         double b[] = new double[200];
28         int n = 100;
29 
30         foo1(a, n, b);
31     }
32 
foo1(double a[][], int n, double b[])33     void foo1(double a[][], int n, double b[]) {
34         double t;
35         int i,k;
36 
37         for (i = 0; i < n; i++) {
38             k = n - (i + 1);
39             b[k] /= a[k][k];
40             t = -b[k];
41             foo2(k + 1000, t, b);
42         }
43     }
44 
foo2(int n, double c, double b[])45     void foo2(int n, double c, double b[]) {
46         try {
47             foo3(n, c, b);
48         } catch (Exception e) {
49         }
50     }
51 
foo3(int n, double c, double b[])52     void foo3(int n, double c, double b[]) {
53         int i = 0;
54         for (i = 0; i < n; i++) {
55             b[i + 1] += c * b[i + 1];
56         }
57     }
58 
59     /*
60      * Test that we correctly preserve floating point registers when we deoptimize.
61      *
62      * Note: These tests rely on the deoptimization happening before the loop,
63      * so that the loop is interpreted and fills the provided arrays. However,
64      * the BCE transformation can be modified to execute the loop as many times
65      * as the compiler can guarantee no AIOOBE and only deoptimize thereafter,
66      * just before the throwing iteration. Then the floating point registers
67      * would no longer be used after the deoptimization and another approach
68      * would be needed to test this.
69      */
70 
testPreserveFloat()71     static public void testPreserveFloat() {
72         float[] array = new float[2];
73         try {
74             $noinline$FloatFill(1.125f, 2.5f, array, 3);
75             throw new Error();
76         } catch (ArrayIndexOutOfBoundsException expected) {
77             System.out.println("array[0]=" + array[0] + "f");
78             System.out.println("array[1]=" + array[1] + "f");
79         }
80     }
81 
82     /// CHECK-START: void Main.$noinline$FloatFill(float, float, float[], int) BCE (after)
83     /// CHECK-DAG:          Deoptimize
84     /// CHECK-DAG:          Deoptimize
85     /// CHECK-DAG:          Deoptimize
86     /// CHECK-NOT:          Deoptimize
87 
88     /// CHECK-START: void Main.$noinline$FloatFill(float, float, float[], int) BCE (after)
89     /// CHECK-NOT:          BoundsCheck
90 
$noinline$FloatFill(float f1, float f2, float[] array, int n)91     public static void $noinline$FloatFill(float f1, float f2, float[] array, int n) {
92         if (doThrow) { throw new Error(); }
93         for (int i = 0; i < n; ++i) {
94             array[i] = ((i & 1) == 1) ? f1 : f2;
95             f1 += 1.5f;
96             f2 += 2.25f;
97         }
98     }
99 
testPreserveDouble()100     static public void testPreserveDouble() {
101         double[] array = new double[2];
102         try {
103             $noinline$DoubleFill(2.125, 3.5, array, 3);
104             throw new Error();
105         } catch (ArrayIndexOutOfBoundsException expected) {
106             System.out.println("array[0]=" + array[0]);
107             System.out.println("array[1]=" + array[1]);
108         }
109     }
110 
111     /// CHECK-START: void Main.$noinline$DoubleFill(double, double, double[], int) BCE (after)
112     /// CHECK-DAG:          Deoptimize
113     /// CHECK-DAG:          Deoptimize
114     /// CHECK-DAG:          Deoptimize
115     /// CHECK-NOT:          Deoptimize
116 
117     /// CHECK-START: void Main.$noinline$DoubleFill(double, double, double[], int) BCE (after)
118     /// CHECK-NOT:          BoundsCheck
119 
$noinline$DoubleFill(double d1, double d2, double[] array, int n)120     public static void $noinline$DoubleFill(double d1, double d2, double[] array, int n) {
121         if (doThrow) { throw new Error(); }
122         for (int i = 0; i < n; ++i) {
123             array[i] = ((i & 1) == 1) ? d1 : d2;
124             d1 += 1.5;
125             d2 += 2.25;
126         }
127     }
128 
129     public static boolean doThrow = false;
130 }
131 
132