DFG JIT should inline Math.abs
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Sep 2011 18:50:04 +0000 (18:50 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Sep 2011 18:50:04 +0000 (18:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68227

Source/JavaScriptCore:

Reviewed by Oliver Hunt.

This adds the ability to track intrinsic functions throughout the
host function infrastructure, so that the DFG can easily query
whether or not a call's target is intrinsic, and if so, which
intrinsic it is.

On top of this, it adds Math.abs intrinsics to DFG. Call(Math.abs)
is transformed into ValueToNumber<-ArithAbs nodes. These nodes
then get optimized using the usual tricks.

Also had to make a completely unrelated change to
DateInstanceCache.h in order to fix a preexisting alphabetical
sorting problem in JSGlobalData.h

This results in a big win in imaging-gaussian-blur: 61% faster
than before. The net win on Kraken is around 13%.

* JavaScriptCore.xcodeproj/project.pbxproj:
* create_hash_table:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::isFunctionConstant):
(JSC::DFG::Graph::valueOfFunctionConstant):
* dfg/DFGIntrinsic.h: Added.
* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::JITCodeGenerator::isFunctionConstant):
(JSC::DFG::JITCodeGenerator::valueOfFunctionConstant):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::isFunctionConstant):
(JSC::DFG::JITCompiler::valueOfFunctionConstant):
* dfg/DFGNode.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNode):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JITStubs.cpp:
(JSC::JITThunks::hostFunctionStub):
* jit/JITStubs.h:
* runtime/DateInstanceCache.h:
* runtime/Executable.cpp:
(JSC::ExecutableBase::intrinsic):
(JSC::NativeExecutable::intrinsic):
* runtime/Executable.h:
(JSC::NativeExecutable::create):
(JSC::NativeExecutable::finishCreation):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::getHostFunction):
* runtime/JSGlobalData.h:
* runtime/Lookup.cpp:
(JSC::HashTable::createTable):
(JSC::setUpStaticFunctionSlot):
* runtime/Lookup.h:
(JSC::HashEntry::initialize):
(JSC::HashEntry::intrinsic):

Source/WebCore:

Reviewed by Oliver Hunt.

Added JavaScriptCore/dfg to include path path. Changed the bindings
scripts to handle the presence of intrinsics.

* CMakeLists.txt:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHashTable):

Source/WebKit:

Reviewed by Oliver Hunt.

Added JavaScriptCore/dfg to include path path.

* CMakeLists.txt:

Source/WebKit2:

Reviewed by Oliver Hunt.

Added JavaScriptCore/dfg to include path path.

* CMakeLists.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@95310 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/create_hash_table
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGIntrinsic.h [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGPropagator.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/jit/JITStubs.h
Source/JavaScriptCore/runtime/DateInstanceCache.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/JavaScriptCore/runtime/Lookup.cpp
Source/JavaScriptCore/runtime/Lookup.h
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebKit/CMakeLists.txt
Source/WebKit/ChangeLog
Source/WebKit2/CMakeLists.txt
Source/WebKit2/ChangeLog

index f94c4d5..19c2700 100644 (file)
@@ -1,5 +1,67 @@
 2011-09-16  Filip Pizlo  <fpizlo@apple.com>
 
+        DFG JIT should inline Math.abs
+        https://bugs.webkit.org/show_bug.cgi?id=68227
+
+        Reviewed by Oliver Hunt.
+        
+        This adds the ability to track intrinsic functions throughout the
+        host function infrastructure, so that the DFG can easily query
+        whether or not a call's target is intrinsic, and if so, which
+        intrinsic it is.
+        
+        On top of this, it adds Math.abs intrinsics to DFG. Call(Math.abs)
+        is transformed into ValueToNumber<-ArithAbs nodes. These nodes
+        then get optimized using the usual tricks.
+        
+        Also had to make a completely unrelated change to
+        DateInstanceCache.h in order to fix a preexisting alphabetical
+        sorting problem in JSGlobalData.h
+        
+        This results in a big win in imaging-gaussian-blur: 61% faster
+        than before. The net win on Kraken is around 13%.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * create_hash_table:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::isFunctionConstant):
+        (JSC::DFG::Graph::valueOfFunctionConstant):
+        * dfg/DFGIntrinsic.h: Added.
+        * dfg/DFGJITCodeGenerator.h:
+        (JSC::DFG::JITCodeGenerator::isFunctionConstant):
+        (JSC::DFG::JITCodeGenerator::valueOfFunctionConstant):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::isFunctionConstant):
+        (JSC::DFG::JITCompiler::valueOfFunctionConstant):
+        * dfg/DFGNode.h:
+        * dfg/DFGPropagator.cpp:
+        (JSC::DFG::Propagator::propagateNode):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::hostFunctionStub):
+        * jit/JITStubs.h:
+        * runtime/DateInstanceCache.h:
+        * runtime/Executable.cpp:
+        (JSC::ExecutableBase::intrinsic):
+        (JSC::NativeExecutable::intrinsic):
+        * runtime/Executable.h:
+        (JSC::NativeExecutable::create):
+        (JSC::NativeExecutable::finishCreation):
+        * runtime/JSGlobalData.cpp:
+        (JSC::JSGlobalData::getHostFunction):
+        * runtime/JSGlobalData.h:
+        * runtime/Lookup.cpp:
+        (JSC::HashTable::createTable):
+        (JSC::setUpStaticFunctionSlot):
+        * runtime/Lookup.h:
+        (JSC::HashEntry::initialize):
+        (JSC::HashEntry::intrinsic):
+
+2011-09-16  Filip Pizlo  <fpizlo@apple.com>
+
         REGRESSION: Reproducible crash below SlotVisitor::harvestWeakReferences
         using Domino's online ordering
         https://bugs.webkit.org/show_bug.cgi?id=68220
