changeset 19815:7ee442766685

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 12 Mar 2015 16:45:24 +0100
parents 4bc9b6838303 (diff) 4bc952439f2a (current diff)
children a71b0398f8c7 52c9b1959f95
files
diffstat 12 files changed, 143 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 12 16:45:24 2015 +0100
@@ -134,9 +134,6 @@
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
 
-    @Option(help = "", type = OptionType.Debug)
-    public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
-
     // Debug settings:
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
@@ -324,13 +321,6 @@
     @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug)
     public static final OptionValue<Boolean> ImplicitStableValues = new OptionValue<>(true);
 
-
-    @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
-    public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
-
-    @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
-    public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
-
     /**
      * Counts the various paths taken through snippets.
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Mar 12 16:45:24 2015 +0100
@@ -1444,6 +1444,7 @@
     @HotSpotVMValue(expression = "SharedRuntime::dsin", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticSinAddress;
     @HotSpotVMValue(expression = "SharedRuntime::dcos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticCosAddress;
     @HotSpotVMValue(expression = "SharedRuntime::dtan", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticTanAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::dpow", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticPowAddress;
 
     @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Mar 12 16:45:24 2015 +0100
@@ -150,6 +150,7 @@
         registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION);
 
         registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Thu Mar 12 16:45:24 2015 +0100
@@ -27,10 +27,10 @@
 import static java.lang.String.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
@@ -69,8 +69,10 @@
 
     public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
         if (b.parsingReplacement()) {
-            boolean compilingSnippet = b.getRootMethod().getAnnotation(MethodSubstitution.class) == null;
-            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", b.getRootMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
+            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
+            Replacement replacement = b.getReplacement();
+            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
+                            method.format("%h.%n(%p)"));
         }
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 12 16:45:24 2015 +0100
@@ -27,6 +27,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -37,6 +38,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
@@ -51,18 +53,27 @@
         @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
         public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
 
-        @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert)
+        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
         public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
 
-        @Option(help = "Traces inlining eagerly performed during bytecode parsing", type = OptionType.Debug)
+        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
 
-        @Option(help = "Traces use of bytecode parser plugins", type = OptionType.Debug)
+        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
 
-        @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug)
+        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
 
+        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
+        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
+        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
+
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+
         // @formatter:on
     }
 
@@ -71,7 +82,7 @@
      * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation
      * is a {@link MethodSubstitution} or a snippet.
      */
-    static class ReplacementContext {
+    static class ReplacementContext implements Replacement {
         /**
          * The method being replaced.
          */
@@ -87,6 +98,18 @@
             this.replacement = substitute;
         }
 
+        public ResolvedJavaMethod getOriginalMethod() {
+            return method;
+        }
+
+        public ResolvedJavaMethod getReplacementMethod() {
+            return replacement;
+        }
+
+        public boolean isIntrinsic() {
+            return false;
+        }
+
         /**
          * Determines if a call within the compilation scope of a replacement represents a call to
          * the original method.
@@ -102,7 +125,7 @@
 
     /**
      * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a
-     * compiler intrinic must replay the intrinsified call. This context object retains the
+     * compiler intrinsic must replay the intrinsified call. This context object retains the
      * information required to build a frame state denoting the JVM state just before the
      * intrinsified call.
      */
@@ -127,6 +150,11 @@
             this.invokeBci = invokeBci;
         }
 
