Title: [97876] trunk/Source
Revision
97876
Author
[email protected]
Date
2011-10-19 14:25:10 -0700 (Wed, 19 Oct 2011)

Log Message

Support CanvasPixelArray in the DFG
https://bugs.webkit.org/show_bug.cgi?id=70384

Reviewed by Filip Pizlo.

Source/_javascript_Core:

Add support for the old CanvasPixelArray optimisations to the
DFG.  This removes the regression seen in the DFG when using
a CPA.

* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::store8):
(JSC::MacroAssemblerX86Common::truncateDoubleToInt32):
* assembler/X86Assembler.h:
(JSC::X86Assembler::movb_rm):
(JSC::X86Assembler::X86InstructionFormatter::oneByteOp8):
* bytecode/PredictedType.cpp:
(JSC::predictionToString):
(JSC::predictionFromClassInfo):
* bytecode/PredictedType.h:
(JSC::isByteArrayPrediction):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::execute):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateByteArray):
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::propagateNodePredictions):
(JSC::DFG::Propagator::fixupNode):
(JSC::DFG::Propagator::performNodeCSE):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArgumentTypes):
(JSC::DFG::compileClampDoubleToByte):
(JSC::DFG::SpeculativeJIT::compilePutByValForByteArray):
(JSC::DFG::SpeculativeJIT::compileGetByValOnByteArray):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/JSByteArray.h:
(JSC::JSByteArray::offsetOfStorage):
* wtf/ByteArray.cpp:
* wtf/ByteArray.h:
(WTF::ByteArray::offsetOfSize):
(WTF::ByteArray::offsetOfData):

Source/WebCore:

Make CanvasPixelArray inherit from ByteArray's ClassInfo so
can identify it more sensibly.

* bindings/js/JSImageDataCustom.cpp:
(WebCore::toJS):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (97875 => 97876)


--- trunk/Source/_javascript_Core/ChangeLog	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-10-19 21:25:10 UTC (rev 97876)
@@ -1,3 +1,51 @@
+2011-10-18  Oliver Hunt  <[email protected]>
+
+        Support CanvasPixelArray in the DFG
+        https://bugs.webkit.org/show_bug.cgi?id=70384
+
+        Reviewed by Filip Pizlo.
+
+        Add support for the old CanvasPixelArray optimisations to the
+        DFG.  This removes the regression seen in the DFG when using
+        a CPA.
+
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::store8):
+        (JSC::MacroAssemblerX86Common::truncateDoubleToInt32):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::movb_rm):
+        (JSC::X86Assembler::X86InstructionFormatter::oneByteOp8):
+        * bytecode/PredictedType.cpp:
+        (JSC::predictionToString):
+        (JSC::predictionFromClassInfo):
+        * bytecode/PredictedType.h:
+        (JSC::isByteArrayPrediction):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::initialize):
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateByteArray):
+        * dfg/DFGPropagator.cpp:
+        (JSC::DFG::Propagator::propagateNodePredictions):
+        (JSC::DFG::Propagator::fixupNode):
+        (JSC::DFG::Propagator::performNodeCSE):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::checkArgumentTypes):
+        (JSC::DFG::compileClampDoubleToByte):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForByteArray):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnByteArray):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * runtime/JSByteArray.h:
+        (JSC::JSByteArray::offsetOfStorage):
+        * wtf/ByteArray.cpp:
+        * wtf/ByteArray.h:
+        (WTF::ByteArray::offsetOfSize):
+        (WTF::ByteArray::offsetOfData):
+
 2011-10-18  Geoffrey Garen  <[email protected]>
 
         Some rope cleanup following r97827

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (97875 => 97876)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -527,6 +527,11 @@
         ASSERT(-128 <= imm.m_value && imm.m_value < 128);
         m_assembler.movb_i8m(imm.m_value, address.offset, address.base, address.index, address.scale);
     }