index cc201e8..e990ae8 100644 (file)
@@ -73,6 +73,7 @@
                0FD82E85141F3FE300179C94 /* BoundsCheckedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E82141F3FC900179C94 /* BoundsCheckedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD82E86141F3FF100179C94 /* PredictedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* PredictedType.cpp */; };
                0FD82E9014207A5F00179C94 /* ValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E8E14207A5100179C94 /* ValueProfile.cpp */; };
+               0FD82EF51423075B00179C94 /* DFGIntrinsic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82EF31423073900179C94 /* DFGIntrinsic.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1400067712A6F7830064D123 /* OSAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400067612A6F7830064D123 /* OSAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1400069312A6F9E10064D123 /* OSAllocatorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */; };
                140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; };
                0FD82E82141F3FC900179C94 /* BoundsCheckedPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoundsCheckedPointer.h; sourceTree = "<group>"; };
                0FD82E84141F3FDA00179C94 /* PredictedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PredictedType.cpp; sourceTree = "<group>"; };
                0FD82E8E14207A5100179C94 /* ValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ValueProfile.cpp; sourceTree = "<group>"; };
+               0FD82EF31423073900179C94 /* DFGIntrinsic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGIntrinsic.h; path = dfg/DFGIntrinsic.h; sourceTree = "<group>"; };
                1400067612A6F7830064D123 /* OSAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSAllocator.h; sourceTree = "<group>"; };
                1400069212A6F9E10064D123 /* OSAllocatorPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OSAllocatorPosix.cpp; sourceTree = "<group>"; };
                140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBasePrivate.h; sourceTree = "<group>"; };
                86EC9DB31328DF44002B2AD7 /* dfg */ = {
                        isa = PBXGroup;
                        children = (
+                               0FD82EF31423073900179C94 /* DFGIntrinsic.h */,
                                0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */,
                                0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */,
                                0FD82E1E14172C2F00179C94 /* DFGCapabilities.cpp */,
                                BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */,
                                86D3B2C410156BDE002865E7 /* ARMAssembler.h in Headers */,
                                86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
+                               0FD82EF51423075B00179C94 /* DFGIntrinsic.h in Headers */,
                                0FD82E85141F3FE300179C94 /* BoundsCheckedPointer.h in Headers */,
                                0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */,
                                0FD82E55141DAEEE00179C94 /* PredictionTracker.h in Headers */,
index 1397f7e..3bb9cc2 100755 (executable)
@@ -252,6 +252,11 @@ sub output() {
     print "#else\n";
     print "#define THUNK_GENERATOR(generator)\n";
     print "#endif\n";
+    print "#if ENABLE(DFG_JIT)\n";
+    print "#define INTRINSIC(intrinsic) , intrinsic\n";
+    print "#else\n";
+    print "#define INTRINSIC(intrinsic)\n";
+    print "#endif\n";
     print "\nstatic const struct HashTableValue ${nameEntries}\[$count\] = {\n";
     my $i = 0;
     foreach my $key (@keys) {
@@ -272,6 +277,7 @@ sub output() {
             $secondValue = "0";
         }
         my $thunkGenerator = "0";
+        my $intrinsic = "DFG::NoIntrinsic";
         if ($key eq "charCodeAt") {
             $thunkGenerator = "charCodeAtThunkGenerator";
         }
@@ -290,6 +296,7 @@ sub output() {
             }
             if ($key eq "abs") {
                 $thunkGenerator = "absThunkGenerator";
+                $intrinsic = "DFG::AbsIntrinsic";
             }
             if ($key eq "floor") {
                 $thunkGenerator = "floorThunkGenerator";
@@ -307,10 +314,10 @@ sub output() {
                 $thunkGenerator = "logThunkGenerator";
             }
         }
-        print "   { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue THUNK_GENERATOR($thunkGenerator) },\n";
+        print "   { \"$key\", $attrs[$i], (intptr_t)" . $castStr . "($firstValue), (intptr_t)$secondValue THUNK_GENERATOR($thunkGenerator) INTRINSIC($intrinsic) },\n";
         $i++;
     }
-    print "   { 0, 0, 0, 0 THUNK_GENERATOR(0) }\n";
+    print "   { 0, 0, 0, 0 THUNK_GENERATOR(0) INTRINSIC(DFG::NoIntrinsic) }\n";
     print "};\n\n";
     print "#undef THUNK_GENERATOR\n";
     print "extern JSC_CONST_HASHTABLE HashTable $name =\n";
index 76d1fdc..280c9dc 100644 (file)
@@ -32,6 +32,7 @@
 #include "DFGCapabilities.h"
 #include "DFGScoreBoard.h"
 #include "CodeBlock.h"
+#include <wtf/MathExtras.h>
 
 namespace JSC { namespace DFG {
 
@@ -49,6 +50,7 @@ public:
         , m_parseFailed(false)
         , m_constantUndefined(UINT_MAX)
         , m_constantNull(UINT_MAX)
+        , m_constantNaN(UINT_MAX)
         , m_constant1(UINT_MAX)
         , m_constants(codeBlock->numberOfConstantRegisters())
         , m_numArguments(codeBlock->m_numParameters)
@@ -64,6 +66,8 @@ public:
     bool parse();
 
 private:
+    // Handle intrinsic functions.
+    bool handleIntrinsic(bool usesResult, int resultOperand, Intrinsic, int firstArg, int lastArg);
     // Parse a single basic block of bytecode instructions.
     bool parseBlock(unsigned limit);
     // Setup predecessor links in the graph's BasicBlocks.
@@ -356,6 +360,34 @@ private:
         return getJSConstant(m_constant1);
     }
     
+    // This method returns a DoubleConstant with the value NaN.
+    NodeIndex constantNaN()
+    {
+        JSValue nan = jsNaN();
+        
+        // Has m_constantNaN been set up yet?
+        if (m_constantNaN == UINT_MAX) {
+            // Search the constant pool for the value NaN, if we find it, we can just reuse this!
+            unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters();
+            for (m_constantNaN = 0; m_constantNaN < numberOfConstants; ++m_constantNaN) {
+                JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN);
+                if (JSValue::encode(testMe) == JSValue::encode(nan))
+                    return getJSConstant(m_constantNaN);
+            }
+
+            // Add the value nan to the CodeBlock's constants, and add a corresponding slot in m_constants.
+            ASSERT(m_constants.size() == numberOfConstants);
+            m_codeBlock->addConstant(nan);
+            m_constants.append(ConstantRecord());
+            ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters());
+        }
+
+        // m_constantNaN must refer to an entry in the CodeBlock's constant pool that has the value nan.
+        ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).isDouble());
+        ASSERT(isnan(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).asDouble()));
+        return getJSConstant(m_constantNaN);
+    }
+    
     CodeOrigin currentCodeOrigin()
     {
         return CodeOrigin(m_currentIndex);
@@ -506,6 +538,7 @@ private:
     // constant pool, as necessary.
     unsigned m_constantUndefined;
     unsigned m_constantNull;
+    unsigned m_constantNaN;
     unsigned m_constant1;
 
     // A constant in the constant pool may be represented by more than one
@@ -569,6 +602,32 @@ private:
     m_currentIndex += OPCODE_LENGTH(name); \
     return !m_parseFailed
 
+bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrinsic intrinsic, int firstArg, int lastArg)
+{
+    switch (intrinsic) {
+    case AbsIntrinsic: {
+        if (!usesResult) {
+            // There is no such thing as executing abs for effect, so this
+            // is dead code.
+            return true;
+        }
+        
+        // We don't care about the this argument. If we don't have a first
+        // argument then make this JSConstant(NaN).
+        int absArg = firstArg + 1;
+        if (absArg > lastArg)
+            set(resultOperand, constantNaN());
+        else
+            set(resultOperand, addToGraph(ArithAbs, getToNumber(absArg)));
+        return true;
+    }
+        
+    default:
+        ASSERT(intrinsic == NoIntrinsic);
+        return false;
+    }
+}
+
 bool ByteCodeParser::parseBlock(unsigned limit)
 {
     // No need to reset state initially, since it has been set by the constructor.
@@ -1169,6 +1228,30 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             LAST_OPCODE(op_end);
             
         case op_call: {
+            NodeIndex callTarget = get(currentInstruction[1].u.operand);
+            if (m_graph.isFunctionConstant(m_codeBlock, *m_globalData, callTarget)) {
+                int argCount = currentInstruction[2].u.operand;
+                int registerOffset = currentInstruction[3].u.operand;
+                int firstArg = registerOffset - argCount - RegisterFile::CallFrameHeaderSize;
+                int lastArg = firstArg + argCount - 1;
+                
+                // Do we have a result?
+                bool usesResult = false;
+                int resultOperand = 0; // make compiler happy
+                Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call);
+                if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
+                    resultOperand = putInstruction[1].u.operand;
+                    usesResult = true;
+                }
+                
+                DFG::Intrinsic intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, *m_globalData, callTarget)->executable()->intrinsic();
+                
+                if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg)) {
+                    // NEXT_OPCODE() has to be inside braces.
+                    NEXT_OPCODE(op_call);
+                }
+            }
+            
             NodeIndex call = addCall(interpreter, currentInstruction, Call);
             aliases.recordCall(call);
             NEXT_OPCODE(op_call);
