comparison truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java @ 22501:a63bda98cfdb

Extract profiles into separate package. Add isProfilingEnabled in TruffleRuntime to disable profiling in the default runtime; Add low overhead profiles for primitives; Add LoopConditionProfile; Profile footprint/threadsafety improvements; Make toString implementations more consistent; Greatly enhanced javadoc documentation for profiles; Deprecate old profiles
author Christian Humer <christian.humer@oracle.com>
date Wed, 16 Dec 2015 16:38:13 +0100
parents truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java@dc83cc1f94f2
children
comparison
equal deleted inserted replaced
22500:fbe1eb7b4172 22501:a63bda98cfdb
1 /*
2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.oracle.truffle.api.profiles;
26
27 import java.util.Objects;
28
29 import com.oracle.truffle.api.CompilerDirectives;
30 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
31 import com.oracle.truffle.api.Truffle;
32
33 /**
34 * <p>
35 * Represents a {@link ValueProfile} that speculates on the primitive equality or object identity of
36 * values. Note that for {@code float} and {@code double} values we compare primitive equality via
37 * {@link Float#floatToRawIntBits} and {@link Double#doubleToRawLongBits}, so that for example
38 * {@code -0.0} is not considered the same as {@code 0.0}, even though primitive equality would
39 * normally say that it was.
40 * </p>
41 *
42 * {@inheritDoc}
43 */
44 public abstract class PrimitiveValueProfile extends ValueProfile {
45
46 PrimitiveValueProfile() {
47 }
48
49 @Override
50 public abstract <T> T profile(T value);
51
52 public abstract byte profile(byte value);
53
54 public abstract short profile(short value);
55
56 public abstract int profile(int value);
57
58 public abstract long profile(long value);
59
60 public abstract float profile(float value);
61
62 public abstract double profile(double value);
63
64 public abstract boolean profile(boolean value);
65
66 public abstract char profile(char value);
67
68 /**
69 * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or object
70 * identity of a value.
71 */
72 public static PrimitiveValueProfile createEqualityProfile() {
73 if (Truffle.getRuntime().isProfilingEnabled()) {
74 return Enabled.create();
75 } else {
76 return Disabled.INSTANCE;
77 }
78 }
79
80 /**
81 * @deprecated going to get removed without replacement
82 */
83 @Deprecated
84 public static boolean exactCompare(float a, float b) {
85 /*
86 * -0.0 == 0.0, but you can tell the difference through other means, so we need to
87 * differentiate.
88 */
89 return Float.floatToRawIntBits(a) == Float.floatToRawIntBits(b);
90 }
91
92 /**
93 * @deprecated going to get removed without replacement
94 */
95 @Deprecated
96 public static boolean exactCompare(double a, double b) {
97 /*
98 * -0.0 == 0.0, but you can tell the difference through other means, so we need to
99 * differentiate.
100 */
101 return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b);
102 }
103
104 static final class Enabled extends PrimitiveValueProfile {
105
106 private static final byte STATE_UNINITIALIZED = 0;
107 private static final byte STATE_BYTE = 1;
108 private static final byte STATE_SHORT = 2;
109 private static final byte STATE_INTEGER = 3;
110 private static final byte STATE_LONG = 4;
111 private static final byte STATE_BOOLEAN = 5;
112 private static final byte STATE_CHARACTER = 6;
113 private static final byte STATE_FLOAT = 7;
114 private static final byte STATE_DOUBLE = 8;
115 private static final byte STATE_IDENTITY = 9;
116 private static final byte STATE_GENERIC = 10;
117
118 @CompilationFinal private byte state = STATE_UNINITIALIZED;
119 @CompilationFinal private Object cachedValue;
120
121 Enabled() {
122 }
123
124 @SuppressWarnings("unchecked")
125 @Override
126 public <T> T profile(T value) {
127 byte s = this.state;
128 Object snapshot;
129 switch (s) {
130 case STATE_BYTE:
131 case STATE_SHORT:
132 case STATE_INTEGER:
133 case STATE_LONG:
134 case STATE_BOOLEAN:
135 case STATE_CHARACTER:
136 snapshot = this.cachedValue;
137 if (snapshot.equals(value)) {
138 return (T) snapshot;
139 }
140 break;
141 case STATE_DOUBLE:
142 snapshot = this.cachedValue;
143 if (value instanceof Double && exactCompare((Double) snapshot, (Double) value)) {
144 return (T) snapshot;
145 }
146 break;
147 case STATE_FLOAT:
148 snapshot = this.cachedValue;
149 if (value instanceof Float && exactCompare((Float) snapshot, (Float) value)) {
150 return (T) snapshot;
151 }
152 break;
153 case STATE_IDENTITY:
154 snapshot = this.cachedValue;
155 if (snapshot == value) {
156 return (T) snapshot;
157 }
158 break;
159 case STATE_GENERIC:
160 return value;
161 }
162 CompilerDirectives.transferToInterpreterAndInvalidate();
163 slowpath(s, value);
164 return value;
165 }
166
167 @Override
168 public byte profile(byte value) {
169 byte s = this.state;
170 if (s != STATE_GENERIC) {
171 if (s == STATE_BYTE) {
172 byte castCachedValue = (byte) this.cachedValue;
173 if (castCachedValue == value) {
174 return castCachedValue;
175 }
176 }
177 CompilerDirectives.transferToInterpreterAndInvalidate();
178 slowpath(s, value);
179 }
180 return value;
181 }
182
183 @Override
184 public short profile(short value) {
185 byte s = this.state;
186 if (s != STATE_GENERIC) {
187 if (s == STATE_SHORT) {
188 short castCachedValue = (short) this.cachedValue;
189 if (castCachedValue == value) {
190 return castCachedValue;
191 }
192 }
193 CompilerDirectives.transferToInterpreterAndInvalidate();
194 slowpath(s, value);
195 }
196 return value;
197 }
198
199 @Override
200 public int profile(int value) {
201 byte s = this.state;
202 if (s != STATE_GENERIC) {
203 if (s == STATE_INTEGER) {
204 int castCachedValue = (int) this.cachedValue;
205 if (castCachedValue == value) {
206 return castCachedValue;
207 }
208 }
209 CompilerDirectives.transferToInterpreterAndInvalidate();
210 slowpath(s, value);
211 }
212 return value;
213 }
214
215 @Override
216 public long profile(long value) {
217 byte s = this.state;
218 if (s != STATE_GENERIC) {
219 if (s == STATE_LONG) {
220 long castCachedValue = (long) this.cachedValue;
221 if (castCachedValue == value) {
222 return castCachedValue;
223 }
224 }
225 CompilerDirectives.transferToInterpreterAndInvalidate();
226 slowpath(s, value);
227 }
228 return value;
229 }
230
231 @Override
232 public float profile(float value) {
233 byte s = this.state;
234 if (s != STATE_GENERIC) {
235 if (s == STATE_FLOAT) {
236 float castCachedValue = (float) this.cachedValue;
237 if (exactCompare(castCachedValue, value)) {
238 return castCachedValue;
239 }
240 }
241 CompilerDirectives.transferToInterpreterAndInvalidate();
242 slowpath(s, value);
243 }
244 return value;
245 }
246
247 @Override
248 public double profile(double value) {
249 byte s = this.state;
250 if (s != STATE_GENERIC) {
251 if (s == STATE_DOUBLE) {
252 double castCachedValue = (double) this.cachedValue;
253 if (exactCompare(castCachedValue, value)) {
254 return castCachedValue;
255 }
256 }
257 CompilerDirectives.transferToInterpreterAndInvalidate();
258 slowpath(s, value);
259 }
260 return value;
261
262 }
263
264 @Override
265 public boolean profile(boolean value) {
266 byte s = this.state;
267 if (s != STATE_GENERIC) {
268 if (s == STATE_BOOLEAN) {
269 boolean castCachedValue = (boolean) this.cachedValue;
270 if (castCachedValue == value) {
271 return castCachedValue;
272 }
273 }
274 CompilerDirectives.transferToInterpreterAndInvalidate();
275 slowpath(s, value);
276 }
277 return value;
278 }
279
280 @Override
281 public char profile(char value) {
282 byte s = this.state;
283 if (s != STATE_GENERIC) {
284 if (s == STATE_CHARACTER) {
285 char castCachedValue = (char) this.cachedValue;
286 if (castCachedValue == value) {
287 return castCachedValue;
288 }
289 }
290 CompilerDirectives.transferToInterpreterAndInvalidate();
291 slowpath(s, value);
292 }
293 return value;
294 }
295
296 private void slowpath(byte s, Object value) {
297 if (s == STATE_UNINITIALIZED) {
298 cachedValue = value;
299 state = specialize(value);
300 } else {
301 state = STATE_GENERIC;
302 cachedValue = null;
303 }
304 }
305
306 private static byte specialize(Object value) {
307 if (value instanceof Byte) {
308 return STATE_BYTE;
309 } else if (value instanceof Short) {
310 return STATE_SHORT;
311 } else if (value instanceof Integer) {
312 return STATE_INTEGER;
313 } else if (value instanceof Long) {
314 return STATE_LONG;
315 } else if (value instanceof Boolean) {
316 return STATE_BOOLEAN;
317 } else if (value instanceof Character) {
318 return STATE_CHARACTER;
319 } else if (value instanceof Double) {
320 return STATE_DOUBLE;
321 } else if (value instanceof Float) {
322 return STATE_FLOAT;
323 } else {
324 return STATE_IDENTITY;
325 }
326 }
327
328 boolean isGeneric() {
329 return state == STATE_GENERIC;
330 }
331
332 boolean isUninitialized() {
333 return state == STATE_UNINITIALIZED;
334 }
335
336 Object getCachedValue() {
337 return cachedValue;
338 }
339
340 @Override
341 public String toString() {
342 return toString(PrimitiveValueProfile.class, state == STATE_UNINITIALIZED, state == STATE_GENERIC, formatSpecialization());
343 }
344
345 private String formatSpecialization() {
346 Object snapshot = this.cachedValue;
347 if (state != STATE_UNINITIALIZED && state != STATE_GENERIC) {
348 if (snapshot == null) {
349 return String.format("value == null");
350 } else {
351 if (state == STATE_IDENTITY) {
352 String simpleName = snapshot.getClass().getSimpleName();
353 return String.format("value == %s@%x", simpleName, Objects.hash(snapshot));
354 } else {
355 return String.format("value == (%s)%s", snapshot.getClass().getSimpleName(), snapshot);
356 }
357 }
358 }
359 return null;
360 }
361
362 /**
363 * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or
364 * object identity of a value.
365 */
366 static PrimitiveValueProfile create() {
367 return new Enabled();
368 }
369 }
370
371 static final class Disabled extends PrimitiveValueProfile {
372
373 static final PrimitiveValueProfile INSTANCE = new Disabled();
374
375 @Override
376 public <T> T profile(T value) {
377 return value;
378 }
379
380 @Override
381 public byte profile(byte value) {
382 return value;
383 }
384
385 @Override
386 public short profile(short value) {
387 return value;
388 }
389
390 @Override
391 public int profile(int value) {
392 return value;
393 }
394
395 @Override
396 public long profile(long value) {
397 return value;
398 }
399
400 @Override
401 public float profile(float value) {
402 return value;
403 }
404
405 @Override
406 public double profile(double value) {
407 return value;
408 }
409
410 @Override
411 public boolean profile(boolean value) {
412 return value;
413 }
414
415 @Override
416 public char profile(char value) {
417 return value;
418 }
419
420 @Override
421 public String toString() {
422 return toStringDisabled(PrimitiveValueProfile.class);
423 }
424
425 }
426
427 }