+    
+    void store8(RegisterID src, BaseIndex address)
+    {
+        m_assembler.movb_rm(src, address.offset, address.base, address.index, address.scale);
+    }
 
 
     // Floating-point operation:
@@ -691,6 +696,12 @@
         return branch32(branchType ? NotEqual : Equal, dest, TrustedImm32(0x80000000));
     }
 
+    void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+    {
+        ASSERT(isSSE2Present());
+        m_assembler.cvttsd2si_rr(src, dest);
+    }
+    
     // Convert 'src' to an integer, and places the resulting 'dest'.
     // If the result is not representable as a 32 bit value, branch.
     // May also branch for some values that are representable in 32 bits

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (97875 => 97876)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -134,6 +134,7 @@
         OP_TEST_EbGb                    = 0x84,
         OP_TEST_EvGv                    = 0x85,
         OP_XCHG_EvGv                    = 0x87,
+        OP_MOV_EbGb                     = 0x88,
         OP_MOV_EvGv                     = 0x89,
         OP_MOV_GvEv                     = 0x8B,
         OP_LEA                          = 0x8D,
@@ -1085,7 +1086,30 @@
         m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, index, scale, offset);
         m_formatter.immediate8(imm);
     }
+    
+    void movb_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
+    {
+#if CPU(X86)
+        // On 32-bit x86 we can only set the first 4 registers;
+        // esp..edi are mapped to the 'h' registers!
+        if (src >= 4) {
+            RegisterID originalSrc = src;
+            xchgl_rr(src, X86Registers::eax);
+            if (base == X86Registers::eax)
+                base = src;
+            else if (index == X86Registers::eax)
+                index = src;
+            src = ""
+            
+            m_formatter.oneByteOp8(OP_MOV_EbGb, src, base, index, scale, offset);
 
+            xchgl_rr(originalSrc, X86Registers::eax);
+            return;
+        }
+#endif
+        m_formatter.oneByteOp8(OP_MOV_EbGb, src, base, index, scale, offset);
+    }
+
     void movl_EAXm(const void* addr)
     {
         m_formatter.oneByteOp(OP_MOV_OvEAX);
@@ -1943,6 +1967,14 @@
             registerModRM(reg, rm);
         }
 
+        void oneByteOp8(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset)
+        {
+            m_buffer.ensureSpace(maxInstructionSize);
+            emitRexIf(byteRegRequiresRex(reg) || regRequiresRex(index) || regRequiresRex(base), reg, index, base);
+            m_buffer.putByteUnchecked(opcode);
+            memoryModRM(reg, base, index, scale, offset);
+        }
+
         void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm)
         {
             m_buffer.ensureSpace(maxInstructionSize);

Modified: trunk/Source/_javascript_Core/bytecode/PredictedType.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/bytecode/PredictedType.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/bytecode/PredictedType.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "PredictedType.h"
 
+#include "JSByteArray.h"
 #include "ValueProfile.h"
 #include <wtf/BoundsCheckedPointer.h>
 
@@ -66,6 +67,11 @@
     else
         isTop = false;
     
+    if (value & PredictByteArray)
+        ptr.strcat("ByteArray");
+    else
+        isTop = false;
+    
     if (value & PredictString)
         ptr.strcat("String");
     else
@@ -110,6 +116,9 @@
     
     if (classInfo == &JSString::s_info)
         return PredictString;
+
+    if (classInfo->isSubClassOf(&JSByteArray::s_info))
+        return PredictByteArray;
     
     if (classInfo->isSubClassOf(&JSObject::s_info))
         return PredictObjectOther;

Modified: trunk/Source/_javascript_Core/bytecode/PredictedType.h (97875 => 97876)


--- trunk/Source/_javascript_Core/bytecode/PredictedType.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/bytecode/PredictedType.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -39,6 +39,7 @@
 static const PredictedType PredictNone          = 0x0000; // We don't know anything yet.
 static const PredictedType PredictFinalObject   = 0x0001; // It's definitely a JSFinalObject.
 static const PredictedType PredictArray         = 0x0002; // It's definitely a JSArray.
+static const PredictedType PredictByteArray     = 0x0004; // It's definitely a JSByteArray.
 static const PredictedType PredictObjectOther   = 0x0010; // It's definitely an object but not JSFinalObject or JSArray.
 static const PredictedType PredictObjectMask    = 0x003f; // Bitmask used for testing for any kind of object prediction.
 static const PredictedType PredictString        = 0x0040; // It's definitely a JSString.
@@ -83,6 +84,11 @@
     return value == PredictArray;
 }
 