index e6125fc..d4a7ed1 100644 (file)
@@ -238,6 +238,14 @@ public:
     {
         return at(nodeIndex).isBooleanConstant(codeBlock);
     }
+    bool isFunctionConstant(CodeBlock* codeBlock, JSGlobalData& globalData, NodeIndex nodeIndex)
+    {
+        if (!isJSConstant(nodeIndex))
+            return false;
+        if (!getJSFunction(globalData, valueOfJSConstant(codeBlock, nodeIndex)))
+            return false;
+        return true;
+    }
     // Helper methods get constant values from nodes.
     JSValue valueOfJSConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     {
@@ -257,6 +265,12 @@ public:
     {
         return valueOfJSConstantNode(codeBlock, nodeIndex).getBoolean();
     }
+    JSFunction* valueOfFunctionConstant(CodeBlock* codeBlock, JSGlobalData& globalData, NodeIndex nodeIndex)
+    {
+        JSCell* function = getJSFunction(globalData, valueOfJSConstant(codeBlock, nodeIndex));
+        ASSERT(function);
+        return asFunction(function);
+    }
 
 #ifndef NDEBUG
     static const char *opName(NodeType);
diff --git a/Source/JavaScriptCore/dfg/DFGIntrinsic.h b/Source/JavaScriptCore/dfg/DFGIntrinsic.h
new file mode 100644 (file)
index 0000000..e18c50e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGIntrinsic_h
+#define DFGIntrinsic_h
+
+namespace JSC { namespace DFG {
+
+enum Intrinsic {
+    NoIntrinsic,
+    AbsIntrinsic
+};
+
+} } // namespace JSC::DFG
+
+#endif // DFGIntrinsic_h
index 98ed35f..0de271b 100644 (file)
@@ -426,10 +426,12 @@ protected:
     bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
     bool isNumberConstant(NodeIndex nodeIndex) { return m_jit.isNumberConstant(nodeIndex); }
     bool isBooleanConstant(NodeIndex nodeIndex) { return m_jit.isBooleanConstant(nodeIndex); }
+    bool isFunctionConstant(NodeIndex nodeIndex) { return m_jit.isFunctionConstant(nodeIndex); }
     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
     double valueOfNumberConstant(NodeIndex nodeIndex) { return m_jit.valueOfNumberConstant(nodeIndex); }
     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
     bool valueOfBooleanConstant(NodeIndex nodeIndex) { return m_jit.valueOfBooleanConstant(nodeIndex); }
+    JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return m_jit.valueOfFunctionConstant(nodeIndex); }
     bool isNullConstant(NodeIndex nodeIndex)
     {
         if (!isConstant(nodeIndex))
index b00a56a..716be4b 100644 (file)
@@ -251,11 +251,13 @@ public:
     bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); }
     bool isNumberConstant(NodeIndex nodeIndex) { return graph().isNumberConstant(codeBlock(), nodeIndex); }
     bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); }
