# HG changeset patch # User Jaroslav Tulach # Date 1450342898 -3600 # Node ID 828c67903db2d8db8b189804bd3d709de9a2aa1a # Parent d2b4fe945c23d631fbc3aee565a08282937e3f02 Moving profiles into their own project to ensure the core API doesn't reference these utility classes. diff -r d2b4fe945c23 -r 828c67903db2 mx.truffle/suite.py --- a/mx.truffle/suite.py Wed Dec 16 15:32:23 2015 -0800 +++ b/mx.truffle/suite.py Thu Dec 17 10:01:38 2015 +0100 @@ -58,6 +58,7 @@ "subDir" : "truffle", "sourceDirs" : ["src"], "dependencies" : [ + "com.oracle.truffle.api.profiles", "com.oracle.truffle.api.interop", "com.oracle.truffle.api.vm", "mx:JUNIT", @@ -145,6 +146,15 @@ "workingSets" : "API,Truffle", }, + "com.oracle.truffle.api.profiles" : { + "subDir" : "truffle", + "sourceDirs" : ["src"], + "dependencies" : ["com.oracle.truffle.api"], + "checkstyle" : "com.oracle.truffle.api", + "javaCompliance" : "1.7", + "workingSets" : "API,Truffle", + }, + "com.oracle.truffle.object" : { "subDir" : "truffle", "sourceDirs" : ["src"], @@ -262,6 +272,7 @@ "dependencies" : [ "com.oracle.truffle.api.interop.java", "com.oracle.truffle.api.dsl", + "com.oracle.truffle.api.profiles", "com.oracle.truffle.api.vm", "com.oracle.truffle.object.basic", ], diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java --- a/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java Wed Dec 16 15:32:23 2015 -0800 +++ b/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java Thu Dec 17 10:01:38 2015 +0100 @@ -26,7 +26,6 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.BranchProfile; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -93,7 +92,7 @@ * CompilerAsserts.compilationConstant(cachedOperand); * ... * } - * + * * Example executions: * execute(1) => doCached(1, 1) // new instantiation, localOperand is bound to 1 * execute(0) => doCached(0, 1) @@ -119,7 +118,7 @@ * CompilerAsserts.compilationConstant(cachedOperand); * ... * } - * + * * Example executions: * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0 * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1 @@ -147,10 +146,10 @@ * CompilerAsserts.compilationConstant(cachedOperand); * ... * } - * + * * @Specialization(contains = "doCached") * void doNormal(int operand) {...} - * + * * Example executions with contains = "doCached": * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0 * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1 @@ -158,7 +157,7 @@ * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2 * execute(3) => doNormal(3) // new instantiation of doNormal due to limit overflow; doCached gets removed. * execute(1) => doNormal(1) - * + * * Example executions without contains = "doCached": * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0 * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1 @@ -166,7 +165,7 @@ * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2 * execute(3) => doNormal(3) // new instantiation of doNormal due to limit overflow * execute(1) => doCached(1, 1) - * + * * * * @@ -178,7 +177,7 @@ * @Specialization * void s(int operand, {@code @Cached}("transformLocal(operand)") int cachedOperand) { * } - * + * * int transformLocal(int operand) { * return operand & 0x42; * } @@ -194,9 +193,9 @@ * void s(Object operand, {@code @Cached}("new()") OtherNode someNode) { * someNode.execute(operand); * } - * + * * static class OtherNode extends Node { - * + * * public String execute(Object value) { * throw new UnsupportedOperationException(); * } @@ -208,7 +207,8 @@ *
  • * Java types without public constructor but with a static factory methods can be initialized by * just referencing its static factory method and its parameters. In this case - * {@link BranchProfile#create()} is used to instantiate the {@link BranchProfile} instance. + * {@link com.oracle.truffle.api.profiles.BranchProfile#create()} is used to instantiate the + * {@link com.oracle.truffle.api.profiles.BranchProfile} instance. * *
      * @Specialization
    diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/BranchProfile.java
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/BranchProfile.java	Thu Dec 17 10:01:38 2015 +0100
    @@ -0,0 +1,143 @@
    +/*
    + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package com.oracle.truffle.api.profiles;
    +
    +import com.oracle.truffle.api.CompilerDirectives;
    +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
    +import com.oracle.truffle.api.Truffle;
    +
    +/**
    + * 

    + * BranchProfiles are profiles to speculate on branches that are unlikely to be visited. If the + * {@link #enter()} method is invoked first the optimized code is invalidated and the branch where + * {@link #enter()} is invoked is enabled for compilation. Otherwise if the {@link #enter()} method + * was never invoked the branch will not get compiled. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + * 
    + *     final BranchProfile errorProfile = BranchProfile.create();
    + * 
    + *     void execute(int value) {
    + *         if (value == Integer.MAX_VALUE) {
    + *             errorProfile.enter();
    + *             throw new Error("Invalid input value")
    + *         }
    + *         return value;
    + *     }
    + * }
    + * 
    + * + * {@inheritDoc} + * + * @see BranchProfile#enter() + */ +public abstract class BranchProfile extends Profile { + + BranchProfile() { + } + + /** + * Call when an unlikely branch is entered. + */ + public abstract void enter(); + + /** + * @deprecated it is not reliable when profiling is turned off. + */ + @Deprecated + public abstract boolean isVisited(); + + /** + * Call to create a new instance of a branch profile. + */ + public static BranchProfile create() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create0(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends BranchProfile { + + @CompilationFinal private boolean visited; + + @Override + public void enter() { + if (!visited) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visited = true; + } + } + + @SuppressWarnings("deprecation") + @Override + public boolean isVisited() { + return visited; + } + + @Override + public String toString() { + return toString(BranchProfile.class, !visited, false, "VISITED"); + } + + /* Needed for lazy class loading. */ + static BranchProfile create0() { + return new Enabled(); + } + } + + static final class Disabled extends BranchProfile { + + static final BranchProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public void enter() { + } + + @SuppressWarnings("deprecation") + @Override + public boolean isVisited() { + return true; + } + + @Override + public String toString() { + return toStringDisabled(BranchProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ByteValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ByteValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of byte runtime values. + * Value profiles require a runtime check in their initialized state to verify their profiled + * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if + * two or more values are profiled within a single profile then the profile has no effect. If the + * value assumption is invalidated in compiled code then it is invalidated. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + *
    + *     final ByteValueProfile profile = ByteValueProfile.createIdentityProfile();
    + *
    + *     byte execute(byte input) {
    + *         byte profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profiledValue;
    + *     }
    + * }
    + * 
    + *

    + * + * + * {@inheritDoc} + * + * @see #createIdentityProfile() + * @see ValueProfile + */ +public abstract class ByteValueProfile extends Profile { + + ByteValueProfile() { + } + + public abstract byte profile(byte value); + + /** + * Returns a value profile that profiles the exact value of a byte. + * + * @see ByteValueProfile + */ + public static ByteValueProfile createIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends ByteValueProfile { + + private static final byte UNINITIALIZED = 0; + private static final byte SPECIALIZED = 1; + private static final byte GENERIC = 2; + + @CompilationFinal private byte cachedValue; + @CompilationFinal private byte state = 0; + + @Override + public byte profile(byte value) { + byte localState = this.state; + if (localState != GENERIC) { + if (localState == SPECIALIZED) { + byte v = cachedValue; + if (v == value) { + return v; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (localState == UNINITIALIZED) { + this.cachedValue = value; + this.state = SPECIALIZED; + } else { + this.state = GENERIC; + } + } + return value; + } + + boolean isGeneric() { + return state == GENERIC; + } + + boolean isUninitialized() { + return state == UNINITIALIZED; + } + + byte getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(ByteValueProfile.class, state == UNINITIALIZED, state == GENERIC, // + String.format("value == (byte)%s", cachedValue)); + } + + /* Needed for lazy class loading. */ + static ByteValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends ByteValueProfile { + + static final ByteValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public byte profile(byte value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(ByteValueProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ConditionProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ConditionProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * ConditionProfiles are useful to profile the outcome of conditions. + *

    + * + *

    + * Usage example: + * + *

    + * class AbsoluteNode extends Node {
    + * 
    + *     final ConditionProfile greaterZeroProfile = ConditionProfile.create{Binary,Counting}Profile();
    + * 
    + *     void execute(int value) {
    + *         if (greaterZeroProfile.profile(value >= 0)) {
    + *             return value;
    + *         } else {
    + *             return -value;
    + *         }
    + *     }
    + * }
    + * 
    + * + * {@inheritDoc} + * + * @see #createBinaryProfile() + * @see #createCountingProfile() + * @see LoopConditionProfile + */ +public abstract class ConditionProfile extends Profile { + + ConditionProfile() { + } + + public abstract boolean profile(boolean value); + + /** + * Returns a {@link ConditionProfile} that speculates on conditions to be never + * true or to be never false. Additionally to a binary profile this + * method returns a condition profile that also counts the number of times the condition was + * true and false. This information is reported to the underlying optimization system using + * {@link CompilerDirectives#injectBranchProbability(double, boolean)}. Condition profiles are + * intended to be used as part of if conditions. + * + * @see ConditionProfile + * @see #createBinaryProfile() + */ + public static ConditionProfile createCountingProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Counting.create(); + } else { + return Disabled.INSTANCE; + } + } + + /** + * Returns a {@link ConditionProfile} that speculates on conditions to be never + * true or to be never false. Condition profiles are intended to be + * used as part of if conditions. + * + * @see ConditionProfile + * @see ConditionProfile#createCountingProfile() + */ + public static ConditionProfile createBinaryProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Binary.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Disabled extends ConditionProfile { + + static final ConditionProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public boolean profile(boolean value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(ConditionProfile.class); + } + + } + + static final class Counting extends ConditionProfile { + + @CompilationFinal private int trueCount; + @CompilationFinal private int falseCount; + + Counting() { + /* package protected constructor */ + } + + @Override + public boolean profile(boolean value) { + if (CompilerDirectives.inInterpreter()) { + if (value) { + // local required to guarantee no overflow in multi-threaded environments + int t = trueCount; + if (t < Integer.MAX_VALUE) { + trueCount = t + 1; + } + } else { + // local required to guarantee no overflow in multi-threaded environments + int f = falseCount; + if (f < Integer.MAX_VALUE) { + falseCount = f + 1; + } + } + // no branch probability calculation in the interpreter + return value; + } else { + // use trueCount and falseCount as locals for compilation speed + int t = trueCount; + int f = falseCount; + if (value) { + if (t == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + t = 1; + } + } else { + if (f == 0) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + f = 1; + } + } + return CompilerDirectives.injectBranchProbability((double) t / (double) (t + f), value); + } + } + + int getTrueCount() { + return trueCount; + } + + int getFalseCount() { + return falseCount; + } + + @Override + public String toString() { + int t = trueCount; + int f = falseCount; + return toString(ConditionProfile.class, trueCount == 0 && falseCount == 0, false, // + String.format("trueProbability=%s (trueCount=%s, falseCount=%s)", (double) t / (double) (t + f), t, f)); + } + + /* Needed for lazy class loading. */ + static ConditionProfile create() { + return new Counting(); + } + } + + /** + * Utility class to speculate on conditions to be never true or to be never false. Condition + * profiles are intended to be used as part of if conditions. + * + * @see ConditionProfile#createBinaryProfile() + */ + static final class Binary extends ConditionProfile { + + @CompilationFinal private boolean wasTrue; + @CompilationFinal private boolean wasFalse; + + Binary() { + /* package protected constructor */ + } + + @Override + public boolean profile(boolean value) { + if (value) { + if (!wasTrue) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + wasTrue = true; + } + return true; + } else { + if (!wasFalse) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + wasFalse = true; + } + return false; + } + } + + boolean wasTrue() { + return wasTrue; + } + + boolean wasFalse() { + return wasFalse; + } + + @Override + public String toString() { + return String.format("%s(wasTrue=%s, wasFalse=%s)@%x", getClass().getSimpleName(), wasTrue, wasFalse, hashCode()); + } + + /* Needed for lazy class loading. */ + static ConditionProfile create() { + return new Binary(); + } + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of double runtime values. + * Value profiles require a runtime check in their initialized state to verify their profiled + * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if + * two or more values are profiled within a single profile then the profile has no effect. If the + * value assumption is invalidated in compiled code then it is invalidated. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + *
    + *     final DoubleValueProfile profile = DoubleValueProfile.createRawIdentityProfile();
    + *
    + *     double execute(double input) {
    + *         double profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profiledValue;
    + *     }
    + * }
    + * 
    + *

    + * + * + * {@inheritDoc} + * + * @see #createRawIdentityProfile() + * @see ValueProfile + */ +public abstract class DoubleValueProfile extends Profile { + + DoubleValueProfile() { + } + + public abstract double profile(double value); + + /** + * Returns a value profile that profiles the exact value of a double using + * {@link Double#doubleToRawLongBits(double)}. + * + * @see IntValueProfile + */ + public static DoubleValueProfile createRawIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends DoubleValueProfile { + + private static final byte UNINITIALIZED = 0; + private static final byte SPECIALIZED = 1; + private static final byte GENERIC = 2; + + @CompilationFinal private double cachedValue; + @CompilationFinal private long cachedRawValue; + @CompilationFinal private byte state = 0; + + @Override + public double profile(double value) { + byte localState = this.state; + if (localState != GENERIC) { + if (localState == SPECIALIZED) { + if (cachedRawValue == Double.doubleToRawLongBits(value)) { + return cachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (localState == UNINITIALIZED) { + this.cachedValue = value; + this.cachedRawValue = Double.doubleToRawLongBits(value); + this.state = SPECIALIZED; + } else { + this.state = GENERIC; + } + } + return value; + } + + boolean isGeneric() { + return state == GENERIC; + } + + boolean isUninitialized() { + return state == UNINITIALIZED; + } + + double getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(DoubleValueProfile.class, state == UNINITIALIZED, state == GENERIC, // + String.format("value == (double)%s (raw %h)", cachedValue, cachedRawValue)); + } + + /* Needed for lazy class loading. */ + static DoubleValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends DoubleValueProfile { + + static final DoubleValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public double profile(double value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(DoubleValueProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/FloatValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/FloatValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of float runtime values. + * Value profiles require a runtime check in their initialized state to verify their profiled + * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if + * two or more values are profiled within a single profile then the profile has no effect. If the + * value assumption is invalidated in compiled code then it is invalidated. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + * 
    + *     final FloatValueProfile profile = FloatValueProfile.createRawIdentityProfile();
    + * 
    + *     float execute(float input) {
    + *         float profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profiledValue;
    + *     }
    + * }
    + * 
    + *

    + * + * + * {@inheritDoc} + * + * @see #createRawIdentityProfile() + * @see ValueProfile + */ +public abstract class FloatValueProfile extends Profile { + + FloatValueProfile() { + } + + public abstract float profile(float value); + + /** + * Returns a value profile that profiles the exact value of a float using + * {@link Float#floatToRawIntBits(float)}. + * + * @see IntValueProfile + */ + public static FloatValueProfile createRawIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends FloatValueProfile { + + private static final byte UNINITIALIZED = 0; + private static final byte SPECIALIZED = 1; + private static final byte GENERIC = 2; + + @CompilationFinal private float cachedValue; + @CompilationFinal private int cachedRawValue; + @CompilationFinal private byte state = 0; + + @Override + public float profile(float value) { + byte localState = this.state; + if (localState != GENERIC) { + if (localState == SPECIALIZED) { + if (cachedRawValue == Float.floatToRawIntBits(value)) { + return cachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (localState == UNINITIALIZED) { + this.cachedValue = value; + this.cachedRawValue = Float.floatToRawIntBits(value); + this.state = SPECIALIZED; + } else { + this.state = GENERIC; + } + } + return value; + } + + boolean isGeneric() { + return state == GENERIC; + } + + boolean isUninitialized() { + return state == UNINITIALIZED; + } + + float getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(FloatValueProfile.class, state == UNINITIALIZED, state == GENERIC, // + String.format("value == (float)%s (raw %h)", cachedValue, cachedRawValue)); + } + + /* Needed for lazy class loading. */ + static FloatValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends FloatValueProfile { + + static final FloatValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public float profile(float value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(FloatValueProfile.class); + } + + } +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/IntValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/IntValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of int runtime values. Value + * profiles require a runtime check in their initialized state to verify their profiled assumption. + * Value profiles are limited to capture monomorphic profiles only. This means that if two or more + * values are profiled within a single profile then the profile has no effect. If the value + * assumption is invalidated in compiled code then it is invalidated. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + *
    + *     final IntValueProfile profile = IntValueProfile.createIdentityProfile();
    + *
    + *     int execute(int input) {
    + *         int profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profiledValue;
    + *     }
    + * }
    + * 
    + *

    + * + * + * {@inheritDoc} + * + * @see #createIdentityProfile() + * @see ValueProfile + */ +public abstract class IntValueProfile extends Profile { + + IntValueProfile() { + } + + public abstract int profile(int value); + + /** + * Returns a value profile that profiles the exact value of an int. + * + * @see IntValueProfile + */ + public static IntValueProfile createIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends IntValueProfile { + + private static final byte UNINITIALIZED = 0; + private static final byte SPECIALIZED = 1; + private static final byte GENERIC = 2; + + @CompilationFinal private int cachedValue; + @CompilationFinal private byte state = 0; + + @Override + public int profile(int value) { + byte localState = this.state; + if (localState != GENERIC) { + if (localState == SPECIALIZED) { + int v = cachedValue; + if (v == value) { + return v; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (localState == UNINITIALIZED) { + this.cachedValue = value; + this.state = SPECIALIZED; + } else { + this.state = GENERIC; + } + } + return value; + } + + boolean isGeneric() { + return state == GENERIC; + } + + boolean isUninitialized() { + return state == UNINITIALIZED; + } + + int getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(IntValueProfile.class, isUninitialized(), isGeneric(), // + String.format("value == (int)%s", cachedValue)); + } + + /* Needed for lazy class loading. */ + static IntValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends IntValueProfile { + + static final IntValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public int profile(int value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(IntValueProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/LongValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/LongValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of long runtime values. + * Value profiles require a runtime check in their initialized state to verify their profiled + * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if + * two or more values are profiled within a single profile then the profile has no effect. If the + * value assumption is invalidated in compiled code then it is invalidated. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + *
    + *     final LongValueProfile profile = LongValueProfile.createIdentityProfile();
    + *
    + *     long execute(long input) {
    + *         long profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profiledValue;
    + *     }
    + * }
    + * 
    + *

    + * + * {@inheritDoc} + * + * @see #createIdentityProfile() + * @see ValueProfile + */ +public abstract class LongValueProfile extends Profile { + + LongValueProfile() { + } + + public abstract long profile(long value); + + /** + * Returns a value profile that profiles the exact value of an long. + * + * @see LongValueProfile + */ + public static LongValueProfile createIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends LongValueProfile { + + private static final byte UNINITIALIZED = 0; + private static final byte SPECIALIZED = 1; + private static final byte GENERIC = 2; + + @CompilationFinal private long cachedValue; + @CompilationFinal private byte state = 0; + + @Override + public long profile(long value) { + byte localState = this.state; + if (localState != GENERIC) { + if (localState == SPECIALIZED) { + long v = cachedValue; + if (v == value) { + return v; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (localState == UNINITIALIZED) { + this.cachedValue = value; + this.state = SPECIALIZED; + } else { + this.state = GENERIC; + } + } + return value; + } + + boolean isGeneric() { + return state == GENERIC; + } + + boolean isUninitialized() { + return state == UNINITIALIZED; + } + + long getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(LongValueProfile.class, state == UNINITIALIZED, state == GENERIC, // + String.format("value == (long)%s", cachedValue)); + } + + /* Needed for lazy class loading. */ + static LongValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends LongValueProfile { + + static final LongValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public long profile(long value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(LongValueProfile.class); + } + + } +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * LoopConditionProfiles are designed to profile the outcome of loop conditions. Loop profiles can + * be used to profile unpredictable loops as well as predictable loops. + *

    + * + *

    + * Arbitrary loop usage example: + * + *

    + * class LoopNode extends Node {
    + * 
    + *     final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
    + * 
    + *     void execute() {
    + *         // loop count cannot be predicted
    + *         while (loopProfile.profile(Math.random() >= 0.9)) {
    + *             // work
    + *         }
    + *     }
    + * }
    + * 
    + * + *

    + * + *

    + * Counted loop usage example: + * + *

    + * class CountedLoopNode extends Node {
    + * 
    + *     final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
    + * 
    + *     void execute(int length) {
    + *         // loop count can be predicted
    + *         loopProfile.profileCounted(length);
    + *         for (int i = 0; loopProfile.inject(i < length); i++) {
    + *             // work
    + *         }
    + *     }
    + * }
    + * 
    + * + *

    + *

    + * The advantage of using {@link #profileCounted(long)} to using {@link #profile(boolean)} is that + * it incurs less overhead in the interpreter. Using {@link LoopConditionProfile#inject(boolean)} is + * a no-op in the interpreter while {@link #profile(boolean)} needs to use a counter for each + * iteration. + *

    + * + * + * {@inheritDoc} + * + * @see #createBinaryProfile() + * @see #createCountingProfile() + * @see LoopConditionProfile + */ +public abstract class LoopConditionProfile extends ConditionProfile { + + LoopConditionProfile() { + } + + @Override + public abstract boolean profile(boolean value); + + /** + * Provides an alternative way to profile counted loops with less interpreter footprint. Please + * see {@link LoopConditionProfile} for an usage example. + * + * @see #inject(boolean) + */ + public abstract void profileCounted(long length); + + /** + * Provides an alternative way to profile counted loops with less interpreter footprint. Please + * see {@link LoopConditionProfile} for an usage example. + * + * @see #inject(boolean) + */ + public abstract boolean inject(boolean condition); + + /** + * Returns a {@link LoopConditionProfile} that speculates on loop conditions to be never + * true. It also captures loop probabilities for the compiler. Loop condition + * profiles are intended to be used for loop conditions. + * + * @see LoopConditionProfile + */ + public static LoopConditionProfile createCountingProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Enabled extends LoopConditionProfile { + + @CompilationFinal private long trueCount; // long for long running loops. + @CompilationFinal private int falseCount; + + @Override + public boolean profile(boolean condition) { + if (CompilerDirectives.inInterpreter()) { + if (condition) { + // local required to guarantee no overflow in multi-threaded environments + long localTrueCount = trueCount; + if (localTrueCount < Long.MAX_VALUE) { + trueCount = localTrueCount + 1; + } + } else { + // local required to guarantee no overflow in multi-threaded environments + int localFalseCount = falseCount; + if (localFalseCount < Integer.MAX_VALUE) { + falseCount = localFalseCount + 1; + } + } + // no branch probability calculation in the interpreter + return condition; + } else { + long trueCountLocal = trueCount; + int falseCountLocal = falseCount; + if (trueCountLocal == 0) { + /* Deopt for never entering the loop. */ + if (condition) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + trueCount = trueCountLocal = 1; + } + } + /* No deopt for not entering the loop. */ + return CompilerDirectives.injectBranchProbability(calculateProbability(trueCountLocal, falseCountLocal), condition); + } + } + + @Override + public void profileCounted(long length) { + if (CompilerDirectives.inInterpreter()) { + long trueCountLocal = trueCount + length; + if (trueCountLocal >= 0) { // don't write overflow values + trueCount = trueCountLocal; + int falseCountLocal = falseCount; + if (falseCountLocal < Integer.MAX_VALUE) { + falseCount = falseCountLocal + 1; + } + } + } + } + + @Override + public boolean inject(boolean condition) { + if (CompilerDirectives.inCompiledCode()) { + return CompilerDirectives.injectBranchProbability(calculateProbability(trueCount, falseCount), condition); + } else { + return condition; + } + } + + private static double calculateProbability(long trueCountLocal, int falseCountLocal) { + if (falseCountLocal == 0 && trueCountLocal == 0) { + /* Avoid division by zero if profile was never used. */ + return 0.0; + } else { + return (double) trueCountLocal / (double) (trueCountLocal + falseCountLocal); + } + } + + /* for testing */ + long getTrueCount() { + return trueCount; + } + + /* for testing */ + int getFalseCount() { + return falseCount; + } + + @Override + public String toString() { + return toString(LoopConditionProfile.class, falseCount == 0, false, // + String.format("trueProbability=%s (trueCount=%s, falseCount=%s)", calculateProbability(trueCount, falseCount), falseCount, trueCount)); + } + + /* Needed for lazy class loading. */ + static LoopConditionProfile create() { + return new Enabled(); + } + + } + + static final class Disabled extends LoopConditionProfile { + + static final LoopConditionProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public boolean profile(boolean condition) { + return condition; + } + + @Override + public void profileCounted(long length) { + } + + @Override + public boolean inject(boolean condition) { + return condition; + } + + @Override + public String toString() { + return toStringDisabled(LoopConditionProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import java.util.Objects; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Represents a {@link ValueProfile} that speculates on the primitive equality or object identity of + * values. Note that for {@code float} and {@code double} values we compare primitive equality via + * {@link Float#floatToRawIntBits} and {@link Double#doubleToRawLongBits}, so that for example + * {@code -0.0} is not considered the same as {@code 0.0}, even though primitive equality would + * normally say that it was. + *

    + * + * {@inheritDoc} + */ +public abstract class PrimitiveValueProfile extends ValueProfile { + + PrimitiveValueProfile() { + } + + @Override + public abstract T profile(T value); + + public abstract byte profile(byte value); + + public abstract short profile(short value); + + public abstract int profile(int value); + + public abstract long profile(long value); + + public abstract float profile(float value); + + public abstract double profile(double value); + + public abstract boolean profile(boolean value); + + public abstract char profile(char value); + + /** + * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or object + * identity of a value. + */ + public static PrimitiveValueProfile createEqualityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Enabled.create(); + } else { + return Disabled.INSTANCE; + } + } + + /** + * @deprecated going to get removed without replacement + */ + @Deprecated + public static boolean exactCompare(float a, float b) { + /* + * -0.0 == 0.0, but you can tell the difference through other means, so we need to + * differentiate. + */ + return Float.floatToRawIntBits(a) == Float.floatToRawIntBits(b); + } + + /** + * @deprecated going to get removed without replacement + */ + @Deprecated + public static boolean exactCompare(double a, double b) { + /* + * -0.0 == 0.0, but you can tell the difference through other means, so we need to + * differentiate. + */ + return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b); + } + + static final class Enabled extends PrimitiveValueProfile { + + private static final byte STATE_UNINITIALIZED = 0; + private static final byte STATE_BYTE = 1; + private static final byte STATE_SHORT = 2; + private static final byte STATE_INTEGER = 3; + private static final byte STATE_LONG = 4; + private static final byte STATE_BOOLEAN = 5; + private static final byte STATE_CHARACTER = 6; + private static final byte STATE_FLOAT = 7; + private static final byte STATE_DOUBLE = 8; + private static final byte STATE_IDENTITY = 9; + private static final byte STATE_GENERIC = 10; + + @CompilationFinal private byte state = STATE_UNINITIALIZED; + @CompilationFinal private Object cachedValue; + + Enabled() { + } + + @SuppressWarnings("unchecked") + @Override + public T profile(T value) { + byte s = this.state; + Object snapshot; + switch (s) { + case STATE_BYTE: + case STATE_SHORT: + case STATE_INTEGER: + case STATE_LONG: + case STATE_BOOLEAN: + case STATE_CHARACTER: + snapshot = this.cachedValue; + if (snapshot.equals(value)) { + return (T) snapshot; + } + break; + case STATE_DOUBLE: + snapshot = this.cachedValue; + if (value instanceof Double && exactCompare((Double) snapshot, (Double) value)) { + return (T) snapshot; + } + break; + case STATE_FLOAT: + snapshot = this.cachedValue; + if (value instanceof Float && exactCompare((Float) snapshot, (Float) value)) { + return (T) snapshot; + } + break; + case STATE_IDENTITY: + snapshot = this.cachedValue; + if (snapshot == value) { + return (T) snapshot; + } + break; + case STATE_GENERIC: + return value; + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + return value; + } + + @Override + public byte profile(byte value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_BYTE) { + byte castCachedValue = (byte) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public short profile(short value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_SHORT) { + short castCachedValue = (short) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public int profile(int value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_INTEGER) { + int castCachedValue = (int) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public long profile(long value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_LONG) { + long castCachedValue = (long) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public float profile(float value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_FLOAT) { + float castCachedValue = (float) this.cachedValue; + if (exactCompare(castCachedValue, value)) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public double profile(double value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_DOUBLE) { + double castCachedValue = (double) this.cachedValue; + if (exactCompare(castCachedValue, value)) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + + } + + @Override + public boolean profile(boolean value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_BOOLEAN) { + boolean castCachedValue = (boolean) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + @Override + public char profile(char value) { + byte s = this.state; + if (s != STATE_GENERIC) { + if (s == STATE_CHARACTER) { + char castCachedValue = (char) this.cachedValue; + if (castCachedValue == value) { + return castCachedValue; + } + } + CompilerDirectives.transferToInterpreterAndInvalidate(); + slowpath(s, value); + } + return value; + } + + private void slowpath(byte s, Object value) { + if (s == STATE_UNINITIALIZED) { + cachedValue = value; + state = specialize(value); + } else { + state = STATE_GENERIC; + cachedValue = null; + } + } + + private static byte specialize(Object value) { + if (value instanceof Byte) { + return STATE_BYTE; + } else if (value instanceof Short) { + return STATE_SHORT; + } else if (value instanceof Integer) { + return STATE_INTEGER; + } else if (value instanceof Long) { + return STATE_LONG; + } else if (value instanceof Boolean) { + return STATE_BOOLEAN; + } else if (value instanceof Character) { + return STATE_CHARACTER; + } else if (value instanceof Double) { + return STATE_DOUBLE; + } else if (value instanceof Float) { + return STATE_FLOAT; + } else { + return STATE_IDENTITY; + } + } + + boolean isGeneric() { + return state == STATE_GENERIC; + } + + boolean isUninitialized() { + return state == STATE_UNINITIALIZED; + } + + Object getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(PrimitiveValueProfile.class, state == STATE_UNINITIALIZED, state == STATE_GENERIC, formatSpecialization()); + } + + private String formatSpecialization() { + Object snapshot = this.cachedValue; + if (state != STATE_UNINITIALIZED && state != STATE_GENERIC) { + if (snapshot == null) { + return String.format("value == null"); + } else { + if (state == STATE_IDENTITY) { + String simpleName = snapshot.getClass().getSimpleName(); + return String.format("value == %s@%x", simpleName, Objects.hash(snapshot)); + } else { + return String.format("value == (%s)%s", snapshot.getClass().getSimpleName(), snapshot); + } + } + } + return null; + } + + /** + * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or + * object identity of a value. + */ + static PrimitiveValueProfile create() { + return new Enabled(); + } + } + + static final class Disabled extends PrimitiveValueProfile { + + static final PrimitiveValueProfile INSTANCE = new Disabled(); + + @Override + public T profile(T value) { + return value; + } + + @Override + public byte profile(byte value) { + return value; + } + + @Override + public short profile(short value) { + return value; + } + + @Override + public int profile(int value) { + return value; + } + + @Override + public long profile(long value) { + return value; + } + + @Override + public float profile(float value) { + return value; + } + + @Override + public double profile(double value) { + return value; + } + + @Override + public boolean profile(boolean value) { + return value; + } + + @Override + public char profile(char value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(PrimitiveValueProfile.class); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/Profile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/Profile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.TruffleRuntime; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeCloneable; +import com.oracle.truffle.api.nodes.RootNode; + +/** + *

    + * A profile is a Truffle utility class that uses the {@link CompilerDirectives Truffle compiler + * directives} to guard for and/or forward runtime information to the compiler. + *

    + * + *

    + * Usage: Profiles should be stored in final or {@link CompilationFinal + * compilation final} fields of node classes to ensure that they can get optimized properly. + * Profiles must not be shared between ASTs. Using the same profile multiple times in a single + * {@link Node node} or in multiple {@link Node nodes} which {@link Node#getRootNode() link} to the + * same {@link RootNode root} is allowed. Never store profiles inside runtime values that + * leave the scope of the originating AST. This limitation exists because the used mechanism to + * invalidate compiled code performs local invalidations only. For global speculations use + * {@link Assumption assumptions} instead. + *

    + * + *

    + * Compilation: Some profiles like {@link BranchProfile branch} profiles do not induce + * additional overhead in compiled code. Others like {@link ValueProfile value} profiles might + * require a runtime check to verify their assumptions which are forwarded to the compiler. Even if + * profiles do not induce direct overhead in compiled code it still might get invalidated as a + * result of using profiles. Invalidating profiles will result in the invalidation of compiled code. + * It is therefore essential to place these profiles in way that is neither too aggressive nor too + * conservative. + *

    + * + *

    + * Footprint: Whether profiling information can be forwarded to the compiler depends on the + * capabilities of the {@link TruffleRuntime runtime system}. If the runtime returns + * true in {@link TruffleRuntime#isProfilingEnabled()} then runtime information will + * get collected. This comes at at the cost of additional overhead and footprint in interpreted + * mode. Thats why the factory methods of profiles can return implementations where profiling is + * disabled. Using disabled profiles makes sense for runtimes that are unable to use the collected + * profiling information. Even runtime implementations that are able to use this information might + * decide to turn off profiling for benchmarking purposes. + *

    + * + *

    + * Profile subclasses: + *

      + *
    • {@link BranchProfile} to profile on unlikely branches like errors.
    • + *
    • {@link ConditionProfile} to profile on conditionals or boolean values.
    • + *
    • {@link LoopConditionProfile} to profile on conditionals of loops with special support for + * counted loops.
    • + *
    • {@link ValueProfile} to profile on properties like type and identity of values.
    • + *
    • {@link ByteValueProfile} to profile on byte values.
    • + *
    • {@link IntValueProfile} to profile on int values.
    • + *
    • {@link LongValueProfile} to profile on long values.
    • + *
    • {@link FloatValueProfile} to profile on float values.
    • + *
    • {@link DoubleValueProfile} to profile on double values.
    • + *
    • {@link PrimitiveValueProfile} to profile on objects by identity and on primitives by value.
    • + *
    + *

    + * + * @see Assumption + */ +public abstract class Profile extends NodeCloneable { + + Profile() { + /* We don't to allow custom profiles. We want to evolve this API further first. Sorry. */ + } + + String toStringDisabled(Class profileClass) { + return String.format("%s(DISABLED)", profileClass.getSimpleName()); + } + + String toString(Class profileClass, boolean uninitialized, boolean generic, String specialization) { + String s; + if (uninitialized) { + s = "UNINITIALIZED"; + } else if (generic) { + s = "GENERIC"; + } else { + s = specialization == null ? "" : specialization; + } + return String.format("%s(%s)@%s", profileClass.getSimpleName(), s, Integer.toHexString(this.hashCode())); + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ValueProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/ValueProfile.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.profiles; + +import java.util.Objects; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.Truffle; + +/** + *

    + * Specialized value profile to capture certain properties of Object runtime values. + * Value profiles require a runtime check in their initialized state to verify their profiled + * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if + * two or more identities or classes are profiles within a single profile then the profile has no + * effect and no overhead after compilation. There are specialized versions of this profile with + * less interpreter footprint for {@link ConditionProfile boolean}, {@link ByteValueProfile byte}, + * {@link IntValueProfile int}, {@link LongValueProfile long}, {@link FloatValueProfile float} and + * {@link DoubleValueProfile double} values. + *

    + * + *

    + * Usage example: + * + *

    + * class SampleNode extends Node {
    + *
    + * final ValueProfile profile = ValueProfile.create{Identity,Class}Profile();
    + *
    + *     Object execute(Object input) {
    + *         Object profiledValue = profile.profile(input);
    + *         // compiler may know now more about profiledValue
    + *         return profieldValue;
    + *     }
    + * }
    + * 
    + *

    + * + * + * {@inheritDoc} + * + * @see #createIdentityProfile() + * @see #createClassProfile() + */ +public abstract class ValueProfile extends Profile { + + ValueProfile() { + } + + public abstract T profile(T value); + + /** + *

    + * Returns a value profile that profiles the exact class of a value. It will check the class of + * the profiled value and provide additional information to the compiler if only non-null values + * of exactly one concrete Java class are passed as a parameter to the + * {@link ValueProfile#profile} method. This can be beneficial if subsequent code can take + * advantage of knowing the concrete class of the value. The profile will degrade to the generic + * case if a null value or if at least two instances of two different Java classes are + * registered. + *

    + * + *

    + * Compilation notes: Value profiles require a runtime check in their initialized state + * to verify their profiled class. If two classes have been seen on a single profile instance + * then this profile will transition to a generic state with no overhead. + *

    + * + * @see ValueProfile usage example + */ + public static ValueProfile createClassProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return ExactClass.create(); + } else { + return Disabled.INSTANCE; + } + } + + /** + *

    + * Returns a value profile that profiles the object identity of a value. A single instance can + * only profile one particular instance. + *

    + * + *

    + * Compilation notes: Identity profiles require a runtime check to verify their profiled + * object identity. If two identities have been seen on a single profile instance then this + * profile will transition to a generic state with no overhead. + *

    + */ + public static ValueProfile createIdentityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Identity.create(); + } else { + return Disabled.INSTANCE; + } + } + + /** + *

    + * Returns a value profile that profiles the object equality of a value. A single instance can + * only profile one set of equal values. + *

    + * + *

    + * Compilation notes: Equality profiles inline the body of the equal method of the first + * profiled value in order to verify its assumption. Please take care that you do this only for + * equals implementations that your guest language actually has control over otherwise your + * compiled code might contain recursions or too much code. If two non equal objects have been + * seen on a single profile instance then this profile will transition to a generic state with + * no overhead. + *

    + */ + public static ValueProfile createEqualityProfile() { + if (Truffle.getRuntime().isProfilingEnabled()) { + return Equality.create(); + } else { + return Disabled.INSTANCE; + } + } + + static final class Disabled extends ValueProfile { + + static final ValueProfile INSTANCE = new Disabled(); + + @Override + protected Object clone() { + return INSTANCE; + } + + @Override + public T profile(T value) { + return value; + } + + @Override + public String toString() { + return toStringDisabled(ValueProfile.class); + } + + } + + static final class Equality extends ValueProfile { + + private static final Object GENERIC = new Object(); + + @CompilationFinal protected Object cachedValue = null; + + Equality() { + } + + @Override + @SuppressWarnings("unchecked") + public T profile(T newValue) { + // Field needs to be cached in local variable for thread safety and startup speed. + Object cached = this.cachedValue; + if (cached != GENERIC) { + if (cached != null && cached.equals(newValue)) { + return (T) cached; + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (cached == null && newValue != null) { + cachedValue = newValue; + } else { + cachedValue = GENERIC; + } + } + } + return newValue; + } + + public boolean isGeneric() { + return getCachedValue() == GENERIC; + } + + public boolean isUninitialized() { + return getCachedValue() == null; + } + + public Object getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(ValueProfile.class, isUninitialized(), isGeneric(), // + String.format("value == %s@%x", cachedValue != null ? cachedValue.getClass().getSimpleName() : "null", Objects.hash(cachedValue))); + } + + /* Needed for lazy class loading. */ + static ValueProfile create() { + return new Equality(); + } + + } + + static final class Identity extends ValueProfile { + + private static final Object UNINITIALIZED = new Object(); + private static final Object GENERIC = new Object(); + + @CompilationFinal protected Object cachedValue = UNINITIALIZED; + + Identity() { + } + + @Override + @SuppressWarnings("unchecked") + public T profile(T newValue) { + // Field needs to be cached in local variable for thread safety and startup speed. + Object cached = this.cachedValue; + if (cached != GENERIC) { + if (cached == newValue) { + return (T) cached; + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (cachedValue == UNINITIALIZED) { + cachedValue = newValue; + } else { + cachedValue = GENERIC; + } + } + } + return newValue; + } + + public boolean isGeneric() { + return getCachedValue() == GENERIC; + } + + public boolean isUninitialized() { + return getCachedValue() == UNINITIALIZED; + } + + public Object getCachedValue() { + return cachedValue; + } + + @Override + public String toString() { + return toString(ValueProfile.class, isUninitialized(), isGeneric(), // + String.format("value == %s@%x", cachedValue != null ? cachedValue.getClass().getSimpleName() : "null", Objects.hash(cachedValue))); + } + + /* Needed for lazy class loading. */ + static ValueProfile create() { + return new Identity(); + } + + } + + static final class ExactClass extends ValueProfile { + + @CompilationFinal protected Class cachedClass; + + ExactClass() { + } + + public static ValueProfile create() { + return new ExactClass(); + } + + @SuppressWarnings("unchecked") + @Override + public T profile(T value) { + // Field needs to be cached in local variable for thread safety and startup speed. + Class clazz = cachedClass; + if (clazz != Object.class) { + if (clazz != null && value != null && clazz == value.getClass()) { + /* + * The cast is really only for the compiler relevant. It does not perform any + * useful action in the interpreter and only takes time. + */ + if (CompilerDirectives.inInterpreter()) { + return value; + } else { + return (T) clazz.cast(value); + } + } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (clazz == null && value != null) { + cachedClass = value.getClass(); + } else { + cachedClass = Object.class; + } + } + } + return value; + } + + boolean isGeneric() { + return cachedClass == Object.class; + } + + boolean isUninitialized() { + return cachedClass == null; + } + + Class getCachedClass() { + return cachedClass; + } + + @Override + public String toString() { + return toString(ValueProfile.class, cachedClass == null, cachedClass == Object.class, // + String.format("value.getClass() == %s.class", cachedClass != null ? cachedClass.getSimpleName() : "null")); + } + + } + +} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.profiles/src/com/oracle/truffle/api/profiles/package-info.java Thu Dec 17 10:01:38 2015 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @ApiInfo( + group="Stable" + ) + */ +/** + * A profile is a Truffle utility class that uses the + * {@link com.oracle.truffle.api.CompilerDirectives Truffle compiler directives} to guard for and/or + * forward runtime information to the compiler. + * + * @see com.oracle.truffle.api.profiles.Profile + */ +package com.oracle.truffle.api.profiles; + diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/BranchProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/BranchProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * BranchProfiles are profiles to speculate on branches that are unlikely to be visited. If the - * {@link #enter()} method is invoked first the optimized code is invalidated and the branch where - * {@link #enter()} is invoked is enabled for compilation. Otherwise if the {@link #enter()} method - * was never invoked the branch will not get compiled. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - * 
    - *     final BranchProfile errorProfile = BranchProfile.create();
    - * 
    - *     void execute(int value) {
    - *         if (value == Integer.MAX_VALUE) {
    - *             errorProfile.enter();
    - *             throw new Error("Invalid input value")
    - *         }
    - *         return value;
    - *     }
    - * }
    - * 
    - * - * {@inheritDoc} - * - * @see BranchProfile#enter() - */ -public abstract class BranchProfile extends Profile { - - BranchProfile() { - } - - /** - * Call when an unlikely branch is entered. - */ - public abstract void enter(); - - /** - * @deprecated it is not reliable when profiling is turned off. - */ - @Deprecated - public abstract boolean isVisited(); - - /** - * Call to create a new instance of a branch profile. - */ - public static BranchProfile create() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create0(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends BranchProfile { - - @CompilationFinal private boolean visited; - - @Override - public void enter() { - if (!visited) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - visited = true; - } - } - - @SuppressWarnings("deprecation") - @Override - public boolean isVisited() { - return visited; - } - - @Override - public String toString() { - return toString(BranchProfile.class, !visited, false, "VISITED"); - } - - /* Needed for lazy class loading. */ - static BranchProfile create0() { - return new Enabled(); - } - } - - static final class Disabled extends BranchProfile { - - static final BranchProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public void enter() { - } - - @SuppressWarnings("deprecation") - @Override - public boolean isVisited() { - return true; - } - - @Override - public String toString() { - return toStringDisabled(BranchProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ByteValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ByteValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of byte runtime values. - * Value profiles require a runtime check in their initialized state to verify their profiled - * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if - * two or more values are profiled within a single profile then the profile has no effect. If the - * value assumption is invalidated in compiled code then it is invalidated. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - *
    - *     final ByteValueProfile profile = ByteValueProfile.createIdentityProfile();
    - *
    - *     byte execute(byte input) {
    - *         byte profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profiledValue;
    - *     }
    - * }
    - * 
    - *

    - * - * - * {@inheritDoc} - * - * @see #createIdentityProfile() - * @see ValueProfile - */ -public abstract class ByteValueProfile extends Profile { - - ByteValueProfile() { - } - - public abstract byte profile(byte value); - - /** - * Returns a value profile that profiles the exact value of a byte. - * - * @see ByteValueProfile - */ - public static ByteValueProfile createIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends ByteValueProfile { - - private static final byte UNINITIALIZED = 0; - private static final byte SPECIALIZED = 1; - private static final byte GENERIC = 2; - - @CompilationFinal private byte cachedValue; - @CompilationFinal private byte state = 0; - - @Override - public byte profile(byte value) { - byte localState = this.state; - if (localState != GENERIC) { - if (localState == SPECIALIZED) { - byte v = cachedValue; - if (v == value) { - return v; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (localState == UNINITIALIZED) { - this.cachedValue = value; - this.state = SPECIALIZED; - } else { - this.state = GENERIC; - } - } - return value; - } - - boolean isGeneric() { - return state == GENERIC; - } - - boolean isUninitialized() { - return state == UNINITIALIZED; - } - - byte getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(ByteValueProfile.class, state == UNINITIALIZED, state == GENERIC, // - String.format("value == (byte)%s", cachedValue)); - } - - /* Needed for lazy class loading. */ - static ByteValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends ByteValueProfile { - - static final ByteValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public byte profile(byte value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(ByteValueProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ConditionProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ConditionProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * ConditionProfiles are useful to profile the outcome of conditions. - *

    - * - *

    - * Usage example: - * - *

    - * class AbsoluteNode extends Node {
    - * 
    - *     final ConditionProfile greaterZeroProfile = ConditionProfile.create{Binary,Counting}Profile();
    - * 
    - *     void execute(int value) {
    - *         if (greaterZeroProfile.profile(value >= 0)) {
    - *             return value;
    - *         } else {
    - *             return -value;
    - *         }
    - *     }
    - * }
    - * 
    - * - * {@inheritDoc} - * - * @see #createBinaryProfile() - * @see #createCountingProfile() - * @see LoopConditionProfile - */ -public abstract class ConditionProfile extends Profile { - - ConditionProfile() { - } - - public abstract boolean profile(boolean value); - - /** - * Returns a {@link ConditionProfile} that speculates on conditions to be never - * true or to be never false. Additionally to a binary profile this - * method returns a condition profile that also counts the number of times the condition was - * true and false. This information is reported to the underlying optimization system using - * {@link CompilerDirectives#injectBranchProbability(double, boolean)}. Condition profiles are - * intended to be used as part of if conditions. - * - * @see ConditionProfile - * @see #createBinaryProfile() - */ - public static ConditionProfile createCountingProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Counting.create(); - } else { - return Disabled.INSTANCE; - } - } - - /** - * Returns a {@link ConditionProfile} that speculates on conditions to be never - * true or to be never false. Condition profiles are intended to be - * used as part of if conditions. - * - * @see ConditionProfile - * @see ConditionProfile#createCountingProfile() - */ - public static ConditionProfile createBinaryProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Binary.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Disabled extends ConditionProfile { - - static final ConditionProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public boolean profile(boolean value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(ConditionProfile.class); - } - - } - - static final class Counting extends ConditionProfile { - - @CompilationFinal private int trueCount; - @CompilationFinal private int falseCount; - - Counting() { - /* package protected constructor */ - } - - @Override - public boolean profile(boolean value) { - if (CompilerDirectives.inInterpreter()) { - if (value) { - // local required to guarantee no overflow in multi-threaded environments - int t = trueCount; - if (t < Integer.MAX_VALUE) { - trueCount = t + 1; - } - } else { - // local required to guarantee no overflow in multi-threaded environments - int f = falseCount; - if (f < Integer.MAX_VALUE) { - falseCount = f + 1; - } - } - // no branch probability calculation in the interpreter - return value; - } else { - // use trueCount and falseCount as locals for compilation speed - int t = trueCount; - int f = falseCount; - if (value) { - if (t == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - t = 1; - } - } else { - if (f == 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - f = 1; - } - } - return CompilerDirectives.injectBranchProbability((double) t / (double) (t + f), value); - } - } - - int getTrueCount() { - return trueCount; - } - - int getFalseCount() { - return falseCount; - } - - @Override - public String toString() { - int t = trueCount; - int f = falseCount; - return toString(ConditionProfile.class, trueCount == 0 && falseCount == 0, false, // - String.format("trueProbability=%s (trueCount=%s, falseCount=%s)", (double) t / (double) (t + f), t, f)); - } - - /* Needed for lazy class loading. */ - static ConditionProfile create() { - return new Counting(); - } - } - - /** - * Utility class to speculate on conditions to be never true or to be never false. Condition - * profiles are intended to be used as part of if conditions. - * - * @see ConditionProfile#createBinaryProfile() - */ - static final class Binary extends ConditionProfile { - - @CompilationFinal private boolean wasTrue; - @CompilationFinal private boolean wasFalse; - - Binary() { - /* package protected constructor */ - } - - @Override - public boolean profile(boolean value) { - if (value) { - if (!wasTrue) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - wasTrue = true; - } - return true; - } else { - if (!wasFalse) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - wasFalse = true; - } - return false; - } - } - - boolean wasTrue() { - return wasTrue; - } - - boolean wasFalse() { - return wasFalse; - } - - @Override - public String toString() { - return String.format("%s(wasTrue=%s, wasFalse=%s)@%x", getClass().getSimpleName(), wasTrue, wasFalse, hashCode()); - } - - /* Needed for lazy class loading. */ - static ConditionProfile create() { - return new Binary(); - } - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of double runtime values. - * Value profiles require a runtime check in their initialized state to verify their profiled - * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if - * two or more values are profiled within a single profile then the profile has no effect. If the - * value assumption is invalidated in compiled code then it is invalidated. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - *
    - *     final DoubleValueProfile profile = DoubleValueProfile.createRawIdentityProfile();
    - *
    - *     double execute(double input) {
    - *         double profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profiledValue;
    - *     }
    - * }
    - * 
    - *

    - * - * - * {@inheritDoc} - * - * @see #createRawIdentityProfile() - * @see ValueProfile - */ -public abstract class DoubleValueProfile extends Profile { - - DoubleValueProfile() { - } - - public abstract double profile(double value); - - /** - * Returns a value profile that profiles the exact value of a double using - * {@link Double#doubleToRawLongBits(double)}. - * - * @see IntValueProfile - */ - public static DoubleValueProfile createRawIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends DoubleValueProfile { - - private static final byte UNINITIALIZED = 0; - private static final byte SPECIALIZED = 1; - private static final byte GENERIC = 2; - - @CompilationFinal private double cachedValue; - @CompilationFinal private long cachedRawValue; - @CompilationFinal private byte state = 0; - - @Override - public double profile(double value) { - byte localState = this.state; - if (localState != GENERIC) { - if (localState == SPECIALIZED) { - if (cachedRawValue == Double.doubleToRawLongBits(value)) { - return cachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (localState == UNINITIALIZED) { - this.cachedValue = value; - this.cachedRawValue = Double.doubleToRawLongBits(value); - this.state = SPECIALIZED; - } else { - this.state = GENERIC; - } - } - return value; - } - - boolean isGeneric() { - return state == GENERIC; - } - - boolean isUninitialized() { - return state == UNINITIALIZED; - } - - double getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(DoubleValueProfile.class, state == UNINITIALIZED, state == GENERIC, // - String.format("value == (double)%s (raw %h)", cachedValue, cachedRawValue)); - } - - /* Needed for lazy class loading. */ - static DoubleValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends DoubleValueProfile { - - static final DoubleValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public double profile(double value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(DoubleValueProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/FloatValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/FloatValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of float runtime values. - * Value profiles require a runtime check in their initialized state to verify their profiled - * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if - * two or more values are profiled within a single profile then the profile has no effect. If the - * value assumption is invalidated in compiled code then it is invalidated. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - * 
    - *     final FloatValueProfile profile = FloatValueProfile.createRawIdentityProfile();
    - * 
    - *     float execute(float input) {
    - *         float profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profiledValue;
    - *     }
    - * }
    - * 
    - *

    - * - * - * {@inheritDoc} - * - * @see #createRawIdentityProfile() - * @see ValueProfile - */ -public abstract class FloatValueProfile extends Profile { - - FloatValueProfile() { - } - - public abstract float profile(float value); - - /** - * Returns a value profile that profiles the exact value of a float using - * {@link Float#floatToRawIntBits(float)}. - * - * @see IntValueProfile - */ - public static FloatValueProfile createRawIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends FloatValueProfile { - - private static final byte UNINITIALIZED = 0; - private static final byte SPECIALIZED = 1; - private static final byte GENERIC = 2; - - @CompilationFinal private float cachedValue; - @CompilationFinal private int cachedRawValue; - @CompilationFinal private byte state = 0; - - @Override - public float profile(float value) { - byte localState = this.state; - if (localState != GENERIC) { - if (localState == SPECIALIZED) { - if (cachedRawValue == Float.floatToRawIntBits(value)) { - return cachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (localState == UNINITIALIZED) { - this.cachedValue = value; - this.cachedRawValue = Float.floatToRawIntBits(value); - this.state = SPECIALIZED; - } else { - this.state = GENERIC; - } - } - return value; - } - - boolean isGeneric() { - return state == GENERIC; - } - - boolean isUninitialized() { - return state == UNINITIALIZED; - } - - float getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(FloatValueProfile.class, state == UNINITIALIZED, state == GENERIC, // - String.format("value == (float)%s (raw %h)", cachedValue, cachedRawValue)); - } - - /* Needed for lazy class loading. */ - static FloatValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends FloatValueProfile { - - static final FloatValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public float profile(float value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(FloatValueProfile.class); - } - - } -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/IntValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/IntValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of int runtime values. Value - * profiles require a runtime check in their initialized state to verify their profiled assumption. - * Value profiles are limited to capture monomorphic profiles only. This means that if two or more - * values are profiled within a single profile then the profile has no effect. If the value - * assumption is invalidated in compiled code then it is invalidated. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - *
    - *     final IntValueProfile profile = IntValueProfile.createIdentityProfile();
    - *
    - *     int execute(int input) {
    - *         int profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profiledValue;
    - *     }
    - * }
    - * 
    - *

    - * - * - * {@inheritDoc} - * - * @see #createIdentityProfile() - * @see ValueProfile - */ -public abstract class IntValueProfile extends Profile { - - IntValueProfile() { - } - - public abstract int profile(int value); - - /** - * Returns a value profile that profiles the exact value of an int. - * - * @see IntValueProfile - */ - public static IntValueProfile createIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends IntValueProfile { - - private static final byte UNINITIALIZED = 0; - private static final byte SPECIALIZED = 1; - private static final byte GENERIC = 2; - - @CompilationFinal private int cachedValue; - @CompilationFinal private byte state = 0; - - @Override - public int profile(int value) { - byte localState = this.state; - if (localState != GENERIC) { - if (localState == SPECIALIZED) { - int v = cachedValue; - if (v == value) { - return v; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (localState == UNINITIALIZED) { - this.cachedValue = value; - this.state = SPECIALIZED; - } else { - this.state = GENERIC; - } - } - return value; - } - - boolean isGeneric() { - return state == GENERIC; - } - - boolean isUninitialized() { - return state == UNINITIALIZED; - } - - int getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(IntValueProfile.class, isUninitialized(), isGeneric(), // - String.format("value == (int)%s", cachedValue)); - } - - /* Needed for lazy class loading. */ - static IntValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends IntValueProfile { - - static final IntValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public int profile(int value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(IntValueProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LongValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LongValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of long runtime values. - * Value profiles require a runtime check in their initialized state to verify their profiled - * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if - * two or more values are profiled within a single profile then the profile has no effect. If the - * value assumption is invalidated in compiled code then it is invalidated. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - *
    - *     final LongValueProfile profile = LongValueProfile.createIdentityProfile();
    - *
    - *     long execute(long input) {
    - *         long profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profiledValue;
    - *     }
    - * }
    - * 
    - *

    - * - * {@inheritDoc} - * - * @see #createIdentityProfile() - * @see ValueProfile - */ -public abstract class LongValueProfile extends Profile { - - LongValueProfile() { - } - - public abstract long profile(long value); - - /** - * Returns a value profile that profiles the exact value of an long. - * - * @see LongValueProfile - */ - public static LongValueProfile createIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends LongValueProfile { - - private static final byte UNINITIALIZED = 0; - private static final byte SPECIALIZED = 1; - private static final byte GENERIC = 2; - - @CompilationFinal private long cachedValue; - @CompilationFinal private byte state = 0; - - @Override - public long profile(long value) { - byte localState = this.state; - if (localState != GENERIC) { - if (localState == SPECIALIZED) { - long v = cachedValue; - if (v == value) { - return v; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (localState == UNINITIALIZED) { - this.cachedValue = value; - this.state = SPECIALIZED; - } else { - this.state = GENERIC; - } - } - return value; - } - - boolean isGeneric() { - return state == GENERIC; - } - - boolean isUninitialized() { - return state == UNINITIALIZED; - } - - long getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(LongValueProfile.class, state == UNINITIALIZED, state == GENERIC, // - String.format("value == (long)%s", cachedValue)); - } - - /* Needed for lazy class loading. */ - static LongValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends LongValueProfile { - - static final LongValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public long profile(long value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(LongValueProfile.class); - } - - } -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * LoopConditionProfiles are designed to profile the outcome of loop conditions. Loop profiles can - * be used to profile unpredictable loops as well as predictable loops. - *

    - * - *

    - * Arbitrary loop usage example: - * - *

    - * class LoopNode extends Node {
    - * 
    - *     final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
    - * 
    - *     void execute() {
    - *         // loop count cannot be predicted
    - *         while (loopProfile.profile(Math.random() >= 0.9)) {
    - *             // work
    - *         }
    - *     }
    - * }
    - * 
    - * - *

    - * - *

    - * Counted loop usage example: - * - *

    - * class CountedLoopNode extends Node {
    - * 
    - *     final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
    - * 
    - *     void execute(int length) {
    - *         // loop count can be predicted
    - *         loopProfile.profileCounted(length);
    - *         for (int i = 0; loopProfile.inject(i < length); i++) {
    - *             // work
    - *         }
    - *     }
    - * }
    - * 
    - * - *

    - *

    - * The advantage of using {@link #profileCounted(long)} to using {@link #profile(boolean)} is that - * it incurs less overhead in the interpreter. Using {@link LoopConditionProfile#inject(boolean)} is - * a no-op in the interpreter while {@link #profile(boolean)} needs to use a counter for each - * iteration. - *

    - * - * - * {@inheritDoc} - * - * @see #createBinaryProfile() - * @see #createCountingProfile() - * @see LoopConditionProfile - */ -public abstract class LoopConditionProfile extends ConditionProfile { - - LoopConditionProfile() { - } - - @Override - public abstract boolean profile(boolean value); - - /** - * Provides an alternative way to profile counted loops with less interpreter footprint. Please - * see {@link LoopConditionProfile} for an usage example. - * - * @see #inject(boolean) - */ - public abstract void profileCounted(long length); - - /** - * Provides an alternative way to profile counted loops with less interpreter footprint. Please - * see {@link LoopConditionProfile} for an usage example. - * - * @see #inject(boolean) - */ - public abstract boolean inject(boolean condition); - - /** - * Returns a {@link LoopConditionProfile} that speculates on loop conditions to be never - * true. It also captures loop probabilities for the compiler. Loop condition - * profiles are intended to be used for loop conditions. - * - * @see LoopConditionProfile - */ - public static LoopConditionProfile createCountingProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Enabled extends LoopConditionProfile { - - @CompilationFinal private long trueCount; // long for long running loops. - @CompilationFinal private int falseCount; - - @Override - public boolean profile(boolean condition) { - if (CompilerDirectives.inInterpreter()) { - if (condition) { - // local required to guarantee no overflow in multi-threaded environments - long localTrueCount = trueCount; - if (localTrueCount < Long.MAX_VALUE) { - trueCount = localTrueCount + 1; - } - } else { - // local required to guarantee no overflow in multi-threaded environments - int localFalseCount = falseCount; - if (localFalseCount < Integer.MAX_VALUE) { - falseCount = localFalseCount + 1; - } - } - // no branch probability calculation in the interpreter - return condition; - } else { - long trueCountLocal = trueCount; - int falseCountLocal = falseCount; - if (trueCountLocal == 0) { - /* Deopt for never entering the loop. */ - if (condition) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - trueCount = trueCountLocal = 1; - } - } - /* No deopt for not entering the loop. */ - return CompilerDirectives.injectBranchProbability(calculateProbability(trueCountLocal, falseCountLocal), condition); - } - } - - @Override - public void profileCounted(long length) { - if (CompilerDirectives.inInterpreter()) { - long trueCountLocal = trueCount + length; - if (trueCountLocal >= 0) { // don't write overflow values - trueCount = trueCountLocal; - int falseCountLocal = falseCount; - if (falseCountLocal < Integer.MAX_VALUE) { - falseCount = falseCountLocal + 1; - } - } - } - } - - @Override - public boolean inject(boolean condition) { - if (CompilerDirectives.inCompiledCode()) { - return CompilerDirectives.injectBranchProbability(calculateProbability(trueCount, falseCount), condition); - } else { - return condition; - } - } - - private static double calculateProbability(long trueCountLocal, int falseCountLocal) { - if (falseCountLocal == 0 && trueCountLocal == 0) { - /* Avoid division by zero if profile was never used. */ - return 0.0; - } else { - return (double) trueCountLocal / (double) (trueCountLocal + falseCountLocal); - } - } - - /* for testing */ - long getTrueCount() { - return trueCount; - } - - /* for testing */ - int getFalseCount() { - return falseCount; - } - - @Override - public String toString() { - return toString(LoopConditionProfile.class, falseCount == 0, false, // - String.format("trueProbability=%s (trueCount=%s, falseCount=%s)", calculateProbability(trueCount, falseCount), falseCount, trueCount)); - } - - /* Needed for lazy class loading. */ - static LoopConditionProfile create() { - return new Enabled(); - } - - } - - static final class Disabled extends LoopConditionProfile { - - static final LoopConditionProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public boolean profile(boolean condition) { - return condition; - } - - @Override - public void profileCounted(long length) { - } - - @Override - public boolean inject(boolean condition) { - return condition; - } - - @Override - public String toString() { - return toStringDisabled(LoopConditionProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import java.util.Objects; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Represents a {@link ValueProfile} that speculates on the primitive equality or object identity of - * values. Note that for {@code float} and {@code double} values we compare primitive equality via - * {@link Float#floatToRawIntBits} and {@link Double#doubleToRawLongBits}, so that for example - * {@code -0.0} is not considered the same as {@code 0.0}, even though primitive equality would - * normally say that it was. - *

    - * - * {@inheritDoc} - */ -public abstract class PrimitiveValueProfile extends ValueProfile { - - PrimitiveValueProfile() { - } - - @Override - public abstract T profile(T value); - - public abstract byte profile(byte value); - - public abstract short profile(short value); - - public abstract int profile(int value); - - public abstract long profile(long value); - - public abstract float profile(float value); - - public abstract double profile(double value); - - public abstract boolean profile(boolean value); - - public abstract char profile(char value); - - /** - * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or object - * identity of a value. - */ - public static PrimitiveValueProfile createEqualityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Enabled.create(); - } else { - return Disabled.INSTANCE; - } - } - - /** - * @deprecated going to get removed without replacement - */ - @Deprecated - public static boolean exactCompare(float a, float b) { - /* - * -0.0 == 0.0, but you can tell the difference through other means, so we need to - * differentiate. - */ - return Float.floatToRawIntBits(a) == Float.floatToRawIntBits(b); - } - - /** - * @deprecated going to get removed without replacement - */ - @Deprecated - public static boolean exactCompare(double a, double b) { - /* - * -0.0 == 0.0, but you can tell the difference through other means, so we need to - * differentiate. - */ - return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b); - } - - static final class Enabled extends PrimitiveValueProfile { - - private static final byte STATE_UNINITIALIZED = 0; - private static final byte STATE_BYTE = 1; - private static final byte STATE_SHORT = 2; - private static final byte STATE_INTEGER = 3; - private static final byte STATE_LONG = 4; - private static final byte STATE_BOOLEAN = 5; - private static final byte STATE_CHARACTER = 6; - private static final byte STATE_FLOAT = 7; - private static final byte STATE_DOUBLE = 8; - private static final byte STATE_IDENTITY = 9; - private static final byte STATE_GENERIC = 10; - - @CompilationFinal private byte state = STATE_UNINITIALIZED; - @CompilationFinal private Object cachedValue; - - Enabled() { - } - - @SuppressWarnings("unchecked") - @Override - public T profile(T value) { - byte s = this.state; - Object snapshot; - switch (s) { - case STATE_BYTE: - case STATE_SHORT: - case STATE_INTEGER: - case STATE_LONG: - case STATE_BOOLEAN: - case STATE_CHARACTER: - snapshot = this.cachedValue; - if (snapshot.equals(value)) { - return (T) snapshot; - } - break; - case STATE_DOUBLE: - snapshot = this.cachedValue; - if (value instanceof Double && exactCompare((Double) snapshot, (Double) value)) { - return (T) snapshot; - } - break; - case STATE_FLOAT: - snapshot = this.cachedValue; - if (value instanceof Float && exactCompare((Float) snapshot, (Float) value)) { - return (T) snapshot; - } - break; - case STATE_IDENTITY: - snapshot = this.cachedValue; - if (snapshot == value) { - return (T) snapshot; - } - break; - case STATE_GENERIC: - return value; - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - return value; - } - - @Override - public byte profile(byte value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_BYTE) { - byte castCachedValue = (byte) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public short profile(short value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_SHORT) { - short castCachedValue = (short) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public int profile(int value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_INTEGER) { - int castCachedValue = (int) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public long profile(long value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_LONG) { - long castCachedValue = (long) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public float profile(float value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_FLOAT) { - float castCachedValue = (float) this.cachedValue; - if (exactCompare(castCachedValue, value)) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public double profile(double value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_DOUBLE) { - double castCachedValue = (double) this.cachedValue; - if (exactCompare(castCachedValue, value)) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - - } - - @Override - public boolean profile(boolean value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_BOOLEAN) { - boolean castCachedValue = (boolean) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - @Override - public char profile(char value) { - byte s = this.state; - if (s != STATE_GENERIC) { - if (s == STATE_CHARACTER) { - char castCachedValue = (char) this.cachedValue; - if (castCachedValue == value) { - return castCachedValue; - } - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowpath(s, value); - } - return value; - } - - private void slowpath(byte s, Object value) { - if (s == STATE_UNINITIALIZED) { - cachedValue = value; - state = specialize(value); - } else { - state = STATE_GENERIC; - cachedValue = null; - } - } - - private static byte specialize(Object value) { - if (value instanceof Byte) { - return STATE_BYTE; - } else if (value instanceof Short) { - return STATE_SHORT; - } else if (value instanceof Integer) { - return STATE_INTEGER; - } else if (value instanceof Long) { - return STATE_LONG; - } else if (value instanceof Boolean) { - return STATE_BOOLEAN; - } else if (value instanceof Character) { - return STATE_CHARACTER; - } else if (value instanceof Double) { - return STATE_DOUBLE; - } else if (value instanceof Float) { - return STATE_FLOAT; - } else { - return STATE_IDENTITY; - } - } - - boolean isGeneric() { - return state == STATE_GENERIC; - } - - boolean isUninitialized() { - return state == STATE_UNINITIALIZED; - } - - Object getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(PrimitiveValueProfile.class, state == STATE_UNINITIALIZED, state == STATE_GENERIC, formatSpecialization()); - } - - private String formatSpecialization() { - Object snapshot = this.cachedValue; - if (state != STATE_UNINITIALIZED && state != STATE_GENERIC) { - if (snapshot == null) { - return String.format("value == null"); - } else { - if (state == STATE_IDENTITY) { - String simpleName = snapshot.getClass().getSimpleName(); - return String.format("value == %s@%x", simpleName, Objects.hash(snapshot)); - } else { - return String.format("value == (%s)%s", snapshot.getClass().getSimpleName(), snapshot); - } - } - } - return null; - } - - /** - * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or - * object identity of a value. - */ - static PrimitiveValueProfile create() { - return new Enabled(); - } - } - - static final class Disabled extends PrimitiveValueProfile { - - static final PrimitiveValueProfile INSTANCE = new Disabled(); - - @Override - public T profile(T value) { - return value; - } - - @Override - public byte profile(byte value) { - return value; - } - - @Override - public short profile(short value) { - return value; - } - - @Override - public int profile(int value) { - return value; - } - - @Override - public long profile(long value) { - return value; - } - - @Override - public float profile(float value) { - return value; - } - - @Override - public double profile(double value) { - return value; - } - - @Override - public boolean profile(boolean value) { - return value; - } - - @Override - public char profile(char value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(PrimitiveValueProfile.class); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/Profile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/Profile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import com.oracle.truffle.api.Assumption; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.TruffleRuntime; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCloneable; -import com.oracle.truffle.api.nodes.RootNode; - -/** - *

    - * A profile is a Truffle utility class that uses the {@link CompilerDirectives Truffle compiler - * directives} to guard for and/or forward runtime information to the compiler. - *

    - * - *

    - * Usage: Profiles should be stored in final or {@link CompilationFinal - * compilation final} fields of node classes to ensure that they can get optimized properly. - * Profiles must not be shared between ASTs. Using the same profile multiple times in a single - * {@link Node node} or in multiple {@link Node nodes} which {@link Node#getRootNode() link} to the - * same {@link RootNode root} is allowed. Never store profiles inside runtime values that - * leave the scope of the originating AST. This limitation exists because the used mechanism to - * invalidate compiled code performs local invalidations only. For global speculations use - * {@link Assumption assumptions} instead. - *

    - * - *

    - * Compilation: Some profiles like {@link BranchProfile branch} profiles do not induce - * additional overhead in compiled code. Others like {@link ValueProfile value} profiles might - * require a runtime check to verify their assumptions which are forwarded to the compiler. Even if - * profiles do not induce direct overhead in compiled code it still might get invalidated as a - * result of using profiles. Invalidating profiles will result in the invalidation of compiled code. - * It is therefore essential to place these profiles in way that is neither too aggressive nor too - * conservative. - *

    - * - *

    - * Footprint: Whether profiling information can be forwarded to the compiler depends on the - * capabilities of the {@link TruffleRuntime runtime system}. If the runtime returns - * true in {@link TruffleRuntime#isProfilingEnabled()} then runtime information will - * get collected. This comes at at the cost of additional overhead and footprint in interpreted - * mode. Thats why the factory methods of profiles can return implementations where profiling is - * disabled. Using disabled profiles makes sense for runtimes that are unable to use the collected - * profiling information. Even runtime implementations that are able to use this information might - * decide to turn off profiling for benchmarking purposes. - *

    - * - *

    - * Profile subclasses: - *

      - *
    • {@link BranchProfile} to profile on unlikely branches like errors.
    • - *
    • {@link ConditionProfile} to profile on conditionals or boolean values.
    • - *
    • {@link LoopConditionProfile} to profile on conditionals of loops with special support for - * counted loops.
    • - *
    • {@link ValueProfile} to profile on properties like type and identity of values.
    • - *
    • {@link ByteValueProfile} to profile on byte values.
    • - *
    • {@link IntValueProfile} to profile on int values.
    • - *
    • {@link LongValueProfile} to profile on long values.
    • - *
    • {@link FloatValueProfile} to profile on float values.
    • - *
    • {@link DoubleValueProfile} to profile on double values.
    • - *
    • {@link PrimitiveValueProfile} to profile on objects by identity and on primitives by value.
    • - *
    - *

    - * - * @see Assumption - */ -public abstract class Profile extends NodeCloneable { - - Profile() { - /* We don't to allow custom profiles. We want to evolve this API further first. Sorry. */ - } - - String toStringDisabled(Class profileClass) { - return String.format("%s(DISABLED)", profileClass.getSimpleName()); - } - - String toString(Class profileClass, boolean uninitialized, boolean generic, String specialization) { - String s; - if (uninitialized) { - s = "UNINITIALIZED"; - } else if (generic) { - s = "GENERIC"; - } else { - s = specialization == null ? "" : specialization; - } - return String.format("%s(%s)@%s", profileClass.getSimpleName(), s, Integer.toHexString(this.hashCode())); - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ValueProfile.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ValueProfile.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,334 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.api.profiles; - -import java.util.Objects; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.Truffle; - -/** - *

    - * Specialized value profile to capture certain properties of Object runtime values. - * Value profiles require a runtime check in their initialized state to verify their profiled - * assumption. Value profiles are limited to capture monomorphic profiles only. This means that if - * two or more identities or classes are profiles within a single profile then the profile has no - * effect and no overhead after compilation. There are specialized versions of this profile with - * less interpreter footprint for {@link ConditionProfile boolean}, {@link ByteValueProfile byte}, - * {@link IntValueProfile int}, {@link LongValueProfile long}, {@link FloatValueProfile float} and - * {@link DoubleValueProfile double} values. - *

    - * - *

    - * Usage example: - * - *

    - * class SampleNode extends Node {
    - *
    - * final ValueProfile profile = ValueProfile.create{Identity,Class}Profile();
    - *
    - *     Object execute(Object input) {
    - *         Object profiledValue = profile.profile(input);
    - *         // compiler may know now more about profiledValue
    - *         return profieldValue;
    - *     }
    - * }
    - * 
    - *

    - * - * - * {@inheritDoc} - * - * @see #createIdentityProfile() - * @see #createClassProfile() - */ -public abstract class ValueProfile extends Profile { - - ValueProfile() { - } - - public abstract T profile(T value); - - /** - *

    - * Returns a value profile that profiles the exact class of a value. It will check the class of - * the profiled value and provide additional information to the compiler if only non-null values - * of exactly one concrete Java class are passed as a parameter to the - * {@link ValueProfile#profile} method. This can be beneficial if subsequent code can take - * advantage of knowing the concrete class of the value. The profile will degrade to the generic - * case if a null value or if at least two instances of two different Java classes are - * registered. - *

    - * - *

    - * Compilation notes: Value profiles require a runtime check in their initialized state - * to verify their profiled class. If two classes have been seen on a single profile instance - * then this profile will transition to a generic state with no overhead. - *

    - * - * @see ValueProfile usage example - */ - public static ValueProfile createClassProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return ExactClass.create(); - } else { - return Disabled.INSTANCE; - } - } - - /** - *

    - * Returns a value profile that profiles the object identity of a value. A single instance can - * only profile one particular instance. - *

    - * - *

    - * Compilation notes: Identity profiles require a runtime check to verify their profiled - * object identity. If two identities have been seen on a single profile instance then this - * profile will transition to a generic state with no overhead. - *

    - */ - public static ValueProfile createIdentityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Identity.create(); - } else { - return Disabled.INSTANCE; - } - } - - /** - *

    - * Returns a value profile that profiles the object equality of a value. A single instance can - * only profile one set of equal values. - *

    - * - *

    - * Compilation notes: Equality profiles inline the body of the equal method of the first - * profiled value in order to verify its assumption. Please take care that you do this only for - * equals implementations that your guest language actually has control over otherwise your - * compiled code might contain recursions or too much code. If two non equal objects have been - * seen on a single profile instance then this profile will transition to a generic state with - * no overhead. - *

    - */ - public static ValueProfile createEqualityProfile() { - if (Truffle.getRuntime().isProfilingEnabled()) { - return Equality.create(); - } else { - return Disabled.INSTANCE; - } - } - - static final class Disabled extends ValueProfile { - - static final ValueProfile INSTANCE = new Disabled(); - - @Override - protected Object clone() { - return INSTANCE; - } - - @Override - public T profile(T value) { - return value; - } - - @Override - public String toString() { - return toStringDisabled(ValueProfile.class); - } - - } - - static final class Equality extends ValueProfile { - - private static final Object GENERIC = new Object(); - - @CompilationFinal protected Object cachedValue = null; - - Equality() { - } - - @Override - @SuppressWarnings("unchecked") - public T profile(T newValue) { - // Field needs to be cached in local variable for thread safety and startup speed. - Object cached = this.cachedValue; - if (cached != GENERIC) { - if (cached != null && cached.equals(newValue)) { - return (T) cached; - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (cached == null && newValue != null) { - cachedValue = newValue; - } else { - cachedValue = GENERIC; - } - } - } - return newValue; - } - - public boolean isGeneric() { - return getCachedValue() == GENERIC; - } - - public boolean isUninitialized() { - return getCachedValue() == null; - } - - public Object getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(ValueProfile.class, isUninitialized(), isGeneric(), // - String.format("value == %s@%x", cachedValue != null ? cachedValue.getClass().getSimpleName() : "null", Objects.hash(cachedValue))); - } - - /* Needed for lazy class loading. */ - static ValueProfile create() { - return new Equality(); - } - - } - - static final class Identity extends ValueProfile { - - private static final Object UNINITIALIZED = new Object(); - private static final Object GENERIC = new Object(); - - @CompilationFinal protected Object cachedValue = UNINITIALIZED; - - Identity() { - } - - @Override - @SuppressWarnings("unchecked") - public T profile(T newValue) { - // Field needs to be cached in local variable for thread safety and startup speed. - Object cached = this.cachedValue; - if (cached != GENERIC) { - if (cached == newValue) { - return (T) cached; - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (cachedValue == UNINITIALIZED) { - cachedValue = newValue; - } else { - cachedValue = GENERIC; - } - } - } - return newValue; - } - - public boolean isGeneric() { - return getCachedValue() == GENERIC; - } - - public boolean isUninitialized() { - return getCachedValue() == UNINITIALIZED; - } - - public Object getCachedValue() { - return cachedValue; - } - - @Override - public String toString() { - return toString(ValueProfile.class, isUninitialized(), isGeneric(), // - String.format("value == %s@%x", cachedValue != null ? cachedValue.getClass().getSimpleName() : "null", Objects.hash(cachedValue))); - } - - /* Needed for lazy class loading. */ - static ValueProfile create() { - return new Identity(); - } - - } - - static final class ExactClass extends ValueProfile { - - @CompilationFinal protected Class cachedClass; - - ExactClass() { - } - - public static ValueProfile create() { - return new ExactClass(); - } - - @SuppressWarnings("unchecked") - @Override - public T profile(T value) { - // Field needs to be cached in local variable for thread safety and startup speed. - Class clazz = cachedClass; - if (clazz != Object.class) { - if (clazz != null && value != null && clazz == value.getClass()) { - /* - * The cast is really only for the compiler relevant. It does not perform any - * useful action in the interpreter and only takes time. - */ - if (CompilerDirectives.inInterpreter()) { - return value; - } else { - return (T) clazz.cast(value); - } - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (clazz == null && value != null) { - cachedClass = value.getClass(); - } else { - cachedClass = Object.class; - } - } - } - return value; - } - - boolean isGeneric() { - return cachedClass == Object.class; - } - - boolean isUninitialized() { - return cachedClass == null; - } - - Class getCachedClass() { - return cachedClass; - } - - @Override - public String toString() { - return toString(ValueProfile.class, cachedClass == null, cachedClass == Object.class, // - String.format("value.getClass() == %s.class", cachedClass != null ? cachedClass.getSimpleName() : "null")); - } - - } - -} diff -r d2b4fe945c23 -r 828c67903db2 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/package-info.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/package-info.java Wed Dec 16 15:32:23 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - @ApiInfo( - group="Stable" - ) - */ -/** - * A profile is a Truffle utility class that uses the - * {@link com.oracle.truffle.api.CompilerDirectives Truffle compiler directives} to guard for and/or - * forward runtime information to the compiler. - * - * @see com.oracle.truffle.api.profiles.Profile - */ -package com.oracle.truffle.api.profiles; -