Mercurial > hg > truffle
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 } |