+    bool isFunctionConstant(NodeIndex nodeIndex) { return graph().isFunctionConstant(codeBlock(), *globalData(), nodeIndex); }
     // Helper methods get constant values from nodes.
     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); }
     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); }
     double valueOfNumberConstant(NodeIndex nodeIndex) { return graph().valueOfNumberConstant(codeBlock(), nodeIndex); }
     bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); }
+    JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return graph().valueOfFunctionConstant(codeBlock(), *globalData(), nodeIndex); }
 
     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
 #if ENABLE(DFG_JIT_ASSERT)
index af40bc6..730c96a 100644 (file)
@@ -151,6 +151,7 @@ private:
     macro(ArithMul, NodeResultNumber) \
     macro(ArithDiv, NodeResultNumber) \
     macro(ArithMod, NodeResultNumber) \
+    macro(ArithAbs, NodeResultNumber) \
     /* Arithmetic operators call ToNumber on their operands. */\
     macro(ValueToNumber, NodeResultNumber | NodeMustGenerate) \
     \
index 6bd83ad..15eecf0 100644 (file)
@@ -215,6 +215,13 @@ private:
             break;
         }
             
+        case ArithAbs: {
+            PredictedType child = m_predictions[node.child1()];
+            if (isStrongPrediction(child))
+                changed |= mergePrediction(child);
+            break;
+        }
+            
         case LogicalNot:
         case CompareLess:
         case CompareLessEq:
