changeset 22501:a63bda98cfdb

Extract profiles into separate package. Add isProfilingEnabled in TruffleRuntime to disable profiling in the default runtime; Add low overhead profiles for primitives; Add LoopConditionProfile; Profile footprint/threadsafety improvements; Make toString implementations more consistent; Greatly enhanced javadoc documentation for profiles; Deprecate old profiles
author Christian Humer <christian.humer@oracle.com>
date Wed, 16 Dec 2015 16:38:13 +0100
parents fbe1eb7b4172
children d2b4fe945c23
files truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/BinaryConditionProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/BranchProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/ByteValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/CountingConditionProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/DoubleValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/EqualityValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/ExactClassValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/FloatValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/IdentityValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/IntValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LazyProfileLoadingTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LongValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LoopConditionProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/PrimitiveValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/BinaryConditionProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/BranchProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/CountingConditionProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/ExactClassValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/IdentityValueProfileTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/PrimitiveValueProfileTest.java truffle/com.oracle.truffle.api/snapshot.sigtest truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/BranchProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ByteValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ConditionProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/FloatValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/IntValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LongValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/Profile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BinaryConditionProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CountingConditionProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IdentityValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/package-info.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLRepeatingNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java
diffstat 49 files changed, 4869 insertions(+), 1534 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Wed Dec 16 16:38:13 2015 +0100
@@ -26,7 +26,8 @@
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.utilities.BranchProfile;
+import com.oracle.truffle.api.profiles.BranchProfile;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/BinaryConditionProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class BinaryConditionProfileTest {
+
+    @DataPoints public static boolean[] data = new boolean[]{true, false};
+
+    private ConditionProfile.Binary profile;
+
+    @Before
+    public void create() {
+        profile = (ConditionProfile.Binary) ConditionProfile.Binary.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.wasTrue(), is(false));
+        assertThat(profile.wasFalse(), is(false));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileOne(boolean value) {
+        boolean result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertThat(profile.wasTrue(), is(value));
+        assertThat(profile.wasFalse(), is(!value));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileTwo(boolean value0, boolean value1) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(profile.wasTrue(), is(value0 || value1));
+        assertThat(profile.wasFalse(), is(!value0 || !value1));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileThree(boolean value0, boolean value1, boolean value2) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+        boolean result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+        assertThat(profile.wasTrue(), is(value0 || value1 || value2));
+        assertThat(profile.wasFalse(), is(!value0 || !value1 || !value2));
+        profile.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/BranchProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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 static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class BranchProfileTest {
+
+    @Test
+    public void testEnter() {
+        BranchProfile profile = BranchProfile.Enabled.create0();
+        profile.enter();
+        profile.enter();
+    }
+
+    @Test
+    public void testToString() {
+        BranchProfile profile = BranchProfile.Enabled.create0();
+        assertTrue(profile.toString().contains(BranchProfile.class.getSimpleName()));
+        assertTrue(profile.toString().contains("UNINITIALIZED"));
+        assertTrue(profile.toString().contains(Integer.toHexString(profile.hashCode())));
+        profile.enter();
+        assertTrue(profile.toString().contains(BranchProfile.class.getSimpleName()));
+        assertTrue(profile.toString().contains("VISITED"));
+        assertTrue(profile.toString().contains(Integer.toHexString(profile.hashCode())));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/ByteValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ByteValueProfileTest {
+
+    @DataPoint public static final byte VALUE0 = Byte.MIN_VALUE;
+    @DataPoint public static final byte VALUE1 = 0;
+    @DataPoint public static final byte VALUE2 = 14;
+    @DataPoint public static final byte VALUE3 = Byte.MAX_VALUE;
+
+    private ByteValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (ByteValueProfile.Enabled) ByteValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneObject(byte value) {
+        byte result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoObject(byte value0, byte value1) {
+        byte result0 = profile.profile(value0);
+        byte result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        if (value0 == value1) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeObject(byte value0, byte value1, byte value2) {
+        byte result0 = profile.profile(value0);
+        byte result1 = profile.profile(value1);
+        byte result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        if (value0 == value1 && value1 == value2) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Test
+    public void testDisabled() {
+        ByteValueProfile.Disabled p = (ByteValueProfile.Disabled) ByteValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(VALUE0), is(VALUE0));
+        assertThat(p.profile(VALUE1), is(VALUE1));
+        assertThat(p.profile(VALUE2), is(VALUE2));
+        assertThat(p.profile(VALUE3), is(VALUE3));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/CountingConditionProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class CountingConditionProfileTest {
+
+    @DataPoints public static boolean[] data = new boolean[]{true, false};
+
+    private ConditionProfile.Counting profile;
+
+    @Before
+    public void create() {
+        profile = (ConditionProfile.Counting) ConditionProfile.Counting.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.getTrueCount(), is(0));
+        assertThat(profile.getFalseCount(), is(0));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileOne(boolean value) {
+        boolean result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertThat(profile.getTrueCount(), is(value ? 1 : 0));
+        assertThat(profile.getFalseCount(), is(!value ? 1 : 0));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileTwo(boolean value0, boolean value1) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0)));
+        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0)));
+        profile.toString();
+    }
+
+    @Theory
+    public void testProfileThree(boolean value0, boolean value1, boolean value2) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+        boolean result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+        assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0) + (value2 ? 1 : 0)));
+        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0) + (!value2 ? 1 : 0)));
+        profile.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/DoubleValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class DoubleValueProfileTest {
+
+    @DataPoint public static final double VALUE0 = Double.MIN_VALUE;
+    @DataPoint public static final double VALUE1 = -0.0f;
+    @DataPoint public static final double VALUE2 = +0.0f;
+    @DataPoint public static final double VALUE3 = 14.5f;
+    @DataPoint public static final double VALUE4 = Double.MAX_VALUE;
+
+    private static final double FLOAT_DELTA = 0.00001f;
+
+    private DoubleValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (DoubleValueProfile.Enabled) DoubleValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneFloat(double value) {
+        double result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value, FLOAT_DELTA);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @SuppressWarnings("deprecation")
+    @Theory
+    public void testProfileTwoFloat(double value0, double value1) {
+        double result0 = profile.profile(value0);
+        double result1 = profile.profile(value1);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
+            assertEquals(profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @SuppressWarnings("deprecation")
+    @Theory
+    public void testProfileThreeFloat(double value0, double value1, double value2) {
+        double result0 = profile.profile(value0);
+        double result1 = profile.profile(value1);
+        double result2 = profile.profile(value2);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+        assertEquals(result2, value2, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
+            assertEquals(profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Test
+    public void testDisabled() {
+        DoubleValueProfile.Disabled p = (DoubleValueProfile.Disabled) DoubleValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(VALUE0), is(VALUE0));
+        assertThat(p.profile(VALUE1), is(VALUE1));
+        assertThat(p.profile(VALUE2), is(VALUE2));
+        assertThat(p.profile(VALUE3), is(VALUE3));
+        assertThat(p.profile(VALUE4), is(VALUE4));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/EqualityValueProfileTest.java	Wed Dec 16 16:38:13 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class EqualityValueProfileTest {
+
+    @DataPoint public static final String O1 = new String();
+    @DataPoint public static final String O2 = O1;
+    @DataPoint public static final Object O3 = new Object();
+    @DataPoint public static final Integer O4 = new Integer(1);
+    @DataPoint public static final Integer O5 = new Integer(1);
+    @DataPoint public static final Integer O6 = null;
+
+    private ValueProfile.Equality profile;
+
+    @Before
+    public void create() {
+        profile = (ValueProfile.Equality) ValueProfile.Equality.create();
+    }
+
+    @Test
+    public void testInitial() throws Exception {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOne(Object value) throws Exception {
+        Object result = profile.profile(value);
+        assertThat(result, is(equalTo(value)));
+        if (value == null) {
+            assertThat(profile.isUninitialized(), is(false));
+            assertThat(profile.isGeneric(), is(true));
+        } else {
+            assertEquals(profile.getCachedValue(), value);
+            assertThat(profile.isUninitialized(), is(false));
+            assertThat(profile.isGeneric(), is(false));
+        }
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwo(Object value0, Object value1) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertThat(result0, is(equalTo(value0)));
+        assertThat(result1, is(equalTo(value1)));
+
+        if (value0 != null && value0.equals(value1)) {
+            assertThat(profile.getCachedValue(), is(equalTo(value0)));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThree(Object value0, Object value1, Object value2) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+        Object result2 = profile.profile(value2);
+
+        assertThat(result0, is(equalTo(value0)));
+        assertThat(result1, is(equalTo(value1)));
+        assertThat(result2, is(equalTo(value2)));
+
+        if (value0 != null && value0.equals(value1) && value1 != null && value1.equals(value2)) {
+            assertThat(profile.getCachedValue(), is(equalTo(value0)));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/ExactClassValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class ExactClassValueProfileTest {
+
+    @DataPoint public static final String O1 = new String();
+    @DataPoint public static final String O2 = new String();
+    @DataPoint public static final Object O3 = new Object();
+    @DataPoint public static final Integer O4 = new Integer(1);
+    @DataPoint public static final Integer O5 = null;
+    @DataPoint public static final TestBaseClass O6 = new TestBaseClass();
+    @DataPoint public static final TestSubClass O7 = new TestSubClass();
+
+    private ValueProfile.ExactClass profile;
+
+    private static class TestBaseClass {
+    }
+
+    private static class TestSubClass extends TestBaseClass {
+    }
+
+    @Before
+    public void create() {
+        profile = (ValueProfile.ExactClass) ValueProfile.ExactClass.create();
+    }
+
+    @Test
+    public void testInitial() throws Exception {
+        assertThat(isGeneric(profile), is(false));
+        assertThat(isUninitialized(profile), is(true));
+        assertNull(getCachedClass(profile));
+        assertNotNull(profile.toString());
+    }
+
+    @Theory
+    public void testProfileOne(Object value) throws Exception {
+        Object result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(expectedClass(value), getCachedClass(profile));
+        assertThat(isUninitialized(profile), is(false));
+        assertNotNull(profile.toString());
+    }
+
+    @Theory
+    public void testProfileTwo(Object value0, Object value1) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        Object expectedClass = expectedClass(value0) == expectedClass(value1) ? expectedClass(value0) : Object.class;
+
+        assertEquals(expectedClass, getCachedClass(profile));
+        assertThat(isUninitialized(profile), is(false));
+        assertThat(isGeneric(profile), is(expectedClass == Object.class));
+        assertNotNull(profile.toString());
+    }
+
+    @Theory
+    public void testProfileThree(Object value0, Object value1, Object value2) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+        Object result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        Object expectedClass = expectedClass(value0) == expectedClass(value1) && expectedClass(value1) == expectedClass(value2) ? expectedClass(value0) : Object.class;
+
+        assertEquals(expectedClass, getCachedClass(profile));
+        assertThat(isUninitialized(profile), is(false));
+        assertThat(isGeneric(profile), is(expectedClass == Object.class));
+        assertNotNull(profile.toString());
+    }
+
+    private static Class<?> expectedClass(Object value) {
+        return value == null ? Object.class : value.getClass();
+    }
+
+    private static Object getCachedClass(ValueProfile.ExactClass profile) throws Exception {
+        return profile.getCachedClass();
+    }
+
+    private static boolean isUninitialized(ValueProfile.ExactClass profile) throws Exception {
+        return profile.isUninitialized();
+    }
+
+    private static boolean isGeneric(ValueProfile.ExactClass profile) throws Exception {
+        return profile.isGeneric();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/FloatValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class FloatValueProfileTest {
+
+    @DataPoint public static final float VALUE0 = Float.MIN_VALUE;
+    @DataPoint public static final float VALUE1 = -0.0f;
+    @DataPoint public static final float VALUE2 = +0.0f;
+    @DataPoint public static final float VALUE3 = 14.5f;
+    @DataPoint public static final float VALUE4 = Float.MAX_VALUE;
+
+    private static final float FLOAT_DELTA = 0.00001f;
+
+    private FloatValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (FloatValueProfile.Enabled) FloatValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneFloat(float value) {
+        float result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value, FLOAT_DELTA);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @SuppressWarnings("deprecation")
+    @Theory
+    public void testProfileTwoFloat(float value0, float value1) {
+        float result0 = profile.profile(value0);
+        float result1 = profile.profile(value1);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
+            assertEquals(profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @SuppressWarnings("deprecation")
+    @Theory
+    public void testProfileThreeFloat(float value0, float value1, float value2) {
+        float result0 = profile.profile(value0);
+        float result1 = profile.profile(value1);
+        float result2 = profile.profile(value2);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+        assertEquals(result2, value2, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
+            assertEquals(profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Test
+    public void testDisabled() {
+        FloatValueProfile.Disabled p = (FloatValueProfile.Disabled) FloatValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(VALUE0), is(VALUE0));
+        assertThat(p.profile(VALUE1), is(VALUE1));
+        assertThat(p.profile(VALUE2), is(VALUE2));
+        assertThat(p.profile(VALUE3), is(VALUE3));
+        assertThat(p.profile(VALUE4), is(VALUE4));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/IdentityValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class IdentityValueProfileTest {
+
+    @DataPoint public static final String O1 = new String();
+    @DataPoint public static final String O2 = O1;
+    @DataPoint public static final Object O3 = new Object();
+    @DataPoint public static final Integer O4 = new Integer(1);
+    @DataPoint public static final Integer O5 = null;
+
+    private ValueProfile.Identity profile;
+
+    @Before
+    public void create() {
+        profile = (ValueProfile.Identity) ValueProfile.Identity.create();
+    }
+
+    @Test
+    public void testInitial() throws Exception {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testDisabled(Object value) {
+        ValueProfile.Disabled p = (ValueProfile.Disabled) ValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(value), is(value));
+        p.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOne(Object value) throws Exception {
+        Object result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwo(Object value0, Object value1) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        if (value0 == value1) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThree(Object value0, Object value1, Object value2) throws Exception {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+        Object result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        if (value0 == value1 && value1 == value2) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/IntValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class IntValueProfileTest {
+
+    @DataPoint public static final int VALUE0 = Integer.MIN_VALUE;
+    @DataPoint public static final int VALUE1 = 0;
+    @DataPoint public static final int VALUE2 = 14;
+    @DataPoint public static final int VALUE3 = Integer.MAX_VALUE;
+
+    private IntValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (IntValueProfile.Enabled) IntValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneObject(int value) {
+        int result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoObject(int value0, int value1) {
+        int result0 = profile.profile(value0);
+        int result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        if (value0 == value1) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeObject(int value0, int value1, int value2) {
+        int result0 = profile.profile(value0);
+        int result1 = profile.profile(value1);
+        int result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        if (value0 == value1 && value1 == value2) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Test
+    public void testDisabled() {
+        IntValueProfile.Disabled p = (IntValueProfile.Disabled) IntValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(VALUE0), is(VALUE0));
+        assertThat(p.profile(VALUE1), is(VALUE1));
+        assertThat(p.profile(VALUE2), is(VALUE2));
+        assertThat(p.profile(VALUE3), is(VALUE3));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LazyProfileLoadingTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ *
+ * 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.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.profiles.LazyProfileLoadingTest.SeparateClassloaderTestRunner;
+
+@RunWith(SeparateClassloaderTestRunner.class)
+public class LazyProfileLoadingTest {
+
+    @Test
+    public void testLazyLoading() {
+        IntValueProfile.createIdentityProfile();
+        assertDefaultProfile(IntValueProfile.class);
+
+        DoubleValueProfile.createRawIdentityProfile();
+        assertDefaultProfile(DoubleValueProfile.class);
+
+        LongValueProfile.createIdentityProfile();
+        assertDefaultProfile(LongValueProfile.class);
+
+        FloatValueProfile.createRawIdentityProfile();
+        assertDefaultProfile(FloatValueProfile.class);
+
+        ByteValueProfile.createIdentityProfile();
+        assertDefaultProfile(ByteValueProfile.class);
+
+        LoopConditionProfile.createCountingProfile();
+        assertDefaultProfile(LoopConditionProfile.class);
+
+        BranchProfile.create();
+        assertDefaultProfile(BranchProfile.class);
+
+        PrimitiveValueProfile.createEqualityProfile();
+        assertDefaultProfile(PrimitiveValueProfile.class);
+
+        ConditionProfile.createBinaryProfile();
+        assertLoaded(ConditionProfile.class.getName(), "Binary", "Disabled");
+
+        ConditionProfile.createCountingProfile();
+        assertLoaded(ConditionProfile.class.getName(), "Counting", "Disabled");
+
+        ValueProfile.createClassProfile();
+        assertLoaded(ValueProfile.class.getName(), "ExactClass", "Disabled");
+
+        ValueProfile.createIdentityProfile();
+        assertLoaded(ValueProfile.class.getName(), "Identity", "Disabled");
+    }
+
+    private void assertDefaultProfile(Class<?> clazz) {
+        assertLoaded(clazz.getName(), "Enabled", "Disabled");
+    }
+
+    private void assertLoaded(String className, String posInnerClass, String negInnerClass) {
+        String enabledClass = className + "$" + posInnerClass;
+        String disabledClass = className + "$" + negInnerClass;
+        if (Truffle.getRuntime().isProfilingEnabled()) {
+            Assert.assertFalse(isLoaded(disabledClass));
+            Assert.assertTrue(isLoaded(enabledClass));
+        } else {
+            Assert.assertFalse(isLoaded(enabledClass));
+            Assert.assertTrue(isLoaded(disabledClass));
+        }
+    }
+
+    private boolean isLoaded(String className) {
+        ClassLoader classLoader = getClass().getClassLoader();
+        Method m;
+        try {
+            m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
+            m.setAccessible(true);
+            return m.invoke(classLoader, className) != null;
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static class SeparateClassloaderTestRunner extends BlockJUnit4ClassRunner {
+
+        public SeparateClassloaderTestRunner(Class<?> clazz) throws InitializationError {
+            super(getFromTestClassloader(clazz));
+        }
+
+        private static Class<?> getFromTestClassloader(Class<?> clazz) throws InitializationError {
+            try {
+                ClassLoader testClassLoader = new TestClassLoader();
+                return Class.forName(clazz.getName(), true, testClassLoader);
+            } catch (ClassNotFoundException e) {
+                throw new InitializationError(e);
+            }
+        }
+
+        public static class TestClassLoader extends URLClassLoader {
+            public TestClassLoader() {
+                super(((URLClassLoader) getSystemClassLoader()).getURLs());
+            }
+
+            @Override
+            public Class<?> loadClass(String name) throws ClassNotFoundException {
+                if (name.startsWith(Profile.class.getPackage().getName())) {
+                    return super.findClass(name);
+                }
+                return super.loadClass(name);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LongValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class LongValueProfileTest {
+
+    @DataPoint public static final long VALUE0 = Long.MIN_VALUE;
+    @DataPoint public static final long VALUE1 = 0L;
+    @DataPoint public static final long VALUE2 = 14L;
+    @DataPoint public static final long VALUE3 = Long.MAX_VALUE;
+
+    private LongValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (LongValueProfile.Enabled) LongValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneObject(long value) {
+        long result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoObject(long value0, long value1) {
+        long result0 = profile.profile(value0);
+        long result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        if (value0 == value1) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeObject(long value0, long value1, long value2) {
+        long result0 = profile.profile(value0);
+        long result1 = profile.profile(value1);
+        long result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        if (value0 == value1 && value1 == value2) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Test
+    public void testDisabled() {
+        LongValueProfile.Disabled p = (LongValueProfile.Disabled) LongValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(VALUE0), is(VALUE0));
+        assertThat(p.profile(VALUE1), is(VALUE1));
+        assertThat(p.profile(VALUE2), is(VALUE2));
+        assertThat(p.profile(VALUE3), is(VALUE3));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/LoopConditionProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@RunWith(Theories.class)
+public class LoopConditionProfileTest {
+
+    @DataPoints public static boolean[] data = new boolean[]{true, false};
+    @DataPoints public static long[] lengthes = new long[]{Long.MAX_VALUE, 0L, Long.MAX_VALUE / 2L, Long.MAX_VALUE / 2 + 1L, 1L};
+
+    private LoopConditionProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (LoopConditionProfile.Enabled) LoopConditionProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.getTrueCount(), is(0L));
+        assertThat(profile.getFalseCount(), is(0));
+        profile.toString(); // not crashing
+    }
+
+    @Theory
+    public void testDisabled(boolean value, long length) {
+        LoopConditionProfile.Disabled p = (LoopConditionProfile.Disabled) LoopConditionProfile.Disabled.INSTANCE;
+        p.profileCounted(length); // not crashing
+        assertThat(p.profile(value), is(value));
+        assertThat(p.inject(value), is(value));
+        p.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOne(boolean value) {
+        boolean result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertThat(profile.getTrueCount(), is(value ? 1L : 0L));
+        assertThat(profile.getFalseCount(), is(!value ? 1 : 0));
+        profile.toString(); // not crashing
+    }
+
+    @Theory
+    public void testProfileTwo(boolean value0, boolean value1) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(profile.getTrueCount(), is((value0 ? 1L : 0L) + (value1 ? 1L : 0L)));
+        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0)));
+        profile.toString(); // not crashing
+    }
+
+    @Theory
+    public void testProfileThree(boolean value0, boolean value1, boolean value2) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+        boolean result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+        assertThat(profile.getTrueCount(), is((value0 ? 1L : 0L) + (value1 ? 1L : 0L) + (value2 ? 1L : 0L)));
+        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0) + (!value2 ? 1 : 0)));
+        profile.toString(); // not crashing
+    }
+
+    @Theory
+    public void testLengthProfiling(long length1, long length2, long length3) {
+        assertThat(profile.inject(false), is(false));
+
+        profile.toString(); // not crashing
+        profile.profileCounted(length1);
+        profile.toString(); // not crashing
+        long expectedLength = length1;
+        assertThat(profile.getTrueCount(), is(expectedLength));
+        assertThat(profile.getFalseCount(), is(1));
+        assertThat(profile.inject(false), is(false));
+
+        profile.profileCounted(length2);
+        profile.toString(); // not crashing
+        expectedLength += length2;
+        if (expectedLength < 0) {
+            assertThat(profile.getTrueCount(), is(length1));
+            assertThat(profile.getFalseCount(), is(1));
+            assertThat(profile.inject(false), is(false));
+
+            profile.profileCounted(length3);
+            expectedLength = length1 + length3;
+
+            if (expectedLength < 0) {
+                assertThat(profile.getTrueCount(), is(length1));
+                assertThat(profile.getFalseCount(), is(1));
+                assertThat(profile.inject(false), is(false));
+            } else {
+                assertThat(profile.getTrueCount(), is(expectedLength));
+                assertThat(profile.getFalseCount(), is(2));
+                assertThat(profile.inject(false), is(false));
+            }
+            return;
+        } else {
+            assertThat(profile.getTrueCount(), is(expectedLength));
+            assertThat(profile.getFalseCount(), is(2));
+            assertThat(profile.inject(false), is(false));
+        }
+
+        profile.profileCounted(length3);
+        profile.toString(); // not crashing
+        expectedLength += length3;
+
+        if (expectedLength < 0) {
+            assertThat(profile.getTrueCount(), is(length1 + length2));
+            assertThat(profile.getFalseCount(), is(2));
+            assertThat(profile.inject(false), is(false));
+        } else {
+            assertThat(profile.getTrueCount(), is(expectedLength));
+            assertThat(profile.getFalseCount(), is(3));
+            assertThat(profile.inject(false), is(false));
+        }
+        profile.toString(); // not crashing
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/profiles/PrimitiveValueProfileTest.java	Wed Dec 16 16:38:13 2015 +0100
@@ -0,0 +1,966 @@
+/*
+ * 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.
+ *
+ * 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 static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoint;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+@SuppressWarnings("deprecation")
+@RunWith(Theories.class)
+public class PrimitiveValueProfileTest {
+
+    @DataPoint public static final String O1 = new String();
+    @DataPoint public static final String O2 = O1;
+    @DataPoint public static final Object O3 = new Object();
+    @DataPoint public static final Object O4 = null;
+
+    @DataPoint public static final byte B1 = Byte.MIN_VALUE;
+    @DataPoint public static final byte B2 = 0;
+    @DataPoint public static final byte B3 = 14;
+    @DataPoint public static final byte B4 = Byte.MAX_VALUE;
+
+    @DataPoint public static final short S1 = Short.MIN_VALUE;
+    @DataPoint public static final short S2 = 0;
+    @DataPoint public static final short S3 = 14;
+    @DataPoint public static final short S4 = Short.MAX_VALUE;
+
+    @DataPoint public static final int I1 = Integer.MIN_VALUE;
+    @DataPoint public static final int I2 = 0;
+    @DataPoint public static final int I3 = 14;
+    @DataPoint public static final int I4 = Integer.MAX_VALUE;
+
+    @DataPoint public static final long L1 = Long.MIN_VALUE;
+    @DataPoint public static final long L2 = 0;
+    @DataPoint public static final long L3 = 14;
+    @DataPoint public static final long L4 = Long.MAX_VALUE;
+
+    @DataPoint public static final float F1 = Float.MIN_VALUE;
+    @DataPoint public static final float F2 = -0.0f;
+    @DataPoint public static final float F3 = +0.0f;
+    @DataPoint public static final float F4 = 14.5f;
+    @DataPoint public static final float F5 = Float.MAX_VALUE;
+
+    @DataPoint public static final double D1 = Double.MIN_VALUE;
+    @DataPoint public static final double D2 = -0.0;
+    @DataPoint public static final double D3 = +0.0;
+    @DataPoint public static final double D4 = 14.5;
+    @DataPoint public static final double D5 = Double.MAX_VALUE;
+
+    @DataPoint public static final boolean T1 = false;
+    @DataPoint public static final boolean T2 = true;
+
+    @DataPoint public static final char C1 = Character.MIN_VALUE;
+    @DataPoint public static final char C2 = 0;
+    @DataPoint public static final char C3 = 14;
+    @DataPoint public static final char C4 = Character.MAX_VALUE;
+
+    private static final float FLOAT_DELTA = 0.00001f;
+    private static final double DOUBLE_DELTA = 0.00001;
+
+    private PrimitiveValueProfile.Enabled profile;
+
+    @Before
+    public void create() {
+        profile = (PrimitiveValueProfile.Enabled) PrimitiveValueProfile.Enabled.create();
+    }
+
+    @Test
+    public void testInitial() {
+        assertThat(profile.isGeneric(), is(false));
+        assertThat(profile.isUninitialized(), is(true));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneObject(Object value) {
+        Object result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoObject(Object value0, Object value1) {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+
+        if (value0 == value1) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeObject(Object value0, Object value1, Object value2) {
+        Object result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+        Object result2 = profile.profile(value2);
+
+        assertThat(result0, is(value0));
+        assertThat(result1, is(value1));
+        assertThat(result2, is(value2));
+
+        if (value0 == value1 && value1 == value2) {
+            assertThat(profile.getCachedValue(), is(value0));
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneByte(byte value) {
+        byte result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoByte(byte value0, byte value1) {
+        byte result0 = profile.profile(value0);
+        byte result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Byte);
+            assertEquals((byte) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeByte(byte value0, byte value1, byte value2) {
+        byte result0 = profile.profile(value0);
+        byte result1 = profile.profile(value1);
+        byte result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Byte);
+            assertEquals((byte) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneShort(short value) {
+        short result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoShort(short value0, short value1) {
+        short result0 = profile.profile(value0);
+        short result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Short);
+            assertEquals((short) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeShort(short value0, short value1, short value2) {
+        short result0 = profile.profile(value0);
+        short result1 = profile.profile(value1);
+        short result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Short);
+            assertEquals((short) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneInteger(int value) {
+        int result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoInteger(int value0, int value1) {
+        int result0 = profile.profile(value0);
+        int result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Integer);
+            assertEquals((int) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeInteger(int value0, int value1, int value2) {
+        int result0 = profile.profile(value0);
+        int result1 = profile.profile(value1);
+        int result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Integer);
+            assertEquals((int) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneLong(long value) {
+        long result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoLong(long value0, long value1) {
+        long result0 = profile.profile(value0);
+        long result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Long);
+            assertEquals((long) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeLong(long value0, long value1, long value2) {
+        long result0 = profile.profile(value0);
+        long result1 = profile.profile(value1);
+        long result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Long);
+            assertEquals((long) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneFloat(float value) {
+        float result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoFloat(float value0, float value1) {
+        float result0 = profile.profile(value0);
+        float result1 = profile.profile(value1);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
+            assertTrue(profile.getCachedValue() instanceof Float);
+            assertEquals((float) profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeFloat(float value0, float value1, float value2) {
+        float result0 = profile.profile(value0);
+        float result1 = profile.profile(value1);
+        float result2 = profile.profile(value2);
+
+        assertEquals(result0, value0, FLOAT_DELTA);
+        assertEquals(result1, value1, FLOAT_DELTA);
+        assertEquals(result2, value2, FLOAT_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
+            assertTrue(profile.getCachedValue() instanceof Float);
+            assertEquals((float) profile.getCachedValue(), value0, FLOAT_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneDouble(double value) {
+        double result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoDouble(double value0, double value1) {
+        double result0 = profile.profile(value0);
+        double result1 = profile.profile(value1);
+
+        assertEquals(result0, value0, DOUBLE_DELTA);
+        assertEquals(result1, value1, DOUBLE_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
+            assertTrue(profile.getCachedValue() instanceof Double);
+            assertEquals((double) profile.getCachedValue(), value0, DOUBLE_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeDouble(double value0, double value1, double value2) {
+        double result0 = profile.profile(value0);
+        double result1 = profile.profile(value1);
+        double result2 = profile.profile(value2);
+
+        assertEquals(result0, value0, DOUBLE_DELTA);
+        assertEquals(result1, value1, DOUBLE_DELTA);
+        assertEquals(result2, value2, DOUBLE_DELTA);
+
+        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
+            assertTrue(profile.getCachedValue() instanceof Double);
+            assertEquals((double) profile.getCachedValue(), value0, DOUBLE_DELTA);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneBoolean(boolean value) {
+        boolean result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoBoolean(boolean value0, boolean value1) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Boolean);
+            assertEquals((boolean) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeBoolean(boolean value0, boolean value1, boolean value2) {
+        boolean result0 = profile.profile(value0);
+        boolean result1 = profile.profile(value1);
+        boolean result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Boolean);
+            assertEquals((boolean) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileOneChar(char value) {
+        char result = profile.profile(value);
+
+        assertThat(result, is(value));
+        assertEquals(profile.getCachedValue(), value);
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileTwoChar(char value0, char value1) {
+        char result0 = profile.profile(value0);
+        char result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+
+        if (value0 == value1) {
+            assertTrue(profile.getCachedValue() instanceof Character);
+            assertEquals((char) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testProfileThreeChar(char value0, char value1, char value2) {
+        char result0 = profile.profile(value0);
+        char result1 = profile.profile(value1);
+        char result2 = profile.profile(value2);
+
+        assertEquals(result0, value0);
+        assertEquals(result1, value1);
+        assertEquals(result2, value2);
+
+        if (value0 == value1 && value1 == value2) {
+            assertTrue(profile.getCachedValue() instanceof Character);
+            assertEquals((char) profile.getCachedValue(), value0);
+            assertThat(profile.isGeneric(), is(false));
+        } else {
+            assertThat(profile.isGeneric(), is(true));
+        }
+        assertThat(profile.isUninitialized(), is(false));
+        profile.toString(); // test that it is not crashing
+    }
+
+    @Theory
+    public void testWithBoxedBoxedByte(byte value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Byte);
+        assertEquals((byte) result0, value);
+        assertTrue(result1 instanceof Byte);
+        assertEquals((byte) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedByte(byte value) {
+        byte result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Byte);
+        assertEquals((byte) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedByte(byte value) {
+        Object result0 = profile.profile((Object) value);
+        byte result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Byte);
+        assertEquals((byte) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedShort(short value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Short);
+        assertEquals((short) result0, value);
+        assertTrue(result1 instanceof Short);
+        assertEquals((short) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedShort(short value) {
+        short result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Short);
+        assertEquals((short) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedShort(short value) {
+        Object result0 = profile.profile((Object) value);
+        short result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Short);
+        assertEquals((short) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedInt(int value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Integer);
+        assertEquals((int) result0, value);
+        assertTrue(result1 instanceof Integer);
+        assertEquals((int) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedInt(int value) {
+        int result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Integer);
+        assertEquals((int) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedInt(int value) {
+        Object result0 = profile.profile((Object) value);
+        int result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Integer);
+        assertEquals((int) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedLong(long value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Long);
+        assertEquals((long) result0, value);
+        assertTrue(result1 instanceof Long);
+        assertEquals((long) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedLong(long value) {
+        long result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Long);
+        assertEquals((long) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedLong(long value) {
+        Object result0 = profile.profile((Object) value);
+        long result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Long);
+        assertEquals((long) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedFloat(float value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Float);
+        assertTrue(PrimitiveValueProfile.exactCompare((float) result0, value));
+        assertTrue(result1 instanceof Float);
+        assertTrue(PrimitiveValueProfile.exactCompare((float) result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedFloat(float value) {
+        float result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(PrimitiveValueProfile.exactCompare(result0, value));
+        assertTrue(result1 instanceof Float);
+        assertTrue(PrimitiveValueProfile.exactCompare((float) result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedFloat(float value) {
+        Object result0 = profile.profile((Object) value);
+        float result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Float);
+        assertTrue(PrimitiveValueProfile.exactCompare((float) result0, value));
+        assertTrue(PrimitiveValueProfile.exactCompare(result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedDouble(double value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Double);
+        assertTrue(PrimitiveValueProfile.exactCompare((double) result0, value));
+        assertTrue(result1 instanceof Double);
+        assertTrue(PrimitiveValueProfile.exactCompare((double) result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedDouble(double value) {
+        double result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(PrimitiveValueProfile.exactCompare(result0, value));
+        assertTrue(result1 instanceof Double);
+        assertTrue(PrimitiveValueProfile.exactCompare((double) result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedDouble(double value) {
+        Object result0 = profile.profile((Object) value);
+        double result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Double);
+        assertTrue(PrimitiveValueProfile.exactCompare((double) result0, value));
+        assertTrue(PrimitiveValueProfile.exactCompare(result1, value));
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedBoolean(boolean value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Boolean);
+        assertEquals((boolean) result0, value);
+        assertTrue(result1 instanceof Boolean);
+        assertEquals((boolean) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedBoolean(boolean value) {
+        boolean result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Boolean);
+        assertEquals((boolean) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedBoolean(boolean value) {
+        Object result0 = profile.profile((Object) value);
+        boolean result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Boolean);
+        assertEquals((boolean) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedBoxedChar(char value) {
+        Object result0 = profile.profile((Object) value);
+        Object result1 = profile.profile((Object) value);
+
+        assertTrue(result0 instanceof Character);
+        assertEquals((char) result0, value);
+        assertTrue(result1 instanceof Character);
+        assertEquals((char) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithUnboxedBoxedChar(char value) {
+        char result0 = profile.profile(value);
+        Object result1 = profile.profile((Object) value);
+
+        assertEquals(result0, value);
+        assertTrue(result1 instanceof Character);
+        assertEquals((char) result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBoxedUnboxedCharacter(char value) {
+        Object result0 = profile.profile((Object) value);
+        char result1 = profile.profile(value);
+
+        assertTrue(result0 instanceof Character);
+        assertEquals((char) result0, value);
+        assertEquals(result1, value);
+        assertFalse(profile.isUninitialized());
+        assertFalse(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithByteThenObject(byte value0, Object value1) {
+        byte result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithShortThenObject(short value0, Object value1) {
+        short result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithIntThenObject(int value0, Object value1) {
+        int result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithLongThenObject(long value0, Object value1) {
+        long result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithFloatThenObject(float value0, Object value1) {
+        float result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertTrue(PrimitiveValueProfile.exactCompare(result0, value0));
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithDoubleThenObject(double value0, Object value1) {
+        double result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertTrue(PrimitiveValueProfile.exactCompare(result0, value0));
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithBooleanThenObject(boolean value0, Object value1) {
+        boolean result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Theory
+    public void testWithCharThenObject(char value0, Object value1) {
+        char result0 = profile.profile(value0);
+        Object result1 = profile.profile(value1);
+
+        assertEquals(result0, value0);
+        assertSame(result1, value1);
+        assertFalse(profile.isUninitialized());
+        assertTrue(profile.isGeneric());
+    }
+
+    @Test
+    public void testNegativeZeroFloat() {
+        profile.profile(-0.0f);
+        profile.profile(+0.0f);
+        assertThat(profile.isGeneric(), is(true));
+    }
+
+    @Test
+    public void testNegativeZeroDouble() {
+        profile.profile(-0.0);
+        profile.profile(+0.0);
+        assertThat(profile.isGeneric(), is(true));
+    }
+
+    @Test
+    public void testDisabled() {
+        PrimitiveValueProfile.Disabled p = (PrimitiveValueProfile.Disabled) PrimitiveValueProfile.Disabled.INSTANCE;
+        assertThat(p.profile(O1), is(O1));
+        assertThat(p.profile(B1), is(B1));
+        assertThat(p.profile(S1), is(S1));
+        assertThat(p.profile(I1), is(I1));
+        assertThat(p.profile(L1), is(L1));
+        assertThat(p.profile(F1), is(F1));
+        assertThat(p.profile(D1), is(D1));
+        assertThat(p.profile(T1), is(T1));
+        assertThat(p.profile(C1), is(C1));
+        p.toString(); // test that it is not crashing
+    }
+
+}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/BinaryConditionProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.utilities;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class BinaryConditionProfileTest {
-
-    @DataPoints public static boolean[] data = new boolean[]{true, false};
-
-    private BinaryConditionProfile profile;
-
-    @Before
-    public void create() {
-        profile = (BinaryConditionProfile) ConditionProfile.createBinaryProfile();
-    }
-
-    @Test
-    public void testInitial() {
-        assertThat(profile.wasTrue(), is(false));
-        assertThat(profile.wasFalse(), is(false));
-    }
-
-    @Theory
-    public void testProfileOne(boolean value) {
-        boolean result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertThat(profile.wasTrue(), is(value));
-        assertThat(profile.wasFalse(), is(!value));
-    }
-
-    @Theory
-    public void testProfileTwo(boolean value0, boolean value1) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(profile.wasTrue(), is(value0 || value1));
-        assertThat(profile.wasFalse(), is(!value0 || !value1));
-    }
-
-    @Theory
-    public void testProfileThree(boolean value0, boolean value1, boolean value2) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-        boolean result2 = profile.profile(value2);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(result2, is(value2));
-        assertThat(profile.wasTrue(), is(value0 || value1 || value2));
-        assertThat(profile.wasFalse(), is(!value0 || !value1 || !value2));
-    }
-
-}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/BranchProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2013, 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.
- *
- * 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.utilities;
-
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class BranchProfileTest {
-
-    @Test
-    public void testEnter() {
-        BranchProfile profile = BranchProfile.create();
-        profile.enter();
-        profile.enter();
-    }
-
-    @Test
-    public void testToString() {
-        BranchProfile profile = BranchProfile.create();
-        assertTrue(profile.toString().contains(profile.getClass().getSimpleName()));
-        assertTrue(profile.toString().contains("not-visited"));
-        assertTrue(profile.toString().contains(Integer.toHexString(profile.hashCode())));
-        profile.enter();
-        assertTrue(profile.toString().contains(profile.getClass().getSimpleName()));
-        assertTrue(profile.toString().contains("visited"));
-        assertTrue(profile.toString().contains(Integer.toHexString(profile.hashCode())));
-    }
-
-}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/CountingConditionProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.utilities;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class CountingConditionProfileTest {
-
-    @DataPoints public static boolean[] data = new boolean[]{true, false};
-
-    private CountingConditionProfile profile;
-
-    @Before
-    public void create() {
-        profile = (CountingConditionProfile) ConditionProfile.createCountingProfile();
-    }
-
-    @Test
-    public void testInitial() {
-        assertThat(profile.getTrueCount(), is(0));
-        assertThat(profile.getFalseCount(), is(0));
-    }
-
-    @Theory
-    public void testProfileOne(boolean value) {
-        boolean result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertThat(profile.getTrueCount(), is(value ? 1 : 0));
-        assertThat(profile.getFalseCount(), is(!value ? 1 : 0));
-    }
-
-    @Theory
-    public void testProfileTwo(boolean value0, boolean value1) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0)));
-        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0)));
-    }
-
-    @Theory
-    public void testProfileThree(boolean value0, boolean value1, boolean value2) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-        boolean result2 = profile.profile(value2);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(result2, is(value2));
-        assertThat(profile.getTrueCount(), is((value0 ? 1 : 0) + (value1 ? 1 : 0) + (value2 ? 1 : 0)));
-        assertThat(profile.getFalseCount(), is((!value0 ? 1 : 0) + (!value1 ? 1 : 0) + (!value2 ? 1 : 0)));
-    }
-
-}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/ExactClassValueProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.utilities;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-
-import java.lang.reflect.Method;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class ExactClassValueProfileTest {
-
-    @DataPoint public static final String O1 = new String();
-    @DataPoint public static final String O2 = new String();
-    @DataPoint public static final Object O3 = new Object();
-    @DataPoint public static final Integer O4 = new Integer(1);
-    @DataPoint public static final Integer O5 = null;
-    @DataPoint public static final TestBaseClass O6 = new TestBaseClass();
-    @DataPoint public static final TestSubClass O7 = new TestSubClass();
-
-    private ValueProfile profile;
-
-    private static class TestBaseClass {
-    }
-
-    private static class TestSubClass extends TestBaseClass {
-    }
-
-    @Before
-    public void create() {
-        profile = ValueProfile.createClassProfile();
-    }
-
-    @Test
-    public void testInitial() throws Exception {
-        assertThat(isGeneric(profile), is(false));
-        assertThat(isUninitialized(profile), is(true));
-        assertNull(getCachedClass(profile));
-        assertNotNull(profile.toString());
-    }
-
-    @Theory
-    public void testProfileOne(Object value) throws Exception {
-        Object result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(expectedClass(value), getCachedClass(profile));
-        assertThat(isUninitialized(profile), is(false));
-        assertNotNull(profile.toString());
-    }
-
-    @Theory
-    public void testProfileTwo(Object value0, Object value1) throws Exception {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-
-        Object expectedClass = expectedClass(value0) == expectedClass(value1) ? expectedClass(value0) : Object.class;
-
-        assertEquals(expectedClass, getCachedClass(profile));
-        assertThat(isUninitialized(profile), is(false));
-        assertThat(isGeneric(profile), is(expectedClass == Object.class));
-        assertNotNull(profile.toString());
-    }
-
-    @Theory
-    public void testProfileThree(Object value0, Object value1, Object value2) throws Exception {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-        Object result2 = profile.profile(value2);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(result2, is(value2));
-
-        Object expectedClass = expectedClass(value0) == expectedClass(value1) && expectedClass(value1) == expectedClass(value2) ? expectedClass(value0) : Object.class;
-
-        assertEquals(expectedClass, getCachedClass(profile));
-        assertThat(isUninitialized(profile), is(false));
-        assertThat(isGeneric(profile), is(expectedClass == Object.class));
-        assertNotNull(profile.toString());
-    }
-
-    private static Class<?> expectedClass(Object value) {
-        return value == null ? Object.class : value.getClass();
-    }
-
-    private static Object get(String name, ValueProfile profile) throws Exception {
-        final Method m = profile.getClass().getDeclaredMethod(name);
-        m.setAccessible(true);
-        return m.invoke(profile);
-    }
-
-    private static Object getCachedClass(ValueProfile profile) throws Exception {
-        return get("getCachedClass", profile);
-    }
-
-    private static boolean isUninitialized(ValueProfile profile) throws Exception {
-        return (Boolean) get("isUninitialized", profile);
-    }
-
-    private static boolean isGeneric(ValueProfile profile) throws Exception {
-        return (Boolean) get("isGeneric", profile);
-    }
-}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/IdentityValueProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.utilities;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.lang.reflect.Method;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class IdentityValueProfileTest {
-
-    @DataPoint public static final String O1 = new String();
-    @DataPoint public static final String O2 = O1;
-    @DataPoint public static final Object O3 = new Object();
-    @DataPoint public static final Integer O4 = new Integer(1);
-    @DataPoint public static final Integer O5 = null;
-
-    private ValueProfile profile;
-
-    @Before
-    public void create() {
-        profile = ValueProfile.createIdentityProfile();
-    }
-
-    @Test
-    public void testInitial() throws Exception {
-        assertThat(isGeneric(profile), is(false));
-        assertThat(isUninitialized(profile), is(true));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOne(Object value) throws Exception {
-        Object result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(getCachedValue(profile), value);
-        assertThat(isUninitialized(profile), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwo(Object value0, Object value1) throws Exception {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-
-        if (value0 == value1) {
-            assertThat(getCachedValue(profile), is(value0));
-            assertThat(isGeneric(profile), is(false));
-        } else {
-            assertThat(isGeneric(profile), is(true));
-        }
-        assertThat(isUninitialized(profile), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThree(Object value0, Object value1, Object value2) throws Exception {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-        Object result2 = profile.profile(value2);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(result2, is(value2));
-
-        if (value0 == value1 && value1 == value2) {
-            assertThat(getCachedValue(profile), is(value0));
-            assertThat(isGeneric(profile), is(false));
-        } else {
-            assertThat(isGeneric(profile), is(true));
-        }
-        assertThat(isUninitialized(profile), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    private static Object get(String name, ValueProfile profile) throws Exception {
-        final Method m = profile.getClass().getDeclaredMethod(name);
-        m.setAccessible(true);
-        return m.invoke(profile);
-    }
-
-    private static Object getCachedValue(ValueProfile profile) throws Exception {
-        return get("getCachedValue", profile);
-    }
-
-    private static boolean isUninitialized(ValueProfile profile) throws Exception {
-        return (Boolean) get("isUninitialized", profile);
-    }
-
-    private static boolean isGeneric(ValueProfile profile) throws Exception {
-        return (Boolean) get("isGeneric", profile);
-    }
-}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/utilities/PrimitiveValueProfileTest.java	Wed Dec 16 12:31:17 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,950 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.utilities;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.theories.DataPoint;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-@RunWith(Theories.class)
-public class PrimitiveValueProfileTest {
-
-    @DataPoint public static final String O1 = new String();
-    @DataPoint public static final String O2 = O1;
-    @DataPoint public static final Object O3 = new Object();
-    @DataPoint public static final Object O4 = null;
-
-    @DataPoint public static final byte B1 = Byte.MIN_VALUE;
-    @DataPoint public static final byte B2 = 0;
-    @DataPoint public static final byte B3 = 14;
-    @DataPoint public static final byte B4 = Byte.MAX_VALUE;
-
-    @DataPoint public static final short S1 = Short.MIN_VALUE;
-    @DataPoint public static final short S2 = 0;
-    @DataPoint public static final short S3 = 14;
-    @DataPoint public static final short S4 = Short.MAX_VALUE;
-
-    @DataPoint public static final int I1 = Integer.MIN_VALUE;
-    @DataPoint public static final int I2 = 0;
-    @DataPoint public static final int I3 = 14;
-    @DataPoint public static final int I4 = Integer.MAX_VALUE;
-
-    @DataPoint public static final long L1 = Long.MIN_VALUE;
-    @DataPoint public static final long L2 = 0;
-    @DataPoint public static final long L3 = 14;
-    @DataPoint public static final long L4 = Long.MAX_VALUE;
-
-    @DataPoint public static final float F1 = Float.MIN_VALUE;
-    @DataPoint public static final float F2 = -0.0f;
-    @DataPoint public static final float F3 = +0.0f;
-    @DataPoint public static final float F4 = 14.5f;
-    @DataPoint public static final float F5 = Float.MAX_VALUE;
-
-    @DataPoint public static final double D1 = Double.MIN_VALUE;
-    @DataPoint public static final double D2 = -0.0;
-    @DataPoint public static final double D3 = +0.0;
-    @DataPoint public static final double D4 = 14.5;
-    @DataPoint public static final double D5 = Double.MAX_VALUE;
-
-    @DataPoint public static final boolean T1 = false;
-    @DataPoint public static final boolean T2 = true;
-
-    @DataPoint public static final char C1 = Character.MIN_VALUE;
-    @DataPoint public static final char C2 = 0;
-    @DataPoint public static final char C3 = 14;
-    @DataPoint public static final char C4 = Character.MAX_VALUE;
-
-    private static final float FLOAT_DELTA = 0.00001f;
-    private static final double DOUBLE_DELTA = 0.00001;
-
-    private PrimitiveValueProfile profile;
-
-    @Before
-    public void create() {
-        profile = ValueProfile.createPrimitiveProfile();
-    }
-
-    @Test
-    public void testInitial() {
-        assertThat(profile.isGeneric(), is(false));
-        assertThat(profile.isUninitialized(), is(true));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneObject(Object value) {
-        Object result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoObject(Object value0, Object value1) {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-
-        if (value0 == value1) {
-            assertThat(profile.getCachedValue(), is(value0));
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeObject(Object value0, Object value1, Object value2) {
-        Object result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-        Object result2 = profile.profile(value2);
-
-        assertThat(result0, is(value0));
-        assertThat(result1, is(value1));
-        assertThat(result2, is(value2));
-
-        if (value0 == value1 && value1 == value2) {
-            assertThat(profile.getCachedValue(), is(value0));
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneByte(byte value) {
-        byte result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoByte(byte value0, byte value1) {
-        byte result0 = profile.profile(value0);
-        byte result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Byte);
-            assertEquals((byte) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeByte(byte value0, byte value1, byte value2) {
-        byte result0 = profile.profile(value0);
-        byte result1 = profile.profile(value1);
-        byte result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Byte);
-            assertEquals((byte) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneShort(short value) {
-        short result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoShort(short value0, short value1) {
-        short result0 = profile.profile(value0);
-        short result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Short);
-            assertEquals((short) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeShort(short value0, short value1, short value2) {
-        short result0 = profile.profile(value0);
-        short result1 = profile.profile(value1);
-        short result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Short);
-            assertEquals((short) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneInteger(int value) {
-        int result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoInteger(int value0, int value1) {
-        int result0 = profile.profile(value0);
-        int result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Integer);
-            assertEquals((int) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeInteger(int value0, int value1, int value2) {
-        int result0 = profile.profile(value0);
-        int result1 = profile.profile(value1);
-        int result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Integer);
-            assertEquals((int) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneLong(long value) {
-        long result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoLong(long value0, long value1) {
-        long result0 = profile.profile(value0);
-        long result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Long);
-            assertEquals((long) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeLong(long value0, long value1, long value2) {
-        long result0 = profile.profile(value0);
-        long result1 = profile.profile(value1);
-        long result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Long);
-            assertEquals((long) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneFloat(float value) {
-        float result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoFloat(float value0, float value1) {
-        float result0 = profile.profile(value0);
-        float result1 = profile.profile(value1);
-
-        assertEquals(result0, value0, FLOAT_DELTA);
-        assertEquals(result1, value1, FLOAT_DELTA);
-
-        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
-            assertTrue(profile.getCachedValue() instanceof Float);
-            assertEquals((float) profile.getCachedValue(), value0, FLOAT_DELTA);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeFloat(float value0, float value1, float value2) {
-        float result0 = profile.profile(value0);
-        float result1 = profile.profile(value1);
-        float result2 = profile.profile(value2);
-
-        assertEquals(result0, value0, FLOAT_DELTA);
-        assertEquals(result1, value1, FLOAT_DELTA);
-        assertEquals(result2, value2, FLOAT_DELTA);
-
-        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
-            assertTrue(profile.getCachedValue() instanceof Float);
-            assertEquals((float) profile.getCachedValue(), value0, FLOAT_DELTA);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneDouble(double value) {
-        double result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoDouble(double value0, double value1) {
-        double result0 = profile.profile(value0);
-        double result1 = profile.profile(value1);
-
-        assertEquals(result0, value0, DOUBLE_DELTA);
-        assertEquals(result1, value1, DOUBLE_DELTA);
-
-        if (PrimitiveValueProfile.exactCompare(value0, value1)) {
-            assertTrue(profile.getCachedValue() instanceof Double);
-            assertEquals((double) profile.getCachedValue(), value0, DOUBLE_DELTA);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeDouble(double value0, double value1, double value2) {
-        double result0 = profile.profile(value0);
-        double result1 = profile.profile(value1);
-        double result2 = profile.profile(value2);
-
-        assertEquals(result0, value0, DOUBLE_DELTA);
-        assertEquals(result1, value1, DOUBLE_DELTA);
-        assertEquals(result2, value2, DOUBLE_DELTA);
-
-        if (PrimitiveValueProfile.exactCompare(value0, value1) && PrimitiveValueProfile.exactCompare(value1, value2)) {
-            assertTrue(profile.getCachedValue() instanceof Double);
-            assertEquals((double) profile.getCachedValue(), value0, DOUBLE_DELTA);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneBoolean(boolean value) {
-        boolean result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoBoolean(boolean value0, boolean value1) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Boolean);
-            assertEquals((boolean) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeBoolean(boolean value0, boolean value1, boolean value2) {
-        boolean result0 = profile.profile(value0);
-        boolean result1 = profile.profile(value1);
-        boolean result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Boolean);
-            assertEquals((boolean) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileOneChar(char value) {
-        char result = profile.profile(value);
-
-        assertThat(result, is(value));
-        assertEquals(profile.getCachedValue(), value);
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileTwoChar(char value0, char value1) {
-        char result0 = profile.profile(value0);
-        char result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-
-        if (value0 == value1) {
-            assertTrue(profile.getCachedValue() instanceof Character);
-            assertEquals((char) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testProfileThreeChar(char value0, char value1, char value2) {
-        char result0 = profile.profile(value0);
-        char result1 = profile.profile(value1);
-        char result2 = profile.profile(value2);
-
-        assertEquals(result0, value0);
-        assertEquals(result1, value1);
-        assertEquals(result2, value2);
-
-        if (value0 == value1 && value1 == value2) {
-            assertTrue(profile.getCachedValue() instanceof Character);
-            assertEquals((char) profile.getCachedValue(), value0);
-            assertThat(profile.isGeneric(), is(false));
-        } else {
-            assertThat(profile.isGeneric(), is(true));
-        }
-        assertThat(profile.isUninitialized(), is(false));
-        profile.toString(); // test that it is not crashing
-    }
-
-    @Theory
-    public void testWithBoxedBoxedByte(byte value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Byte);
-        assertEquals((byte) result0, value);
-        assertTrue(result1 instanceof Byte);
-        assertEquals((byte) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedByte(byte value) {
-        byte result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Byte);
-        assertEquals((byte) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedByte(byte value) {
-        Object result0 = profile.profile((Object) value);
-        byte result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Byte);
-        assertEquals((byte) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedShort(short value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Short);
-        assertEquals((short) result0, value);
-        assertTrue(result1 instanceof Short);
-        assertEquals((short) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedShort(short value) {
-        short result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Short);
-        assertEquals((short) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedShort(short value) {
-        Object result0 = profile.profile((Object) value);
-        short result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Short);
-        assertEquals((short) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedInt(int value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Integer);
-        assertEquals((int) result0, value);
-        assertTrue(result1 instanceof Integer);
-        assertEquals((int) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedInt(int value) {
-        int result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Integer);
-        assertEquals((int) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedInt(int value) {
-        Object result0 = profile.profile((Object) value);
-        int result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Integer);
-        assertEquals((int) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedLong(long value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Long);
-        assertEquals((long) result0, value);
-        assertTrue(result1 instanceof Long);
-        assertEquals((long) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedLong(long value) {
-        long result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Long);
-        assertEquals((long) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedLong(long value) {
-        Object result0 = profile.profile((Object) value);
-        long result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Long);
-        assertEquals((long) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedFloat(float value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Float);
-        assertTrue(PrimitiveValueProfile.exactCompare((float) result0, value));
-        assertTrue(result1 instanceof Float);
-        assertTrue(PrimitiveValueProfile.exactCompare((float) result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedFloat(float value) {
-        float result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(PrimitiveValueProfile.exactCompare(result0, value));
-        assertTrue(result1 instanceof Float);
-        assertTrue(PrimitiveValueProfile.exactCompare((float) result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedFloat(float value) {
-        Object result0 = profile.profile((Object) value);
-        float result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Float);
-        assertTrue(PrimitiveValueProfile.exactCompare((float) result0, value));
-        assertTrue(PrimitiveValueProfile.exactCompare(result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedDouble(double value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Double);
-        assertTrue(PrimitiveValueProfile.exactCompare((double) result0, value));
-        assertTrue(result1 instanceof Double);
-        assertTrue(PrimitiveValueProfile.exactCompare((double) result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedDouble(double value) {
-        double result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(PrimitiveValueProfile.exactCompare(result0, value));
-        assertTrue(result1 instanceof Double);
-        assertTrue(PrimitiveValueProfile.exactCompare((double) result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedDouble(double value) {
-        Object result0 = profile.profile((Object) value);
-        double result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Double);
-        assertTrue(PrimitiveValueProfile.exactCompare((double) result0, value));
-        assertTrue(PrimitiveValueProfile.exactCompare(result1, value));
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedBoolean(boolean value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Boolean);
-        assertEquals((boolean) result0, value);
-        assertTrue(result1 instanceof Boolean);
-        assertEquals((boolean) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedBoolean(boolean value) {
-        boolean result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Boolean);
-        assertEquals((boolean) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedBoolean(boolean value) {
-        Object result0 = profile.profile((Object) value);
-        boolean result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Boolean);
-        assertEquals((boolean) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedBoxedChar(char value) {
-        Object result0 = profile.profile((Object) value);
-        Object result1 = profile.profile((Object) value);
-
-        assertTrue(result0 instanceof Character);
-        assertEquals((char) result0, value);
-        assertTrue(result1 instanceof Character);
-        assertEquals((char) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithUnboxedBoxedChar(char value) {
-        char result0 = profile.profile(value);
-        Object result1 = profile.profile((Object) value);
-
-        assertEquals(result0, value);
-        assertTrue(result1 instanceof Character);
-        assertEquals((char) result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBoxedUnboxedCharacter(char value) {
-        Object result0 = profile.profile((Object) value);
-        char result1 = profile.profile(value);
-
-        assertTrue(result0 instanceof Character);
-        assertEquals((char) result0, value);
-        assertEquals(result1, value);
-        assertFalse(profile.isUninitialized());
-        assertFalse(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithByteThenObject(byte value0, Object value1) {
-        byte result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithShortThenObject(short value0, Object value1) {
-        short result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithIntThenObject(int value0, Object value1) {
-        int result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithLongThenObject(long value0, Object value1) {
-        long result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithFloatThenObject(float value0, Object value1) {
-        float result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertTrue(PrimitiveValueProfile.exactCompare(result0, value0));
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithDoubleThenObject(double value0, Object value1) {
-        double result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertTrue(PrimitiveValueProfile.exactCompare(result0, value0));
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithBooleanThenObject(boolean value0, Object value1) {
-        boolean result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Theory
-    public void testWithCharThenObject(char value0, Object value1) {
-        char result0 = profile.profile(value0);
-        Object result1 = profile.profile(value1);
-
-        assertEquals(result0, value0);
-        assertSame(result1, value1);
-        assertFalse(profile.isUninitialized());
-        assertTrue(profile.isGeneric());
-    }
-
-    @Test
-    public void testNegativeZeroFloat() {
-        profile.profile(-0.0f);
-        profile.profile(+0.0f);
-        assertThat(profile.isGeneric(), is(true));
-    }
-
-    @Test
-    public void testNegativeZeroDouble() {
-        profile.profile(-0.0);
-        profile.profile(+0.0);
-        assertThat(profile.isGeneric(), is(true));
-    }
-
-}
--- a/truffle/com.oracle.truffle.api/snapshot.sigtest	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/snapshot.sigtest	Wed Dec 16 16:38:13 2015 +0100
@@ -172,6 +172,8 @@
 meth public abstract java.lang.String getName()
 meth public abstract java.util.Collection<com.oracle.truffle.api.RootCallTarget> getCallTargets()
 meth public abstract void notifyTransferToInterpreter()
+meth public abstract boolean isProfilingEnabled()
+
 
 CLSS public abstract interface com.oracle.truffle.api.TruffleRuntimeAccess
 meth public abstract com.oracle.truffle.api.TruffleRuntime getRuntime()
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Wed Dec 16 16:38:13 2015 +0100
@@ -173,4 +173,13 @@
      */
     void notifyTransferToInterpreter();
 
+    /**
+     * Whether or not the {@link TruffleRuntime} implementation can or wants to use gathered
+     * profiling information Truffle compilation. If this method returns <code>false</code> then all
+     * profiles in the {@link com.oracle.truffle.api.utilities} package are returning void
+     * implementations. If it returns <code>true</code> then all implementations gather profilinig
+     * information.
+     */
+    boolean isProfilingEnabled();
+
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Wed Dec 16 16:38:13 2015 +0100
@@ -177,4 +177,8 @@
         }
         return new DefaultLoopNode(repeating);
     }
+
+    public boolean isProfilingEnabled() {
+        return false;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/BranchProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * class SampleNode extends Node {
+ * 
+ *     final BranchProfile errorProfile = BranchProfile.create();
+ * 
+ *     void execute(int value) {
+ *         if (value == Integer.MAX_VALUE) {
+ *             errorProfile.enter();
+ *             throw new Error(&quot;Invalid input value&quot;)
+ *         }
+ *         return value;
+ *     }
+ * }
+ * </pre>
+ *
+ * {@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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ByteValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>byte</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ *
+ * {@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 <code>byte</code>.
+     *
+     * @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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ConditionProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * ConditionProfiles are useful to profile the outcome of conditions.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * {@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
+     * <code>true</code> or to be never <code>false</code>. 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
+     * <code>true</code> or to be never <code>false</code>. 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();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/DoubleValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>double</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ *
+ * {@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 <code>double</code> 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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/FloatValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>float</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ *
+ * {@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 <code>float</code> 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);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/IntValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>int</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ *
+ * {@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 <code>int</code>.
+     *
+     * @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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LongValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>long</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ * {@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 <code>long</code>.
+     *
+     * @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);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/LoopConditionProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * LoopConditionProfiles are designed to profile the outcome of loop conditions. Loop profiles can
+ * be used to profile unpredictable loops as well as predictable loops.
+ * </p>
+ *
+ * <p>
+ * <b> Arbitrary loop usage example: </b>
+ *
+ * <pre>
+ * class LoopNode extends Node {
+ * 
+ *     final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
+ * 
+ *     void execute() {
+ *         // loop count cannot be predicted
+ *         while (loopProfile.profile(Math.random() &gt;= 0.9)) {
+ *             // work
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * </p>
+ *
+ * <p>
+ * <b> Counted loop usage example: </b>
+ *
+ * <pre>
+ * 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 &lt; length); i++) {
+ *             // work
+ *         }
+ *     }
+ * }
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ *
+ *
+ * {@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
+     * <code>true</code>. 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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/PrimitiveValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * 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.
+ * </p>
+ *
+ * {@inheritDoc}
+ */
+public abstract class PrimitiveValueProfile extends ValueProfile {
+
+    PrimitiveValueProfile() {
+    }
+
+    @Override
+    public abstract <T> 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> 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> 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);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/Profile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * 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.
+ * </p>
+ *
+ * <p>
+ * <b>Usage:</b> Profiles should be stored in <code>final</code> 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. <b>Never</b> 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.
+ * </p>
+ *
+ * <p>
+ * <b>Compilation:</b> 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.
+ * </p>
+ *
+ * <p>
+ * <b>Footprint:</b> Whether profiling information can be forwarded to the compiler depends on the
+ * capabilities of the {@link TruffleRuntime runtime system}. If the runtime returns
+ * <code>true</code> 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.
+ * </p>
+ *
+ * <p>
+ * Profile subclasses:
+ * <ul>
+ * <li> {@link BranchProfile} to profile on unlikely branches like errors.</li>
+ * <li> {@link ConditionProfile} to profile on conditionals or boolean values.</li>
+ * <li> {@link LoopConditionProfile} to profile on conditionals of loops with special support for
+ * counted loops.</li>
+ * <li> {@link ValueProfile} to profile on properties like type and identity of values.</li>
+ * <li> {@link ByteValueProfile} to profile on <code>byte</code> values.</li>
+ * <li> {@link IntValueProfile} to profile on <code>int</code> values.</li>
+ * <li> {@link LongValueProfile} to profile on <code>long</code> values.</li>
+ * <li> {@link FloatValueProfile} to profile on <code>float</code> values.</li>
+ * <li> {@link DoubleValueProfile} to profile on <code>double</code> values.</li>
+ * <li> {@link PrimitiveValueProfile} to profile on objects by identity and on primitives by value.</li>
+ * </ul>
+ * </p>
+ *
+ * @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()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/ValueProfile.java	Wed Dec 16 16:38:13 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;
+
+/**
+ * <p>
+ * Specialized value profile to capture certain properties of <code>Object</code> 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.
+ * </p>
+ *
+ * <p>
+ * <b> Usage example: </b>
+ *
+ * <pre>
+ * 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;
+ *     }
+ * }
+ * </pre>
+ * <p>
+ *
+ *
+ * {@inheritDoc}
+ *
+ * @see #createIdentityProfile()
+ * @see #createClassProfile()
+ */
+public abstract class ValueProfile extends Profile {
+
+    ValueProfile() {
+    }
+
+    public abstract <T> T profile(T value);
+
+    /**
+     * <p>
+     * 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.
+     * </p>
+     *
+     * <p>
+     * <b>Compilation notes:</b> 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.
+     * </P>
+     *
+     * @see ValueProfile usage example
+     */
+    public static ValueProfile createClassProfile() {
+        if (Truffle.getRuntime().isProfilingEnabled()) {
+            return ExactClass.create();
+        } else {
+            return Disabled.INSTANCE;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns a value profile that profiles the object identity of a value. A single instance can
+     * only profile one particular instance.
+     * </p>
+     *
+     * <p>
+     * <b>Compilation notes:</b> 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.
+     * </p>
+     */
+    public static ValueProfile createIdentityProfile() {
+        if (Truffle.getRuntime().isProfilingEnabled()) {
+            return Identity.create();
+        } else {
+            return Disabled.INSTANCE;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns a value profile that profiles the object equality of a value. A single instance can
+     * only profile one set of equal values.
+     * </p>
+     *
+     * <p>
+     * <b>Compilation notes:</b> 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.
+     * </p>
+     */
+    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> 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> 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> 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> 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"));
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/profiles/package-info.java	Wed Dec 16 16:38:13 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;
+
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BinaryConditionProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BinaryConditionProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -28,11 +28,11 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 
 /**
- * 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()
+ * @deprecated package name renamed to {@link com.oracle.truffle.api.profiles.ConditionProfile}
+ *             instead
  */
+@SuppressWarnings("deprecation")
+@Deprecated
 public final class BinaryConditionProfile extends ConditionProfile {
 
     @CompilationFinal private boolean wasTrue;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/BranchProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -29,14 +29,9 @@
 import com.oracle.truffle.api.nodes.NodeCloneable;
 
 /**
- * Utility class to speculate on branches to be never 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.
- *
- * All {@code BranchProfile} instances must be held in {@code final} fields for compiler
- * optimizations to take effect.
+ * @deprecated use {@link com.oracle.truffle.api.profiles.BranchProfile} instead
  */
+@Deprecated
 public final class BranchProfile extends NodeCloneable {
 
     @CompilationFinal private boolean visited;
@@ -55,6 +50,10 @@
         return visited;
     }
 
+    /**
+     * @deprecated use {@link com.oracle.truffle.api.profiles.BranchProfile#create()} instead
+     */
+    @Deprecated
     public static BranchProfile create() {
         return new BranchProfile();
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -24,33 +24,12 @@
  */
 package com.oracle.truffle.api.utilities;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.nodes.NodeCloneable;
 
 /**
- * Abstract utility class to speculate on conditions. Condition profiles are intended to be used as
- * part of if conditions.
- *
- * Example usage:
- *
- * <pre>
- * private final ConditionProfile zero = ConditionProfile.createBinaryProfile();
- *
- * int value = ...;
- * if (zero.profile(value == 0)) {
- *   return 0;
- * } else {
- *   return value;
- * }
- *
- * </pre>
- *
- * All instances of {@code ConditionProfile} (and subclasses) must be held in {@code final} fields
- * for compiler optimizations to take effect.
- *
- * @see #createCountingProfile()
- * @see #createBinaryProfile()
+ * @deprecated use {@link com.oracle.truffle.api.profiles.ConditionProfile} instead
  */
+@Deprecated
 public abstract class ConditionProfile extends NodeCloneable {
     ConditionProfile() {
     }
@@ -58,27 +37,23 @@
     public abstract boolean profile(boolean value);
 
     /**
-     * Returns a {@link ConditionProfile} that speculates on conditions to be never
-     * <code>true</code> or to be never <code>false</code>. 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()
+     * @deprecated use
+     *             {@link com.oracle.truffle.api.profiles.ConditionProfile#createCountingProfile()}
+     *             instead
      */
+    @SuppressWarnings("deprecation")
+    @Deprecated
     public static ConditionProfile createCountingProfile() {
         return new CountingConditionProfile();
     }
 
     /**
-     * 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()
+     * @deprecated use
+     *             {@link com.oracle.truffle.api.profiles.ConditionProfile#createBinaryProfile()}
+     *             instead
      */
+    @Deprecated
+    @SuppressWarnings("deprecation")
     public static ConditionProfile createBinaryProfile() {
         return new BinaryConditionProfile();
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CountingConditionProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/CountingConditionProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -28,14 +28,11 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 
 /**
- * Utility class to speculate on conditions to be never true or to be never false. Additionally to
- * {@link BinaryConditionProfile} this implementation of {@link ConditionProfile} 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#createCountingProfile()
+ * @deprecated use {@link com.oracle.truffle.api.profiles.ConditionProfile#createCountingProfile()}
+ *             instead
  */
+@Deprecated
+@SuppressWarnings("deprecation")
 public final class CountingConditionProfile extends ConditionProfile {
 
     @CompilationFinal private int trueCount;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -28,8 +28,10 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 
 /**
- * Represents a {@link ValueProfile} that speculates on the exact class of a value.
+ * @deprecated use {@link com.oracle.truffle.api.profiles.ValueProfile#createClassProfile()} instead
  */
+@Deprecated
+@SuppressWarnings("deprecation")
 final class ExactClassValueProfile extends ValueProfile {
 
     @CompilationFinal protected Class<?> cachedClass;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IdentityValueProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/IdentityValueProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -26,11 +26,15 @@
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+
 import java.util.Objects;
 
 /**
- * Represents a {@link ValueProfile} that speculates on the object identity of a value.
+ * @deprecated use {@link com.oracle.truffle.api.profiles.ValueProfile#createIdentityProfile()}
+ *             instead
  */
+@Deprecated
+@SuppressWarnings("deprecation")
 final class IdentityValueProfile extends ValueProfile {
 
     private static final Object UNINITIALIZED = new Object();
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -26,17 +26,14 @@
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+
 import java.util.Objects;
 
 /**
- * Represents a {@link ValueProfile} that speculates on the primitive equality or object identity of
- * values.
- * <p>
- * 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.
+ * @deprecated use {@link com.oracle.truffle.api.profiles.PrimitiveValueProfile} instead
  */
+@Deprecated
+@SuppressWarnings("deprecation")
 public class PrimitiveValueProfile extends ValueProfile {
 
     private static final Object UNINITIALIZED = new Object();
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Wed Dec 16 16:38:13 2015 +0100
@@ -27,51 +27,38 @@
 import com.oracle.truffle.api.nodes.NodeCloneable;
 
 /**
- * Utility class to speculate on certain properties of values.
- *
- * Example usage:
- *
- * <pre>
- * private final ValueProfile classProfile = ValueProfile.createClassProfile();
- *
- * return classProfile.profile(value);
- * </pre>
- *
- * All instances of {@code ValueProfile} (and subclasses) must be held in {@code final} fields for
- * compiler optimizations to take effect.
- *
- * @see #createPrimitiveProfile()
- * @see #createIdentityProfile()
- * @see #createClassProfile()
+ * @deprecated use {@link com.oracle.truffle.api.profiles.ValueProfile} instead
  */
+@Deprecated
+@SuppressWarnings("deprecation")
 public abstract class ValueProfile extends NodeCloneable {
 
     public abstract <T> T profile(T value);
 
     /**
-     * Returns a {@link PrimitiveValueProfile} that speculates on the primitive equality or object
-     * identity of a value.
+     * @deprecated use
+     *             {@link com.oracle.truffle.api.profiles.PrimitiveValueProfile#createEqualityProfile()}
+     *             instead
      */
+    @Deprecated
     public static PrimitiveValueProfile createPrimitiveProfile() {
         return new PrimitiveValueProfile();
     }
 
     /**
-     * Returns a {@link ValueProfile} that speculates on 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.
+     * @deprecated use {@link com.oracle.truffle.api.profiles.ValueProfile#createClassProfile()}
+     *             instead
      */
+    @Deprecated
     public static ValueProfile createClassProfile() {
         return new ExactClassValueProfile();
     }
 
     /**
-     * Returns a {@link ValueProfile} that speculates on the object identity of a value.
+     * @deprecated use {@link com.oracle.truffle.api.profiles.ValueProfile#createIdentityProfile()}
+     *             instead
      */
+    @Deprecated
     public static ValueProfile createIdentityProfile() {
         return new IdentityValueProfile();
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/package-info.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/package-info.java	Wed Dec 16 16:38:13 2015 +0100
@@ -28,8 +28,24 @@
  group="To Review"
  )
  */
-
-/** Various utility methods.
+/**
+ * Various utility classes that aim to make the development of TruffleLanguage guest
+ * languages easier.
+ *
+ * <p>
+ * We try to capture common language patterns in this package. Here is an overview of patterns that
+ * we have captured so far:
+ * <ul>
+ * <li>{@link com.oracle.truffle.api.utilities.AssumedValue} speculates on global values to remain
+ * unchanged.</li>
+ * <li>{@link com.oracle.truffle.api.utilities.CyclicAssumption} speculates on assumptions that
+ * might invalidate more often but are assumed to stabilize over time.</li>
+ * <li>{@link com.oracle.truffle.api.utilities.NeverValidAssumption} utility for assumptions that
+ * are always invalidated</li>
+ * <li>{@link com.oracle.truffle.api.utilities.UnionAssumption} utility for the union of two
+ * assumptions</li>
+ * </ul>
+ * </p>
  */
 package com.oracle.truffle.api.utilities;
 
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Wed Dec 16 16:38:13 2015 +0100
@@ -43,7 +43,7 @@
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.api.utilities.BranchProfile;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.sl.nodes.SLExpressionNode;
 import com.oracle.truffle.sl.nodes.SLRootNode;
 import com.oracle.truffle.sl.nodes.SLStatementNode;
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Wed Dec 16 16:38:13 2015 +0100
@@ -46,9 +46,7 @@
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.nodes.UnexpectedResultException;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.api.utilities.BinaryConditionProfile;
-import com.oracle.truffle.api.utilities.ConditionProfile;
-import com.oracle.truffle.api.utilities.CountingConditionProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.sl.nodes.SLExpressionNode;
 import com.oracle.truffle.sl.nodes.SLStatementNode;
 
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLRepeatingNode.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLRepeatingNode.java	Wed Dec 16 16:38:13 2015 +0100
@@ -46,7 +46,7 @@
 import com.oracle.truffle.api.nodes.RepeatingNode;
 import com.oracle.truffle.api.nodes.UnexpectedResultException;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.api.utilities.BranchProfile;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.sl.nodes.SLExpressionNode;
 import com.oracle.truffle.sl.nodes.SLStatementNode;
 
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Wed Dec 16 12:31:17 2015 +0100
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Wed Dec 16 16:38:13 2015 +0100
@@ -41,8 +41,8 @@
 package com.oracle.truffle.sl.nodes.local;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.api.utilities.BranchProfile;
 import com.oracle.truffle.sl.nodes.SLExpressionNode;
 import com.oracle.truffle.sl.parser.SLNodeFactory;
 import com.oracle.truffle.sl.runtime.SLNull;