+inline bool isByteArrayPrediction(PredictedType value)
+{
+    return value == PredictByteArray;
+}
+
 inline bool isArrayOrOtherPrediction(PredictedType value)
 {
     return !!(value & (PredictArray | PredictOther)) && !(value & ~(PredictArray | PredictOther));

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -105,6 +105,8 @@
             root->valuesAtHead.argument(i).set(PredictInt32);
         else if (isArrayPrediction(prediction))
             root->valuesAtHead.argument(i).set(PredictArray);
+        else if (isByteArrayPrediction(prediction))
+            root->valuesAtHead.argument(i).set(PredictByteArray);
         else if (isBooleanPrediction(prediction))
             root->valuesAtHead.argument(i).set(PredictBoolean);
         else
@@ -181,6 +183,8 @@
             forNode(node.child1()).filter(PredictInt32);
         else if (isArrayPrediction(predictedType))
             forNode(node.child1()).filter(PredictArray);
+        else if (isByteArrayPrediction(predictedType))
+            forNode(node.child1()).filter(PredictByteArray);
         else if (isBooleanPrediction(predictedType))
             forNode(node.child1()).filter(PredictBoolean);
         
@@ -375,6 +379,12 @@
             forNode(nodeIndex).set(PredictString);
             break;
         }
+        if (m_graph[node.child1()].shouldSpeculateByteArray()) {
+            forNode(node.child1()).filter(PredictByteArray);
+            forNode(node.child2()).filter(PredictInt32);
+            forNode(nodeIndex).set(PredictInt32);
+            break;
+        }
         forNode(node.child1()).filter(PredictArray);
         forNode(node.child2()).filter(PredictInt32);
         forNode(nodeIndex).makeTop();
@@ -389,6 +399,12 @@
             forNode(nodeIndex).makeTop();
             break;
         }
+        if (m_graph[node.child1()].shouldSpeculateByteArray()) {
+            forNode(node.child1()).filter(PredictByteArray);
+            forNode(node.child2()).filter(PredictInt32);
+            forNode(node.child3()).filter(PredictNumber);
+            break;
+        }
         forNode(node.child1()).filter(PredictArray);
         forNode(node.child2()).filter(PredictInt32);
         break;
@@ -540,11 +556,16 @@
         forNode(node.child1()).filter(PredictArray);
         forNode(nodeIndex).set(PredictInt32);
         break;
-            
+
     case GetStringLength:
         forNode(node.child1()).filter(PredictString);
         forNode(nodeIndex).set(PredictInt32);
         break;
+        
+    case GetByteArrayLength:
+        forNode(node.child1()).filter(PredictByteArray);
+        forNode(nodeIndex).set(PredictInt32);
+        break;
             
     case CheckStructure:
         // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -267,6 +267,7 @@
     macro(PutByOffset, NodeMustGenerate | NodeClobbersWorld) \
     macro(GetArrayLength, NodeResultInt32) \
     macro(GetStringLength, NodeResultInt32) \
+    macro(GetByteArrayLength, NodeResultInt32) \
     macro(GetMethod, NodeResultJS | NodeMustGenerate) \
     macro(CheckMethod, NodeResultJS | NodeMustGenerate) \
     macro(GetScopeChain, NodeResultJS) \
@@ -942,6 +943,11 @@
         return isArrayPrediction(prediction());
     }
     
