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: NewInstance
117   /// CHECK: InstanceFieldSet
118   /// CHECK: ConstructorFence
119   /// CHECK: InstanceFieldGet
120 
121   /// CHECK-START: double Main.calcCircleAreaOrCircumference(double, boolean) load_store_elimination (after)
122   /// CHECK: NewInstance
123   /// CHECK-NOT: ConstructorFence
124 
125   //
126   // The object allocation will not be eliminated by LSE because of aliased stores.
127   // However the object is still a singleton, so it never escapes the current thread.
128   // There should not be a constructor fence here after LSE.
calcCircleAreaOrCircumference(double radius, boolean area_or_circumference)129   static double calcCircleAreaOrCircumference(double radius, boolean area_or_circumference) {
130     CalcCircleAreaOrCircumference calc =
131       new CalcCircleAreaOrCircumference(
132           area_or_circumference ? CalcCircleAreaOrCircumference.TYPE_AREA :
133           CalcCircleAreaOrCircumference.TYPE_CIRCUMFERENCE);
134 
135     if (area_or_circumference) {
136       // Area
137       calc.value = Math.PI * Math.PI * radius;
138     } else {
139       // Circumference
140       calc.value = 2 * Math.PI * radius;
141     }
142 
143     return calc.value;
144   }
145 
146   /// CHECK-START: Circle Main.makeCircle(double) load_store_elimination (after)
147   /// CHECK: NewInstance
148   /// CHECK: ConstructorFence
149 
150   // The object allocation is considered a singleton by LSE,
151   // but we cannot eliminate the new because it is returned.
152   //
153   // The constructor fence must also not be removed because the object could escape the
154   // current thread (in the caller).
makeCircle(double radius)155   static Circle makeCircle(double radius) {
156     return new Circle(radius);
157   }
158 
assertIntEquals(int result, int expected)159   static void assertIntEquals(int result, int expected) {
160     if (expected != result) {
161       throw new Error("Expected: " + expected + ", found: " + result);
162     }
163   }
164 
assertFloatEquals(float result, float expected)165   static void assertFloatEquals(float result, float expected) {
166     if (expected != result) {
167       throw new Error("Expected: " + expected + ", found: " + result);
168     }
169   }
170 
assertDoubleEquals(double result, double expected)171   static void assertDoubleEquals(double result, double expected) {
172     if (expected != result) {
173       throw new Error("Expected: " + expected + ", found: " + result);
174     }
175   }
176 
assertInstanceOf(Object result, Class<?> expected)177   static void assertInstanceOf(Object result, Class<?> expected) {
178     if (result.getClass() != expected) {
179       throw new Error("Expected type: " + expected + ", found : " + result.getClass());
180     }
181   }
182 
main(String[] args)183   public static void main(String[] args) {
184     assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI));
185     assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcEllipseArea(Math.PI, Math.PI));
186     assertDoubleEquals(2 * Math.PI * Math.PI, calcCircleAreaOrCircumference(Math.PI, false));
187     assertInstanceOf(makeCircle(Math.PI), Circle.class);
188   }
189 
190   static boolean sFlag;
191 }
192