+        @Override
+        public boolean isIntrinsic() {
+            return true;
+        }
+
         /**
          * Gets the frame state that will restart the interpreter just before the intrinsified
          * invocation.
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Mar 12 16:45:24 2015 +0100
@@ -34,6 +34,30 @@
  */
 public interface GraphBuilderContext {
 
+    /**
+     * Information about a snippet or method substitution currently being processed by the graph
+     * builder.
+     */
+    public interface Replacement {
+
+        /**
+         * Gets the method being replaced.
+         */
+        ResolvedJavaMethod getOriginalMethod();
+
+        /**
+         * Gets the replacement method.
+         */
+        ResolvedJavaMethod getReplacementMethod();
+
+        /**
+         * Determines if this replacement is being inlined as a compiler intrinsic. A compiler
+         * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler
+         * intrinsic will restart the interpreter at the intrinsified call.
+         */
+        boolean isIntrinsic();
+    }
+
     <T extends ControlSinkNode> T append(T fixed);
 
     <T extends ControlSplitNode> T append(T fixed);
@@ -87,7 +111,15 @@
     /**
      * Determines if the current parsing context is a snippet or method substitution.
      */
-    boolean parsingReplacement();
+    default boolean parsingReplacement() {
+        return getReplacement() == null;
+    }
+
+    /**
+     * Gets the replacement of the current parsing context or {@code null} if not
+     * {@link #parsingReplacement() parsing a replacement}.
+     */
+    Replacement getReplacement();
 
     /**
      * @see GuardingPiNode#nullCheckedValue(ValueNode)
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 12 16:45:24 2015 +0100
@@ -461,7 +461,7 @@
                 for (int i = loopBegins.size() - 1; i >= 0; --i) {
                     LoopBeginNode loopBegin = loopBegins.get(i);
                     insertLoopExits(loopBegin, innerLoopsMap);
-                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                    if (DumpDuringGraphBuilding.getValue()) {
                         Debug.dump(currentGraph, "After building loop exits for %s.", loopBegin);
                     }
                 }
@@ -527,7 +527,7 @@
 
                 for (LoopBeginNode inner : innerLoopBegins) {
                     addLoopExits(loopBegin, inner, innerLoopsMap, visited);
-                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                    if (DumpDuringGraphBuilding.getValue()) {
                         Debug.dump(currentGraph, "After adding loop exits for %s.", inner);
                     }
                 }
@@ -1210,9 +1210,10 @@
                 }
                 ReplacementContext context = this.replacementContext;
                 if (context != null && context.isCallToOriginal(targetMethod)) {
+                    assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying";
                     // Self recursive replacement means the original
                     // method should be called.
-                    if (targetMethod.hasBytecodes()) {
+                    if (context.method.hasBytecodes()) {
                         parseAndInlineCallee(context.method, args, null);
                     } else {
                         return false;
@@ -1225,9 +1226,13 @@
                             context = new ReplacementContext(targetMethod, inlinedMethod);
                         }
                     }
-                    parseAndInlineCallee(inlinedMethod, args, context);
-                    if (plugin != null) {
-                        plugin.postInline(inlinedMethod);
+                    if (inlinedMethod.hasBytecodes()) {
+                        parseAndInlineCallee(inlinedMethod, args, context);
+                        if (plugin != null) {
+                            plugin.postInline(inlinedMethod);
+                        }
+                    } else {
+                        return false;
                     }
                 }
                 return true;
@@ -2350,6 +2355,10 @@
                 return parent == null ? 0 : 1 + parent.getDepth();
             }
 
+            public Replacement getReplacement() {
+                return replacementContext;
+            }
+
             public ResolvedJavaMethod getRootMethod() {
                 return rootMethod;
             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Mar 12 16:45:24 2015 +0100
@@ -77,7 +77,7 @@
             /**
              * The method to be inlined. If this is not equal to the {@code method} argument passed
              * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as
-             * a {@linkplain GraphBuilderContext#parsingReplacement() replacement}.
+             * a {@linkplain GraphBuilderContext.Replacement replacement}.
              */
             public final ResolvedJavaMethod methodToInline;
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Mar 12 16:45:24 2015 +0100
@@ -438,10 +438,11 @@
                 } else {
                     // only handle the outermost frame states
                     if (frameState.outerFrameState() == null) {
+                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
                         assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
-                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
-                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
-                                        frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+                        assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
+                        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
+                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState;
                         if (outerFrameState == null) {
                             outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind);
                         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Thu Mar 12 16:45:24 2015 +0100
@@ -51,16 +51,6 @@
     static class TestMethodsSubstitutions {
 
         @MethodSubstitution(isStatic = true)
-        static double next(double v) {
-            return TestMethods.next(v);
-        }
-
-        @MethodSubstitution(isStatic = true)
-        static double next2(double v) {
-            return next2(v);
-        }
-
-        @MethodSubstitution(isStatic = true)
         static double nextAfter(double x, double d) {
             double xx = (x == -0.0 ? 0.0 : x);
             return Math.nextAfter(xx, d);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Thu Mar 12 16:45:24 2015 +0100
@@ -57,42 +57,68 @@
         test("mathAll", value);
     }
 
-    @SuppressWarnings("all")
+    @Test
+    public void testMathPow() {
+        double a = 34567.891D;
+        double b = 4.6D;
+        test("mathPow", a, b);
+
+        // Test the values directly handled by the substitution
+
+        // If the second argument is positive or negative zero, then the result is 1.0.
+        test("mathPow", a, 0.0D);
+        test("mathPow", a, -0.0D);
+        // If the second argument is 1.0, then the result is the same as the first argument.
+        test("mathPow", a, 1.0D);
+        // If the second argument is NaN, then the result is NaN.
+        test("mathPow", a, Double.NaN);
+        // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
+        test("mathPow", Double.NaN, b);
+        test("mathPow", Double.NaN, 0.0D);
+        // x**-1 = 1/x
+        test("mathPow", a, -1.0D);
+        // x**2 = x*x
+        test("mathPow", a, 2.0D);
+        // x**0.5 = sqrt(x)
+        test("mathPow", a, 0.5D);
+    }
+
+    public static double mathPow(double a, double b) {
+        return mathPow0(a, b);
+    }
+
+    public static double mathPow0(double a, double b) {
+        return Math.pow(a, b);
+    }
+
     public static double mathAbs(double value) {
         return Math.abs(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathSqrt(double value) {
         return Math.sqrt(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathLog(double value) {
         return Math.log(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathLog10(double value) {
         return Math.log10(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathSin(double value) {
         return Math.sin(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathCos(double value) {
         return Math.cos(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathTan(double value) {
         return Math.tan(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathAll(double value) {
         return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
     }
@@ -130,22 +156,18 @@
         testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args);
     }
 
-    @SuppressWarnings("all")
     public static int integerReverseBytes(int value) {
         return Integer.reverseBytes(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerNumberOfLeadingZeros(int value) {
         return Integer.numberOfLeadingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerNumberOfTrailingZeros(int value) {
         return Integer.numberOfTrailingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerBitCount(int value) {
         return Integer.bitCount(value);
     }
@@ -160,22 +182,18 @@
         testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args);
     }
 
-    @SuppressWarnings("all")
     public static long longReverseBytes(long value) {
         return Long.reverseBytes(value);
     }
 
-    @SuppressWarnings("all")
     public static int longNumberOfLeadingZeros(long value) {
         return Long.numberOfLeadingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int longNumberOfTrailingZeros(long value) {
         return Long.numberOfTrailingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int longBitCount(long value) {
         return Long.bitCount(value);
     }
@@ -186,12 +204,10 @@
         testGraph("intBitsToFloat");
     }
 
-    @SuppressWarnings("all")
     public static int floatToIntBits(float value) {
         return Float.floatToIntBits(value);
     }
 
-    @SuppressWarnings("all")
     public static float intBitsToFloat(int value) {
         return Float.intBitsToFloat(value);
     }
@@ -202,22 +218,18 @@
         testGraph("longBitsToDouble");
     }
 
-    @SuppressWarnings("all")
     public static long doubleToLongBits(double value) {
         return Double.doubleToLongBits(value);
     }
 
-    @SuppressWarnings("all")
     public static double longBitsToDouble(long value) {
         return Double.longBitsToDouble(value);
     }
 
-    @SuppressWarnings("all")
     public static boolean isInstance(Class<?> clazz, Object object) {
         return clazz.isInstance(object);
     }
 
-    @SuppressWarnings("all")
     public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
         return clazz.isAssignableFrom(other);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Thu Mar 12 15:59:01 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Thu Mar 12 16:45:24 2015 +0100
@@ -46,12 +46,12 @@
     @MethodSubstitution(guard = MathGuard.class)
     public static double pow(double x, double y) {
         // If the second argument is positive or negative zero, then the result is 1.0.
-        if (y == 0) {
+        if (y == 0.0D) {
             return 1;
         }
 
         // If the second argument is 1.0, then the result is the same as the first argument.
-        if (y == 1) {
+        if (y == 1.0D) {
             return x;
         }
 
@@ -61,26 +61,25 @@
         }
 
         // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
-        if (Double.isNaN(x) && y != 0) {
+        if (Double.isNaN(x) && y != 0.0D) {
             return Double.NaN;
         }
 
         // x**-1 = 1/x
-        if (y == -1) {
+        if (y == -1.0D) {
             return 1 / x;
         }
 
         // x**2 = x*x
-        if (y == 2) {
+        if (y == 2.0D) {
             return x * x;
         }
 
         // x**0.5 = sqrt(x)
-        if (y == 0.5 && x >= 0) {
+        if (y == 0.5D && x >= 0.0D) {
             return Math.sqrt(x);
         }
-
-        return pow(x, y);
+        return callDouble2(ARITHMETIC_POW, x, y);
     }
 
     // NOTE on snippets below:
@@ -94,7 +93,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.SIN);
         } else {
-            return callDouble(ARITHMETIC_SIN, x);
+            return callDouble1(ARITHMETIC_SIN, x);
         }
     }
 
@@ -103,7 +102,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.COS);
         } else {
-            return callDouble(ARITHMETIC_COS, x);
+            return callDouble1(ARITHMETIC_COS, x);
         }
     }
 
@@ -112,7 +111,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.TAN);
         } else {
-            return callDouble(ARITHMETIC_TAN, x);
+            return callDouble1(ARITHMETIC_TAN, x);
         }
     }
 
@@ -127,7 +126,11 @@
     public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_POW = new ForeignCallDescriptor("arithmeticPow", double.class, double.class, double.class);
 
     @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
-    public static native double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
+    private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b);
 }