+    bool shouldSpeculateByteArray()
+    {
+        return !!(prediction() & PredictByteArray);
+    }
+    
     bool shouldSpeculateArrayOrOther()
     {
         return isArrayOrOtherPrediction(prediction());

Modified: trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -561,6 +561,7 @@
             
         case ValueToDouble:
         case GetArrayLength:
+        case GetByteArrayLength:
         case GetStringLength: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
@@ -734,17 +735,25 @@
         case GetById: {
             bool isArray = isArrayPrediction(m_graph[node.child1()].prediction());
             bool isString = isStringPrediction(m_graph[node.child1()].prediction());
-            if (!isArray && !isString)
-                break;
+            bool isByteArray = m_graph[node.child1()].shouldSpeculateByteArray();
             if (!isInt32Prediction(m_graph[m_compileIndex].prediction()))
                 break;
+            if (!isArray && !isString && !isByteArray)
+                break;
             if (m_codeBlock->identifier(node.identifierNumber()) != m_globalData.propertyNames->length)
                 break;
             
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
             printf("  @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength");
 #endif
-            node.op = isArray ? GetArrayLength : GetStringLength;
+            if (isArray)
+                node.op = GetArrayLength;
+            else if (isString)
+                node.op = GetStringLength;
+            else if (isByteArray)
+                node.op = GetByteArrayLength;
+            else
+                ASSERT_NOT_REACHED();
             break;
         }
             
@@ -1310,6 +1319,7 @@
         case ArithMin:
         case ArithMax:
         case ArithSqrt:
+        case GetByteArrayLength:
         case GetCallee:
         case GetStringLength:
         case StringCharAt:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -26,6 +26,7 @@
 #include "config.h"
 
 #include "DFGSpeculativeJIT.h"
+#include "JSByteArray.h"
 
 #if ENABLE(DFG_JIT)
 
@@ -383,6 +384,11 @@
             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
             speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+        } else if (isByteArrayPrediction(predictedType)) {
+            GPRTemporary temp(this);
+            m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
+            speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
+            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
         } else if (isBooleanPrediction(predictedType)) {
             GPRTemporary temp(this);
             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
@@ -398,6 +404,12 @@
             speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
             m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+        } else if (isByteArrayPrediction(predictedType)) {
+            GPRTemporary temp(this);
+            m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
+            speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
+            m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
+            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
         } // FIXME: need boolean predictions, but we currently don't have that support.
 #endif
     }
@@ -642,6 +654,122 @@
     integerResult(result.gpr(), m_compileIndex, op1.format());
 }
 