index 87eba31..f7e19fb 100644 (file)
@@ -1057,6 +1057,32 @@ void SpeculativeJIT::compile(Node& node)
         integerResult(edx.gpr(), m_compileIndex);
         break;
     }
+        
+    case ArithAbs: {
+        if (shouldSpeculateInteger(node.child1())) {
+            SpeculateIntegerOperand op1(this, node.child1());
+            GPRTemporary result(this, op1);
+            GPRTemporary scratch(this);
+            
+            m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());
+            m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());
+            m_jit.add32(scratch.gpr(), result.gpr());
+            m_jit.xor32(scratch.gpr(), result.gpr());
+            speculationCheck(m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));
+            integerResult(result.gpr(), m_compileIndex);
+            break;
+        }
+        
+        SpeculateDoubleOperand op1(this, node.child1());
+        FPRTemporary result(this);
+        
+        static const double negativeZeroConstant = -0.0;
+        
+        m_jit.loadDouble(&negativeZeroConstant, result.fpr());
+        m_jit.andnotDouble(op1.fpr(), result.fpr());
+        doubleResult(result.fpr(), m_compileIndex);
+        break;
+    }
 
     case LogicalNot: {
         if (isKnownBoolean(node.child1())) {
index c09e346..44b1fc8 100644 (file)
@@ -3686,16 +3686,16 @@ NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFu
 {
     std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
     if (!*entry.first->second)
-        entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, function), function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor));
+        entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, function), function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, DFG::NoIntrinsic));
     return entry.first->second.get();
 }
 
-NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator)
+NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator, DFG::Intrinsic intrinsic)
 {
     std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
     if (!*entry.first->second) {
         MacroAssemblerCodeRef code = globalData->canUseJIT() ? generator(globalData) : MacroAssemblerCodeRef();
-        entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor));
+        entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, intrinsic));
     }
     return entry.first->second.get();
 }
index e8a73c3..b1f5576 100644 (file)
@@ -31,6 +31,7 @@
 #define JITStubs_h
 
 #include "CallData.h"
