Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (96188 => 96189)
--- trunk/Source/_javascript_Core/ChangeLog 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-09-28 05:33:21 UTC (rev 96189)
@@ -1,5 +1,42 @@
2011-09-27 Filip Pizlo <fpi...@apple.com>
+ DFG JIT cannot compile op_new_object, op_new_array,
+ op_new_array_buffer, or op_new_regexp
+ https://bugs.webkit.org/show_bug.cgi?id=68580
+
+ Reviewed by Oliver Hunt.
+
+ This implements all four opcodes, but has op_new_regexp turns off
+ by default because it unveils some bad speculation logic when
+ compiling string-validate-input.
+
+ With op_new_regexp turned off, this is a 5% win on Kraken and a
+ 0.7% speed-up on V8. Neutral on SunSpider.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::canCompileOpcode):
+ * dfg/DFGJITCodeGenerator.h:
+ (JSC::DFG::callOperation):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasConstantBuffer):
+ (JSC::DFG::Node::startConstant):
+ (JSC::DFG::Node::numConstants):
+ (JSC::DFG::Node::hasRegexpIndex):
+ (JSC::DFG::Node::regexpIndex):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPropagator.cpp:
+ (JSC::DFG::Propagator::propagateNodePredictions):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::isKnownArray):
+
+2011-09-27 Filip Pizlo <fpi...@apple.com>
+
DFG JIT should speculate more aggressively on reads of array.length
https://bugs.webkit.org/show_bug.cgi?id=68932
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2011-09-28 05:33:21 UTC (rev 96189)
@@ -724,6 +724,32 @@
NEXT_OPCODE(op_create_this);
}
+ case op_new_object: {
+ set(currentInstruction[1].u.operand, addToGraph(NewObject));
+ NEXT_OPCODE(op_new_object);
+ }
+
+ case op_new_array: {
+ int startOperand = currentInstruction[2].u.operand;
+ int numOperands = currentInstruction[3].u.operand;
+ for (int operandIdx = startOperand; operandIdx < startOperand + numOperands; ++operandIdx)
+ addVarArgChild(get(operandIdx));
+ set(currentInstruction[1].u.operand, addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
+ NEXT_OPCODE(op_new_array);
+ }
+
+ case op_new_array_buffer: {
+ int startConstant = currentInstruction[2].u.operand;
+ int numConstants = currentInstruction[3].u.operand;
+ set(currentInstruction[1].u.operand, addToGraph(NewArrayBuffer, OpInfo(startConstant), OpInfo(numConstants)));
+ NEXT_OPCODE(op_new_array_buffer);
+ }
+
+ case op_new_regexp: {
+ set(currentInstruction[1].u.operand, addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand)));
+ NEXT_OPCODE(op_new_regexp);
+ }
+
case op_get_callee: {
set(currentInstruction[1].u.operand, addToGraph(GetCallee));
NEXT_OPCODE(op_get_callee);
@@ -1401,8 +1427,9 @@
}
default:
- // Parse failed!
- ASSERT(!canCompileOpcode(opcodeID));
+ // Parse failed! This should not happen because the capabilities checker
+ // should have caught it.
+ ASSERT_NOT_REACHED();
return false;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.h (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.h 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.h 2011-09-28 05:33:21 UTC (rev 96189)
@@ -31,6 +31,8 @@
namespace JSC { namespace DFG {
+#define ENABLE_DFG_RESTRICTIONS 1
+
#if ENABLE(DFG_JIT)
// Fast check functions; if they return true it is still necessary to
// check opcodes.
@@ -119,11 +121,28 @@
case op_resolve:
case op_resolve_base:
case op_resolve_global:
+ case op_new_object:
+ case op_new_array:
+ case op_new_array_buffer:
case op_strcat:
case op_to_primitive:
case op_throw:
case op_throw_reference_error:
return true;
+
+ // Opcodes we support conditionally. Enabling these opcodes currently results in
+ // performance regressions. Each node that we disable under restrictions has a
+ // comment describing what we know about the regression so far.
+
+ // Regresses string-validate-input, probably because it uses comparisons (< and >)
+ // on strings, which currently will cause speculation failures in some cases.
+ case op_new_regexp:
+#if ENABLE(DFG_RESTRICTIONS)
+ return false;
+#else
+ return true;
+#endif
+
default:
return false;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h 2011-09-28 05:33:21 UTC (rev 96189)
@@ -1068,6 +1068,17 @@
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
+ void callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants)
+ {
+ ASSERT(isFlushed());
+
+ m_jit.move(JITCompiler::TrustedImm32(numConstants), GPRInfo::argumentGPR2);
+ m_jit.move(JITCompiler::TrustedImm32(startConstant), GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+ appendCallWithExceptionCheck(operation);
+ m_jit.move(GPRInfo::returnValueGPR, result);
+ }
void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
{
ASSERT(isFlushed());
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2011-09-28 05:33:21 UTC (rev 96189)
@@ -287,6 +287,12 @@
macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
\
+ /* Allocations. */\
+ macro(NewObject, NodeResultJS) \
+ macro(NewArray, NodeResultJS | NodeHasVarArgs) \
+ macro(NewArrayBuffer, NodeResultJS) \
+ macro(NewRegexp, NodeResultJS) \
+ \
/* Resolve nodes. */\
macro(Resolve, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(ResolveBase, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
@@ -560,6 +566,34 @@
return true;
}
+ bool hasConstantBuffer()
+ {
+ return op == NewArrayBuffer;
+ }
+
+ unsigned startConstant()
+ {
+ ASSERT(hasConstantBuffer());
+ return m_opInfo;
+ }
+
+ unsigned numConstants()
+ {
+ ASSERT(hasConstantBuffer());
+ return m_opInfo2;
+ }
+
+ bool hasRegexpIndex()
+ {
+ return op == NewRegexp;
+ }
+
+ unsigned regexpIndex()
+ {
+ ASSERT(hasRegexpIndex());
+ return m_opInfo;
+ }
+
bool hasVarNumber()
{
return op == GetGlobalVar || op == PutGlobalVar || op == GetScopedVar || op == PutScopedVar;
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2011-09-28 05:33:21 UTC (rev 96189)
@@ -157,6 +157,11 @@
return JSValue::encode(constructEmptyObject(exec, structure));
}
+EncodedJSValue operationNewObject(ExecState* exec)
+{
+ return JSValue::encode(constructEmptyObject(exec));
+}
+
EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
JSValue op1 = JSValue::decode(encodedOp1);
@@ -790,6 +795,29 @@
return JSValue::encode(jsString(exec, static_cast<Register*>(start), size));
}
+EncodedJSValue operationNewArray(ExecState* exec, void* start, size_t size)
+{
+ ArgList argList(static_cast<Register*>(start), size);
+ return JSValue::encode(constructArray(exec, argList));
+}
+
+EncodedJSValue operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
+{
+ ArgList argList(exec->codeBlock()->constantBuffer(start), size);
+ return JSValue::encode(constructArray(exec, argList));
+}
+
+EncodedJSValue operationNewRegexp(ExecState* exec, void* regexpPtr)
+{
+ RegExp* regexp = static_cast<RegExp*>(regexpPtr);
+ if (!regexp->isValid()) {
+ throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ return JSValue::encode(jsUndefined());
+ }
+
+ return RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp);
+}
+
void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase)
{
JSValue base = JSValue::decode(encodedBase);
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2011-09-28 05:33:21 UTC (rev 96189)
@@ -50,6 +50,7 @@
typedef EncodedJSValue (*J_DFGOperation_EJI)(ExecState*, EncodedJSValue, Identifier*);
typedef EncodedJSValue (*J_DFGOperation_EP)(ExecState*, void*);
typedef EncodedJSValue (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
+typedef EncodedJSValue (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
typedef EncodedJSValue (*J_DFGOperation_EI)(ExecState*, Identifier*);
typedef RegisterSizedBoolean (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
typedef RegisterSizedBoolean (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
@@ -62,6 +63,7 @@
// These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
EncodedJSValue operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
EncodedJSValue operationCreateThis(ExecState*, EncodedJSValue encodedOp1);
+EncodedJSValue operationNewObject(ExecState*);
EncodedJSValue operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
EncodedJSValue operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
EncodedJSValue operationArithAdd(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
@@ -82,6 +84,9 @@
EncodedJSValue operationResolveGlobal(ExecState*, GlobalResolveInfo*, Identifier*);
EncodedJSValue operationToPrimitive(ExecState*, EncodedJSValue);
EncodedJSValue operationStrCat(ExecState*, void* start, size_t);
+EncodedJSValue operationNewArray(ExecState*, void* start, size_t);
+EncodedJSValue operationNewArrayBuffer(ExecState*, size_t, size_t);
+EncodedJSValue operationNewRegexp(ExecState*, void*);
void operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
void operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
void operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
Modified: trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp 2011-09-28 05:33:21 UTC (rev 96189)
@@ -509,11 +509,23 @@
break;
}
- case CreateThis: {
+ case CreateThis:
+ case NewObject: {
changed |= setPrediction(PredictFinalObject);
break;
}
+ case NewArray:
+ case NewArrayBuffer: {
+ changed |= setPrediction(PredictArray);
+ break;
+ }
+
+ case NewRegexp: {
+ changed |= setPrediction(PredictObjectOther);
+ break;
+ }
+
case StrCat: {
changed |= setPrediction(PredictString);
break;
@@ -538,7 +550,7 @@
}
break;
}
-
+
case ValueToDouble:
case GetArrayLength: {
// This node should never be visible at this stage of compilation. It is
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2011-09-28 05:33:21 UTC (rev 96189)
@@ -685,6 +685,36 @@
return false;
}
+template<typename T>
+void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
+{
+ MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
+
+ m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
+ slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
+
+ // The object is half-allocated: we have what we know is a fresh object, but
+ // it's still on the GC's free list.
+
+ // Ditch the structure by placing it into the structure slot, so that we can reuse
+ // scratchGPR.
+ m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
+
+ // Now that we have scratchGPR back, remove the object from the free list
+ m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
+ m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
+
+ // Initialize the object's vtable
+ m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
+
+ // Initialize the object's inheritorID.
+ m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
+
+ // Initialize the object's property storage pointer.
+ m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
+ m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
+}
+
void SpeculativeJIT::compile(Node& node)
{
NodeType op = node.op;
@@ -1386,8 +1416,7 @@
// Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
// If we have predicted the base to be type array, we can skip the check.
- Node& baseNode = m_jit.graph()[node.child1()];
- if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+ if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
@@ -1421,8 +1450,7 @@
// Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
// If we have predicted the base to be type array, we can skip the check.
- Node& baseNode = m_jit.graph()[node.child1()];
- if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+ if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
base.use();
@@ -1637,9 +1665,10 @@
break;
}
- case StrCat: {
- // We really don't want to grow the register file just to do a StrCat. Say we
- // have 50 functions on the stack that all have a StrCat in them that has
+ case StrCat:
+ case NewArray: {
+ // We really don't want to grow the register file just to do a StrCat or NewArray.
+ // Say we have 50 functions on the stack that all have a StrCat in them that has
// upwards of 10 operands. In the DFG this would mean that each one gets
// some random virtual register, and then to do the StrCat we'd need a second
// span of 10 operands just to have somewhere to copy the 10 operands to, where
@@ -1669,12 +1698,32 @@
GPRResult result(this);
- callOperation(operationStrCat, result.gpr(), buffer, node.numChildren());
+ callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), buffer, node.numChildren());
- jsValueResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+ cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
break;
}
-
+
+ case NewArrayBuffer: {
+ flushRegisters();
+ GPRResult result(this);
+
+ callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants());
+
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case NewRegexp: {
+ flushRegisters();
+ GPRResult result(this);
+
+ callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));
+
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
case ConvertThis: {
SpeculateCellOperand thisValue(this, node.child1());
@@ -1718,46 +1767,49 @@
m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
- MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
+ emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
- m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
- slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
+ MacroAssembler::Jump done = m_jit.jump();
- // The object is half-allocated: we have what we know is a fresh object, but
- // it's still on the GC's free list.
+ slowPath.link(&m_jit);
- // Ditch the inheritorID by placing it into the structure, so that we can reuse
- // scratchGPR.
- m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
+ silentSpillAllRegisters(resultGPR);
+ m_jit.move(protoGPR, GPRInfo::argumentGPR1);
+ m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ appendCallWithExceptionCheck(operationCreateThis);
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+ silentFillAllRegisters(resultGPR);
- // Now that we have scratchGPR back, remove the object from the free list
- m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
- m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
+ done.link(&m_jit);
- // Initialize the object's vtable
- m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
+ cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+ break;
+ }
- // Initialize the object's inheritorID.
- m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
+ case NewObject: {
+ GPRTemporary result(this);
+ GPRTemporary scratch(this);
- // Initialize the object's property storage pointer.
- m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
- m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
+ GPRReg resultGPR = result.gpr();
+ GPRReg scratchGPR = scratch.gpr();
+ MacroAssembler::JumpList slowPath;
+
+ emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);
+
MacroAssembler::Jump done = m_jit.jump();
slowPath.link(&m_jit);
silentSpillAllRegisters(resultGPR);
- m_jit.move(protoGPR, GPRInfo::argumentGPR1);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
- appendCallWithExceptionCheck(operationCreateThis);
+ appendCallWithExceptionCheck(operationNewObject);
m_jit.move(GPRInfo::returnValueGPR, resultGPR);
silentFillAllRegisters(resultGPR);
done.link(&m_jit);
- cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+ cellResult(resultGPR, m_compileIndex);
break;
}
@@ -1833,14 +1885,13 @@
}
case GetArrayLength: {
- Node& baseNode = m_jit.graph()[node.child1()];
SpeculateCellOperand base(this, node.child1());
GPRTemporary result(this);
GPRReg baseGPR = base.gpr();
GPRReg resultGPR = result.gpr();
- if (baseNode.op != GetLocal || !isArrayPrediction(m_jit.graph().getPrediction(baseNode.local())))
+ if (!isKnownArray(node.child1()))
speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (96188 => 96189)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-09-28 05:23:51 UTC (rev 96188)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2011-09-28 05:33:21 UTC (rev 96189)
@@ -512,11 +512,32 @@
|| (shouldSpeculateObject(op1) && shouldSpeculateArray(op2));
}
+ bool isKnownArray(NodeIndex op1)
+ {
+ Node& node = m_jit.graph()[op1];
+ switch (node.op) {
+ case GetLocal:
+ return isArrayPrediction(m_jit.graph().getPrediction(node.local()));
+
+ case NewArray:
+ case NewArrayBuffer:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, Z_DFGOperation_EJJ);
void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition);
void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr);
void compileObjectEquality(Node&, void* vptr);
+
+ // It is acceptable to have structure be equal to scratch, so long as you're fine
+ // with the structure GPR being clobbered.
+ template<typename T>
+ void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath);
#if USE(JSVALUE64)
JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);