1 /*
2  * Copyright (C) 2017 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 // This base class has a single final field;
18 // the constructor should have one fence.
19 class Circle {
Circle(double radius)20   Circle(double radius) {
21     this.radius = radius;
22   }
getRadius()23   public double getRadius() {
24     return radius;
25   }
getArea()26   public double getArea() {
27     return radius * radius * Math.PI;
28   }
29 
getCircumference()30   public double getCircumference() {
31     return 2 * Math.PI * radius;
32   }
33 
34   private final double radius;
35 }
36 
37 // This subclass adds an extra final field;
38 // there should be an extra constructor fence added
39 // (for a total of 2 after inlining).
40 class Ellipse extends Circle {
Ellipse(double vertex, double covertex)41   Ellipse(double vertex, double covertex) {
42     super(vertex);
43 
44     this.covertex = covertex;
45   }
46 
getVertex()47   public double getVertex() {
48     return getRadius();
49   }
50 
getCovertex()51   public double getCovertex() {
52     return covertex;
53   }
54 
55   @Override
getArea()56   public double getArea() {
57     return getRadius() * covertex * Math.PI;
58   }
59 
60   private final double covertex;
61 }
62 
63 class CalcCircleAreaOrCircumference {
64   public static final int TYPE_AREA = 0;
65   public static final int TYPE_CIRCUMFERENCE = 1;
66 
67   double value;
68 
CalcCircleAreaOrCircumference(int type)69   public CalcCircleAreaOrCircumference(int type) {
70     this.type = type;
71   }
72 
73   final int type;
74 }
75 
76 public class Main {
77 
78   /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (before)
79   /// CHECK: NewInstance
80   /// CHECK: InstanceFieldSet
81   /// CHECK: ConstructorFence
82   /// CHECK: InstanceFieldGet
83 
84   /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (after)
85   /// CHECK-NOT: NewInstance
86   /// CHECK-NOT: InstanceFieldSet
87   /// CHECK-NOT: ConstructorFence
88   /// CHECK-NOT: InstanceFieldGet
89 
90   // Make sure the constructor fence gets eliminated when the allocation is eliminated.
calcCircleArea(double radius)91   static double calcCircleArea(double radius) {
92     return new Circle(radius).getArea();
93   }
94 
95   /// CHECK-START: double Main.calcEllipseArea(double, double) load_store_elimination (before)
96   /// CHECK: NewInstance
97   /// CHECK: InstanceFieldSet
98   /// CHECK: InstanceFieldSet
99   /// CHECK: ConstructorFence
100   /// CHECK: InstanceFieldGet
101   /// CHECK: InstanceFieldGet
102 
103   /// CHECK-START: double Main.calcEllipseArea(double, double) load_store_elimination (after)
104   /// CHECK-NOT: NewInstance
105   /// CHECK-NOT: InstanceFieldSet
106   /// CHECK-NOT: ConstructorFence
107   /// CHECK-NOT: InstanceFieldGet
108 
109   // Multiple constructor fences can accumulate through inheritance, make sure
110   // they are all eliminated when the allocation is eliminated.
calcEllipseArea(double vertex, double covertex)111   static double calcEllipseArea(double vertex, double covertex) {
112     return new Ellipse(vertex, covertex).getArea();
113   }
114 
115   /// CHECK-START: double Main.calcCircleAreaOrCircumference(double, boolean) load_store_elimination (before)
116   /// CHECK-DAG: NewInstance
117   /// CHECK-DAG: InstanceFieldSet
118   /// CHECK-DAG: ConstructorFence
119   /// CHECK-DAG: InstanceFieldGet
120 
121   /// CHECK-START: double Main.calcCircleAreaOrCircumference(double, boolean) load_store_elimination (after)
122   /// CHECK:     Phi
123   /// CHECK-NOT: Phi
124 
125   /// CHECK-START: double Main.calcCircleAreaOrCircumference(double, boolean) load_store_elimination (after)
126   /// CHECK-NOT: NewInstance
127   /// CHECK-NOT: ConstructorFence
128 
129   // The object allocation shall be eliminated by LSE and the load shall be replaced
130   // by a Phi with the values that were previously being stored.
calcCircleAreaOrCircumference(double radius, boolean area_or_circumference)131   static double calcCircleAreaOrCircumference(double radius, boolean area_or_circumference) {
132     CalcCircleAreaOrCircumference calc =
133       new CalcCircleAreaOrCircumference(
134           area_or_circumference ? CalcCircleAreaOrCircumference.TYPE_AREA :
135           CalcCircleAreaOrCircumference.TYPE_CIRCUMFERENCE);
136 
137     if (area_or_circumference) {
138       // Area
139       calc.value = Math.PI * Math.PI * radius;
140     } else {
141       // Circumference
142       calc.value = 2 * Math.PI * radius;
143     }
144 
145     return calc.value;
146   }
147 
148   /// CHECK-START: Circle Main.makeCircle(double) load_store_elimination (after)
149   /// CHECK: NewInstance
150   /// CHECK: ConstructorFence
151 
152   // The object allocation is considered a singleton by LSE,
153   // but we cannot eliminate the new because it is returned.
154   //
155   // The constructor fence must also not be removed because the object could escape the
156   // current thread (in the caller).
makeCircle(double radius)157   static Circle makeCircle(double radius) {
158     return new Circle(radius);
159   }
160 
assertIntEquals(int result, int expected)161   static void assertIntEquals(int result, int expected) {
162     if (expected != result) {
163       throw new Error("Expected: " + expected + ", found: " + result);
164     }
165   }
166 
assertFloatEquals(float result, float expected)167   static void assertFloatEquals(float result, float expected) {
168     if (expected != result) {
169       throw new Error("Expected: " + expected + ", found: " + result);
170     }
171   }
172 
assertDoubleEquals(double result, double expected)173   static void assertDoubleEquals(double result, double expected) {
174     if (expected != result) {
175       throw new Error("Expected: " + expected + ", found: " + result);
176     }
177   }
178 
assertInstanceOf(Object result, Class<?> expected)179   static void assertInstanceOf(Object result, Class<?> expected) {
180     if (result.getClass() != expected) {
181       throw new Error("Expected type: " + expected + ", found : " + result.getClass());
182     }
183   }
184 
main(String[] args)185   public static void main(String[] args) {
186     assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI));
187     assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcEllipseArea(Math.PI, Math.PI));
188     assertDoubleEquals(2 * Math.PI * Math.PI, calcCircleAreaOrCircumference(Math.PI, false));
189     assertInstanceOf(makeCircle(Math.PI), Circle.class);
190   }
191 
192   static boolean sFlag;
193 }
194