+static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
+{
+    // Unordered compare so we pick up NaN
+    static const double zero = 0;
+    static const double byteMax = 255;
+    static const double half = 0.5;
+    jit.loadDouble(&zero, scratch);
+    MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
+    jit.loadDouble(&byteMax, scratch);
+    MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
+    
+    jit.loadDouble(&half, scratch);
+    jit.addDouble(source, scratch);
+    jit.truncateDoubleToInt32(scratch, result);   
+    MacroAssembler::Jump truncatedInt = jit.jump();
+    
+    tooSmall.link(&jit);
+    jit.xorPtr(result, result);
+    MacroAssembler::Jump zeroed = jit.jump();
+    
+    tooBig.link(&jit);
+    jit.move(JITCompiler::TrustedImm32(255), result);
+    
+    truncatedInt.link(&jit);
+    zeroed.link(&jit);
+
+}
+
+void SpeculativeJIT::compilePutByValForByteArray(GPRReg base, GPRReg property, Node& node)
+{
+    NodeIndex baseIndex = node.child1();
+    NodeIndex valueIndex = node.child3();
+    
+    if (!isByteArrayPrediction(m_state.forNode(baseIndex).m_type))
+        speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+    GPRTemporary value;
+    GPRReg valueGPR;
+
+    if (at(valueIndex).isConstant()) {
+        JSValue jsValue = valueOfJSConstant(valueIndex);
+        if (!jsValue.isNumber()) {
+            terminateSpeculativeExecution();
+            noResult(m_compileIndex);
+            return;
+        }
+        double d = jsValue.asNumber();
+        d += 0.5;
+        if (!(d > 0))
+            d = 0;
+        else if (d > 255)
+            d = 255;
+        GPRTemporary scratch(this);
+        GPRReg scratchReg = scratch.gpr();
+        m_jit.move(Imm32((int)d), scratchReg);
+        value.adopt(scratch);
+        valueGPR = scratchReg;
+    } else if (!at(valueIndex).shouldNotSpeculateInteger()) {
+        SpeculateIntegerOperand valueOp(this, valueIndex);
+        GPRTemporary scratch(this);
+        GPRReg scratchReg = scratch.gpr();
+        m_jit.move(valueOp.gpr(), scratchReg);
+        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::BelowOrEqual, scratchReg, TrustedImm32(0xff));
+        MacroAssembler::Jump tooBig = m_jit.branch32(MacroAssembler::GreaterThan, scratchReg, TrustedImm32(0xff));
+        m_jit.xorPtr(scratchReg, scratchReg);
+        MacroAssembler::Jump clamped = m_jit.jump();
+        m_jit.move(TrustedImm32(255), scratchReg);
+        clamped.link(&m_jit);
+        inBounds.link(&m_jit);
+        value.adopt(scratch);
+        valueGPR = scratchReg;
+    } else {
+        SpeculateDoubleOperand valueOp(this, valueIndex);
+        GPRTemporary result(this);
+        FPRTemporary floatScratch(this);
+        FPRReg fpr = valueOp.fpr();
+        GPRReg gpr = result.gpr();
+        compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
+        value.adopt(result);
+        valueGPR = gpr;
+    }
+    ASSERT(valueGPR != property);
+    ASSERT(valueGPR != base);
+    GPRTemporary storage(this);
+    GPRReg storageReg = storage.gpr();
+    ASSERT(valueGPR != storageReg);
+    m_jit.loadPtr(MacroAssembler::Address(base, JSByteArray::offsetOfStorage()), storageReg);
+    MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(storageReg, ByteArray::offsetOfSize()));
+    m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne, ByteArray::offsetOfData()));
+    outOfBounds.link(&m_jit);
+    noResult(m_compileIndex);
+}
+
+void SpeculativeJIT::compileGetByValOnByteArray(Node& node)
+{
+    ASSERT(node.child3() == NoNode);
+    SpeculateCellOperand base(this, node.child1());
+    SpeculateStrictInt32Operand property(this, node.child2());
+    
+    GPRReg baseReg = base.gpr();
+    GPRReg propertyReg = property.gpr();
+    
+    if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
+        speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+
+    // Load the character into scratchReg
+    GPRTemporary storage(this);
+    GPRReg storageReg = storage.gpr();
+    m_jit.loadPtr(MacroAssembler::Address(baseReg, JSByteArray::offsetOfStorage()), storageReg);
+    
+    // unsigned comparison so we can filter out negative indices and indices that are too large
+    speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ByteArray::offsetOfSize())));
+
+    m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, ByteArray::offsetOfData()), storageReg);
+    integerResult(storageReg, m_compileIndex);
+}
+
 } } // namespace JSC::DFG
 
 #endif

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -449,6 +449,8 @@
     void compileGetCharCodeAt(Node&);
     void compileGetByValOnString(Node&);
     void compileValueToInt32(Node&);
