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);