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