+    void compileGetByValOnByteArray(Node&);
+    void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
     
     // It is acceptable to have structure be equal to scratch, so long as you're fine
     // with the structure GPR being clobbered.

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -29,6 +29,7 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "JSByteArray.h"
 #include "DFGJITCompilerInlineMethods.h"
 
 namespace JSC { namespace DFG {
@@ -747,6 +748,13 @@
                 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
             m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
             noResult(m_compileIndex);
+        } else if (isByteArrayPrediction(predictedType)) {
+            SpeculateCellOperand cell(this, node.child1());
+            GPRReg cellGPR = cell.gpr();
+            if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
+                speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+            m_jit.storePtr(cellGPR, JITCompiler::payloadFor(node.local()));
+            noResult(m_compileIndex);
         } else { // FIXME: Add BooleanPrediction handling
             JSValueOperand value(this, node.child1());
             m_jit.store32(value.payloadGPR(), JITCompiler::payloadFor(node.local()));
@@ -1318,6 +1326,13 @@
                 return;
             break;
         }
+        
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compileGetByValOnByteArray(node);
+            if (!m_compileOkay)
+                return;
+            break;            
+        }
 
         ASSERT(node.child3() == NoNode);
         SpeculateCellOperand base(this, node.child1());
@@ -1374,6 +1389,11 @@
 
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compilePutByValForByteArray(base.gpr(), property.gpr(), node);
+            break;
+        }
+
         JSValueOperand value(this, node.child3());
         GPRTemporary scratch(this);
 
@@ -1438,6 +1458,12 @@
     case PutByValAlias: {
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
+
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compilePutByValForByteArray(base.gpr(), property.gpr(), node);
+            break;
+        }
+
         JSValueOperand value(this, node.child3());
         GPRTemporary scratch(this, base);
         
@@ -1999,6 +2025,23 @@
         break;
     }
 
+    case GetByteArrayLength: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this);
+        
+        GPRReg baseGPR = base.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
+            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+        
+        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSByteArray::offsetOfStorage()), resultGPR);
+        m_jit.load32(MacroAssembler::Address(baseGPR, ByteArray::offsetOfSize()), resultGPR);
+        
+        integerResult(resultGPR, m_compileIndex);
+        break;
+    }
+
     case CheckFunction: {
         SpeculateCellOperand function(this, node.child1());
         speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, function.gpr(), JITCompiler::TrustedImmPtr(node.function())));

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "DFGSpeculativeJIT.h"
 
+#include "JSByteArray.h"
+
 #if ENABLE(DFG_JIT)
 
 namespace JSC { namespace DFG {
@@ -873,6 +875,13 @@
                 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
             m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
             noResult(m_compileIndex);
+        } else if (isByteArrayPrediction(predictedType)) {
+            SpeculateCellOperand cell(this, node.child1());
+            GPRReg cellGPR = cell.gpr();
+            if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
+                speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+            m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
+            noResult(m_compileIndex);
         } else if (isBooleanPrediction(predictedType)) {
             SpeculateBooleanOperand boolean(this, node.child1());
             m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));
@@ -1446,6 +1455,13 @@
             break;
         }
 
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compileGetByValOnByteArray(node);
+            if (!m_compileOkay)
+                return;
+            break;            
+        }
+
         ASSERT(node.child3() == NoNode);
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
@@ -1498,6 +1514,11 @@
 
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compilePutByValForByteArray(base.gpr(), property.gpr(), node);
+            break;
+        }
+
         JSValueOperand value(this, node.child3());
         GPRTemporary scratch(this);
 
@@ -1509,7 +1530,7 @@
         
         if (!m_compileOkay)
             return;
-
+        
         writeBarrier(baseReg, value.gpr(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);
 
         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
@@ -1563,6 +1584,11 @@
             
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
+        if (at(node.child1()).shouldSpeculateByteArray()) {
+            compilePutByValForByteArray(base.gpr(), property.gpr(), node);
+            break;
+        }
+
         JSValueOperand value(this, node.child3());
         GPRTemporary scratch(this);
         
@@ -2082,6 +2108,24 @@
         integerResult(resultGPR, m_compileIndex);
         break;
     }
+
+    case GetByteArrayLength: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this);
+        
+        GPRReg baseGPR = base.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
+            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
+        
+        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSByteArray::offsetOfStorage()), resultGPR);
+        m_jit.load32(MacroAssembler::Address(baseGPR, ByteArray::offsetOfSize()), resultGPR);
+
+        integerResult(resultGPR, m_compileIndex);
+        break;
+    }
+
     case CheckFunction: {
         SpeculateCellOperand function(this, node.child1());
         speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, function.gpr(), JITCompiler::TrustedImmPtr(node.function())));