+#include "DFGIntrinsic.h"
 #include "MacroAssemblerCodeRef.h"
 #include "Register.h"
 #include "ThunkGenerators.h"
@@ -297,7 +298,7 @@ namespace JSC {
         MacroAssemblerCodeRef ctiStub(JSGlobalData*, ThunkGenerator);
 
         NativeExecutable* hostFunctionStub(JSGlobalData*, NativeFunction);
-        NativeExecutable* hostFunctionStub(JSGlobalData*, NativeFunction, ThunkGenerator);
+        NativeExecutable* hostFunctionStub(JSGlobalData*, NativeFunction, ThunkGenerator, DFG::Intrinsic);
 
         void clearHostFunctionStubs();
 
index 0d89eb8..cdd12cf 100644 (file)
@@ -27,6 +27,7 @@
 #define DateInstanceCache_h
 
 #include <wtf/DateMath.h>
+#include <wtf/FixedArray.h>
 #include <wtf/HashFunctions.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
index d136624..af4d2c9 100644 (file)
@@ -50,6 +50,13 @@ void ExecutableBase::clearCode()
     m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
 }
 
+#if ENABLE(DFG_JIT)
+DFG::Intrinsic ExecutableBase::intrinsic() const
+{
+    return DFG::NoIntrinsic;
+}
+#endif
+
 class ExecutableFinalizer : public WeakHandleOwner {
     virtual void finalize(Handle<Unknown> handle, void*)
     {
@@ -70,6 +77,13 @@ NativeExecutable::~NativeExecutable()
 {
 }
 
+#if ENABLE(DFG_JIT)
+DFG::Intrinsic NativeExecutable::intrinsic() const
+{
+    return m_intrinsic;
+}
+#endif
+
 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0 };
 
 const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 };
index 71395fe..eb08f3f 100644 (file)
@@ -156,6 +156,10 @@ namespace JSC {
             return hasJITCodeForConstruct();
         }
 
+#if ENABLE(DFG_JIT)
+        virtual DFG::Intrinsic intrinsic() const;
+#endif
+
     protected:
         JITCode m_jitCodeForCall;
         JITCode m_jitCodeForConstruct;
@@ -173,15 +177,15 @@ namespace JSC {
         typedef ExecutableBase Base;
 
 #if ENABLE(JIT)
-        static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor)
+        static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, DFG::Intrinsic intrinsic)
         {
             NativeExecutable* executable;
             if (!callThunk) {
                 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
-                executable->finishCreation(globalData, JITCode(), JITCode());
+                executable->finishCreation(globalData, JITCode(), JITCode(), intrinsic);
             } else {
                 executable = new (allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
-                executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk));
+                executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
             }
             return executable;
         }
@@ -204,15 +208,22 @@ namespace JSC {
 
     protected:
 #if ENABLE(JIT)
-        void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk)
+        void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk, DFG::Intrinsic intrinsic)
         {
             Base::finishCreation(globalData);
             m_jitCodeForCall = callThunk;
             m_jitCodeForConstruct = constructThunk;
             m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
             m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
+#if ENABLE(DFG_JIT)
+            m_intrinsic = intrinsic;
+#endif
         }
 #endif
+        
+#if ENABLE(DFG_JIT)
+        virtual DFG::Intrinsic intrinsic() const;
+#endif
  
     private:
 #if ENABLE(JIT)
@@ -235,6 +246,8 @@ namespace JSC {
         // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
         // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
         NativeFunction m_constructor;
+        
+        DFG::Intrinsic m_intrinsic;
     };
 
     class ScriptExecutable : public ExecutableBase {
index f1969e7..97fd9d8 100644 (file)
@@ -410,9 +410,9 @@ NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
 {
     return jitStubs->hostFunctionStub(this, function);
 }
-NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator)
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, ThunkGenerator generator, DFG::Intrinsic intrinsic)
 {
-    return jitStubs->hostFunctionStub(this, function, generator);
+    return jitStubs->hostFunctionStub(this, function, generator, intrinsic);
 }
 #else
 NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function)
index 0bf1c33..2ea99a2 100644 (file)
 #define JSGlobalData_h
 
 #include "CachedTranscendentalFunction.h"
-#include "Heap.h"
+#include "DFGIntrinsic.h"
 #include "DateInstanceCache.h"
 #include "ExecutableAllocator.h"
+#include "Heap.h"
 #include "Strong.h"
 #include "JITStubs.h"
 #include "JSValue.h"
@@ -219,7 +220,7 @@ namespace JSC {
         {
             return jitStubs->ctiStub(this, generator);
         }
-        NativeExecutable* getHostFunction(NativeFunction, ThunkGenerator);
+        NativeExecutable* getHostFunction(NativeFunction, ThunkGenerator, DFG::Intrinsic);
 #endif
         NativeExecutable* getHostFunction(NativeFunction);
 
index 80edbdd..209bbad 100644 (file)
@@ -49,6 +49,9 @@ void HashTable::createTable(JSGlobalData* globalData) const
         entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2
 #if ENABLE(JIT)
                           , values[i].generator
+#if ENABLE(DFG_JIT)
+                          , values[i].intrinsic
+#endif
 #endif
                           );
     }
@@ -79,7 +82,7 @@ void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject*
         JSGlobalObject* globalObject = thisObj->globalObject();
 #if ENABLE(JIT)
         if (entry->generator())
-            function = JSFunction::create(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator()));
+            function = JSFunction::create(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->generator(), entry->intrinsic()));
         else
 #endif
             function = JSFunction::create(exec, globalObject, globalObject->functionStructure(), entry->functionLength(), propertyName, entry->function());
index c0013d6..5adba51 100644 (file)
@@ -22,6 +22,7 @@
 #define Lookup_h
 
 #include "CallFrame.h"
+#include "DFGIntrinsic.h"
 #include "Identifier.h"
 #include "JSGlobalObject.h"
 #include "PropertySlot.h"
@@ -44,6 +45,9 @@ namespace JSC {
         intptr_t value2;
 #if ENABLE(JIT)
         ThunkGenerator generator;
+#if ENABLE(DFG_JIT)
+        DFG::Intrinsic intrinsic;
+#endif
 #endif
     };
 