Modified: trunk/Source/_javascript_Core/runtime/JSByteArray.h (97875 => 97876)


--- trunk/Source/_javascript_Core/runtime/JSByteArray.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/runtime/JSByteArray.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -110,6 +110,8 @@
         virtual ~JSByteArray();
 #endif
 
+        static size_t offsetOfStorage() { return OBJECT_OFFSETOF(JSByteArray, m_storage); }
+
     protected:
         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
 

Modified: trunk/Source/_javascript_Core/wtf/ByteArray.cpp (97875 => 97876)


--- trunk/Source/_javascript_Core/wtf/ByteArray.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/wtf/ByteArray.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -25,6 +25,7 @@
 
 #include "config.h"
 #include "ByteArray.h"
+
 #include "StdLibExtras.h"
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/wtf/ByteArray.h (97875 => 97876)


--- trunk/Source/_javascript_Core/wtf/ByteArray.h	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/_javascript_Core/wtf/ByteArray.h	2011-10-19 21:25:10 UTC (rev 97876)
@@ -30,6 +30,7 @@
 #include <wtf/PassRefPtr.h>
 #include <wtf/Platform.h>
 #include <wtf/RefCounted.h>
+#include <wtf/StdLibExtras.h>
 
 namespace WTF {
     class ByteArray : public RefCountedBase {
@@ -84,6 +85,9 @@
 
         static PassRefPtr<ByteArray> create(size_t size);
 
+        static size_t offsetOfSize() { return OBJECT_OFFSETOF(ByteArray, m_size); }
+        static size_t offsetOfData() { return OBJECT_OFFSETOF(ByteArray, m_data); }
+
     private:
         ByteArray(size_t size)
             : m_size(size)

Modified: trunk/Source/WebCore/ChangeLog (97875 => 97876)


--- trunk/Source/WebCore/ChangeLog	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/WebCore/ChangeLog	2011-10-19 21:25:10 UTC (rev 97876)
@@ -1,3 +1,16 @@
+2011-10-18  Oliver Hunt  <[email protected]>
+
+        Support CanvasPixelArray in the DFG
+        https://bugs.webkit.org/show_bug.cgi?id=70384
+
+        Reviewed by Filip Pizlo.
+
+        Make CanvasPixelArray inherit from ByteArray's ClassInfo so
+        can identify it more sensibly.
+
+        * bindings/js/JSImageDataCustom.cpp:
+        (WebCore::toJS):
+
 2011-10-19  Chang Shu  <[email protected]>
 
         [Qt] Disable fullscreen api on Qt by default

Modified: trunk/Source/WebCore/bindings/js/JSImageDataCustom.cpp (97875 => 97876)


--- trunk/Source/WebCore/bindings/js/JSImageDataCustom.cpp	2011-10-19 21:07:42 UTC (rev 97875)
+++ trunk/Source/WebCore/bindings/js/JSImageDataCustom.cpp	2011-10-19 21:25:10 UTC (rev 97876)
@@ -47,7 +47,7 @@
     
     wrapper = CREATE_DOM_WRAPPER(exec, globalObject, ImageData, imageData);
     Identifier dataName(exec, "data");
-    static const ClassInfo cpaClassInfo = { "CanvasPixelArray", &JSByteArray::Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSByteArray) };
+    static const ClassInfo cpaClassInfo = { "CanvasPixelArray", &JSByteArray::s_info, 0, 0, CREATE_METHOD_TABLE(JSByteArray) };
     Structure* cpaStructure = getCachedDOMStructure(globalObject, &cpaClassInfo);
     if (!cpaStructure)
         cpaStructure = cacheDOMStructure(globalObject, JSByteArray::createStructure(exec->globalData(), globalObject, jsNull(), &cpaClassInfo), &cpaClassInfo);
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to