@@ -58,6 +62,9 @@ namespace JSC {
         void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
 #if ENABLE(JIT)
                         , ThunkGenerator generator = 0
+#if ENABLE(DFG_JIT)
+                        , DFG::Intrinsic intrinsic = DFG::NoIntrinsic
+#endif
 #endif
                         )
         {
@@ -67,6 +74,9 @@ namespace JSC {
             m_u.store.value2 = v2;
 #if ENABLE(JIT)
             m_u.function.generator = generator;
+#if ENABLE(DFG_JIT)
+            m_u.function.intrinsic = intrinsic;
+#endif
 #endif
             m_next = 0;
         }
@@ -78,6 +88,15 @@ namespace JSC {
 
 #if ENABLE(JIT)
         ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
+        DFG::Intrinsic intrinsic() const
+        {
+            ASSERT(m_attributes & Function);
+#if ENABLE(DFG_JIT)
+            return m_u.function.intrinsic;
+#else
+            return DFG::NoIntrinsic;
+#endif
+        }
 #endif
         NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
         unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
@@ -104,6 +123,9 @@ namespace JSC {
                 intptr_t length; // number of arguments for function
 #if ENABLE(JIT)
                 ThunkGenerator generator;
+#if ENABLE(DFG_JIT)
+                DFG::Intrinsic intrinsic;
+#endif
 #endif
             } function;
             struct {
index ae2fb83..a41d260 100644 (file)
@@ -69,6 +69,7 @@ SET(WebCore_INCLUDE_DIRECTORIES
     "${JAVASCRIPTCORE_DIR}/assembler"
     "${JAVASCRIPTCORE_DIR}/bytecode"
     "${JAVASCRIPTCORE_DIR}/bytecompiler"
+    "${JAVASCRIPTCORE_DIR}/dfg"
     "${JAVASCRIPTCORE_DIR}/heap"
     "${JAVASCRIPTCORE_DIR}/debugger"
     "${JAVASCRIPTCORE_DIR}/interpreter"
index 333ebae..aecd332 100644 (file)
@@ -1,3 +1,17 @@
+2011-09-16  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG JIT should inline Math.abs
+        https://bugs.webkit.org/show_bug.cgi?id=68227
+
+        Reviewed by Oliver Hunt.
+
+        Added JavaScriptCore/dfg to include path path. Changed the bindings
+        scripts to handle the presence of intrinsics.
+
+        * CMakeLists.txt:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHashTable):
+
 2011-09-16  Iain Merrick  <husky@google.com>
 
         [chromium] Fix CCLayerTreeHostTest
index a1cb026..09528d5 100644 (file)
@@ -2936,6 +2936,11 @@ sub GenerateHashTable
     push(@implContent, "#else\n");
     push(@implContent, "#define THUNK_GENERATOR(generator)\n");
     push(@implContent, "#endif\n");
+    push(@implContent, "#if ENABLE(DFG_JIT)\n");
+    push(@implContent, "#define INTRINSIC(intrinsic) , intrinsic\n");
+    push(@implContent, "#else\n");
+    push(@implContent, "#define INTRINSIC(intrinsic)\n");
+    push(@implContent, "#endif\n");
     push(@implContent, "\nstatic const HashTableValue $nameEntries\[\] =\n\{\n");
     $i = 0;
     foreach my $key (@{$keys}) {
@@ -2955,13 +2960,13 @@ sub GenerateHashTable
         } else {
             $targetType = "static_cast<PropertySlot::GetValueFunc>";
         }
-        push(@implContent, "    { \"$key\", @$specials[$i], (intptr_t)" . $targetType . "(@$value1[$i]), (intptr_t)@$value2[$i] THUNK_GENERATOR(0) },\n");
+        push(@implContent, "    { \"$key\", @$specials[$i], (intptr_t)" . $targetType . "(@$value1[$i]), (intptr_t)@$value2[$i] THUNK_GENERATOR(0) INTRINSIC(DFG::NoIntrinsic) },\n");
         if ($conditional) {
             push(@implContent, "#endif\n");
         }
         ++$i;
     }
-    push(@implContent, "    { 0, 0, 0, 0 THUNK_GENERATOR(0) }\n");
+    push(@implContent, "    { 0, 0, 0, 0 THUNK_GENERATOR(0) INTRINSIC(DFG::NoIntrinsic) }\n");
     push(@implContent, "};\n\n");
     push(@implContent, "#undef THUNK_GENERATOR\n");
     my $compactSizeMask = $numEntries - 1;
index b65d1bd..24566c4 100644 (file)
@@ -37,6 +37,7 @@ SET(WebKit_INCLUDE_DIRECTORIES
     "${JAVASCRIPTCORE_DIR}/assembler"
     "${JAVASCRIPTCORE_DIR}/bytecode"
     "${JAVASCRIPTCORE_DIR}/bytecompiler"
+    "${JAVASCRIPTCORE_DIR}/dfg"
     "${JAVASCRIPTCORE_DIR}/heap"
     "${JAVASCRIPTCORE_DIR}/debugger"
     "${JAVASCRIPTCORE_DIR}/interpreter"
index 78428c8..637eef5 100644 (file)
@@ -1,3 +1,14 @@
+2011-09-16  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG JIT should inline Math.abs
+        https://bugs.webkit.org/show_bug.cgi?id=68227
+
+        Reviewed by Oliver Hunt.
+
+        Added JavaScriptCore/dfg to include path path.
+
+        * CMakeLists.txt:
+
 2011-09-14  Anders Carlsson  <andersca@apple.com>
 
         Get rid of WebCoreViewFactory and its WebViewFactory subclass
index f670c2f..dcbf796 100644 (file)
@@ -75,6 +75,7 @@ SET(WebKit2_INCLUDE_DIRECTORIES
     "${JAVASCRIPTCORE_DIR}/assembler"
     "${JAVASCRIPTCORE_DIR}/bytecode"
     "${JAVASCRIPTCORE_DIR}/bytecompiler"
+    "${JAVASCRIPTCORE_DIR}/dfg"
     "${JAVASCRIPTCORE_DIR}/collector/handles"
     "${JAVASCRIPTCORE_DIR}/heap"
     "${JAVASCRIPTCORE_DIR}/interpreter"
index 735620b..f114b10 100644 (file)
@@ -1,3 +1,14 @@
+2011-09-16  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG JIT should inline Math.abs
+        https://bugs.webkit.org/show_bug.cgi?id=68227
+
+        Reviewed by Oliver Hunt.
+
+        Added JavaScriptCore/dfg to include path path.
+
+        * CMakeLists.txt:
+
 2011-09-16  Igor Oliveira  <igor.oliveira@openbossa.org>
 
         [WK2] mouseDidMoveOverElement needs to send more information about hovered element to UiProcess.