summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-06-27 09:28:46 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-06-27 09:28:46 +0200
commit6668b07fcd51f86be243b9e08e667224e30c0cf8 (patch)
tree64f466e09b68a77ae1156c0d35cd5b95e18a34ca /Source/JavaScriptCore/dfg
parente7923d9de38974f0c6fb7646c898a6ea618261e8 (diff)
downloadqtwebkit-6668b07fcd51f86be243b9e08e667224e30c0cf8.tar.gz
Imported WebKit commit 26cd9bd8ab0471ffe987c9b60368f63dc0f1f31b (http://svn.webkit.org/repository/webkit/trunk@121325)
New snapshot with more Windows build fixes
Diffstat (limited to 'Source/JavaScriptCore/dfg')
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp12
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h25
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp11
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h31
-rw-r--r--Source/JavaScriptCore/dfg/DFGNodeType.h5
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp18
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.h7
-rw-r--r--Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp6
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp28
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h30
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp95
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp79
13 files changed, 280 insertions, 79 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 94e96853d..c2d49f7ee 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1141,13 +1141,19 @@ bool AbstractState::execute(unsigned indexInBlock)
case NewArray:
case NewArrayBuffer:
node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObject()->arrayStructure());
+ forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
+ m_haveStructures = true;
+ break;
+
+ case NewArrayWithSize:
+ speculateInt32Unary(node);
+ forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->arrayStructure());
m_haveStructures = true;
break;
case NewRegexp:
node.setCanExit(false);
- forNode(nodeIndex).set(m_codeBlock->globalObject()->regExpStructure());
+ forNode(nodeIndex).set(m_graph.globalObjectFor(node.codeOrigin)->regExpStructure());
m_haveStructures = true;
break;
@@ -1392,7 +1398,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case StructureTransitionWatchpoint: {
// FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible!
AbstractValue& value = forNode(node.child1());
- ASSERT(isCellSpeculation(value.m_type));
+ ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
value.filter(node.structure());
node.setCanExit(true);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 75611972e..cdb0b639a 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1606,15 +1606,19 @@ bool ByteCodeParser::handleConstantInternalFunction(
// we know about is small enough, that having just a linear cascade of if statements
// is good enough.
- UNUSED_PARAM(registerOffset); // Remove this once we do more things to the arguments.
UNUSED_PARAM(prediction); // Remove this once we do more things.
UNUSED_PARAM(kind); // Remove this once we do more things.
if (function->classInfo() == &ArrayConstructor::s_info) {
- // We could handle this but don't for now.
- if (argumentCountIncludingThis != 1)
- return false;
+ if (argumentCountIncludingThis == 2) {
+ setIntrinsicResult(
+ usesResult, resultOperand,
+ addToGraph(NewArrayWithSize, get(registerOffset + argumentToOperand(1))));
+ return true;
+ }
+ for (int i = 1; i < argumentCountIncludingThis; ++i)
+ addVarArgChild(get(registerOffset + argumentToOperand(i)));
setIntrinsicResult(
usesResult, resultOperand,
addToGraph(Node::VarArg, NewArray, OpInfo(0), OpInfo(0)));
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index 4cacd45c1..b60290870 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -160,6 +160,14 @@ public:
addCallArgument(arg2);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2)
{
resetCallArguments();
@@ -203,6 +211,15 @@ public:
addCallArgument(arg3);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
+ {
+ resetCallArguments();
+ addCallArgument(GPRInfo::callFrameRegister);
+ addCallArgument(arg1);
+ addCallArgument(arg2);
+ addCallArgument(arg3);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
{
resetCallArguments();
@@ -597,6 +614,14 @@ public:
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
}
+ ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, TrustedImmPtr arg2, TrustedImmPtr arg3)
+ {
+ move(arg1, GPRInfo::argumentGPR1);
+ move(arg2, GPRInfo::argumentGPR2);
+ move(arg3, GPRInfo::argumentGPR3);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ }
+
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, TrustedImm32 arg3)
{
move(arg1, GPRInfo::argumentGPR1);
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index a362e6e97..be0012f56 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1080,10 +1080,15 @@ private:
break;
case PutByVal:
- if (m_graph.byValIsPure(node)
- && !m_graph[node.child1()].shouldSpeculateArguments()
- && getByValLoadElimination(node.child1().index(), node.child2().index()) != NoNode)
+ if (isActionableMutableArraySpeculation(m_graph[node.child1()].prediction())
+ && m_graph[node.child2()].shouldSpeculateInteger()
+ && !m_graph[node.child1()].shouldSpeculateArguments()) {
+ NodeIndex nodeIndex = getByValLoadElimination(
+ node.child1().index(), node.child2().index());
+ if (nodeIndex == NoNode)
+ break;
node.setOp(PutByValAlias);
+ }
break;
case CheckStructure:
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 9e4a28fc3..a9080d117 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -463,10 +463,31 @@ public:
bool byValIsPure(Node& node)
{
- return at(node.child2()).shouldSpeculateInteger()
- && ((node.op() == PutByVal || node.op() == PutByValAlias)
- ? isActionableMutableArraySpeculation(at(node.child1()).prediction())
- : isActionableArraySpeculation(at(node.child1()).prediction()));
+ if (!at(node.child2()).shouldSpeculateInteger())
+ return false;
+ SpeculatedType prediction = at(node.child1()).prediction();
+ switch (node.op()) {
+ case PutByVal:
+ if (!isActionableMutableArraySpeculation(prediction))
+ return false;
+ if (isArraySpeculation(prediction))
+ return false;
+ return true;
+
+ case PutByValAlias:
+ if (!isActionableMutableArraySpeculation(prediction))
+ return false;
+ return true;
+
+ case GetByVal:
+ if (!isActionableArraySpeculation(prediction))
+ return false;
+ return true;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return false;
+ }
}
bool clobbersWorld(Node& node)
@@ -484,6 +505,8 @@ public:
case CompareEq:
return !isPredictedNumerical(node);
case GetByVal:
+ case PutByVal:
+ case PutByValAlias:
return !byValIsPure(node);
default:
ASSERT_NOT_REACHED();
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 4671f6b6c..8c2f96222 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -111,8 +111,8 @@ namespace JSC { namespace DFG {
/* Since a put to 'length' may invalidate optimizations here, */\
/* this must be the directly subsequent property put. */\
macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
- macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \
- macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \
+ macro(PutByVal, NodeMustGenerate | NodeMightClobber) \
+ macro(PutByValAlias, NodeMustGenerate | NodeMightClobber) \
macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
macro(PutById, NodeMustGenerate | NodeClobbersWorld) \
@@ -184,6 +184,7 @@ namespace JSC { namespace DFG {
/* Allocations. */\
macro(NewObject, NodeResultJS) \
macro(NewArray, NodeResultJS | NodeHasVarArgs) \
+ macro(NewArrayWithSize, NodeResultJS) \
macro(NewArrayBuffer, NodeResultJS) \
macro(NewRegexp, NodeResultJS) \
\
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index b056a3c6d..11362f432 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1005,12 +1005,22 @@ EncodedJSValue DFG_OPERATION operationStrCat(ExecState* exec, void* buffer, size
return JSValue::encode(jsString(exec, static_cast<Register*>(buffer), size));
}
-EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* buffer, size_t size)
+EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
- return JSValue::encode(constructArray(exec, static_cast<JSValue*>(buffer), size));
+ return JSValue::encode(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
+}
+
+EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
+{
+ return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure));
+}
+
+EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size)
+{
+ return JSValue::encode(JSArray::create(exec->globalData(), arrayStructure, size));
}
EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
@@ -1238,12 +1248,12 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void*
SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
CodeBlock* codeBlock = debugInfo->codeBlock;
CodeBlock* alternative = codeBlock->alternative();
- dataLog("Speculation failure in %p at @%u with executeCounter = %d, "
+ dataLog("Speculation failure in %p at @%u with executeCounter = %s, "
"reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, "
"success/fail %u/(%u+%u)\n",
codeBlock,
debugInfo->nodeIndex,
- alternative ? alternative->jitExecuteCounter() : 0,
+ alternative ? alternative->jitExecuteCounter().status() : 0,
alternative ? alternative->reoptimizationRetryCounter() : 0,
alternative ? alternative->optimizationDelayCounter() : 0,
codeBlock->speculativeSuccessCounter(),
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 7477ab2fc..3c85ee761 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -76,6 +76,9 @@ typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EP)(ExecState*, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPP)(ExecState*, void*, void*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EPS)(ExecState*, void*, size_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESS)(ExecState*, size_t, size_t);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ESt)(ExecState*, Structure*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStI)(ExecState*, Structure*, int32_t);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EStPS)(ExecState*, Structure*, void*, size_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZ)(ExecState*, int32_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZIcfZ)(ExecState*, int32_t, InlineCallFrame*, int32_t);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EZZ)(ExecState*, int32_t, int32_t);
@@ -124,8 +127,10 @@ EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState*, Identifie
EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState*, GlobalResolveInfo*, JSGlobalObject*, Identifier*) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationStrCat(ExecState*, void*, size_t) WTF_INTERNAL;
-EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, void*, size_t) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewArray(ExecState*, Structure*, void*, size_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState*, size_t, size_t) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewEmptyArray(ExecState*, Structure*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewArrayWithSize(ExecState*, Structure*, int32_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index bcb79a96a..0bd81ec44 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -535,6 +535,12 @@ private:
break;
}
+ case NewArrayWithSize: {
+ changed |= setPrediction(SpecArray);
+ changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+ break;
+ }
+
case NewArrayBuffer: {
changed |= setPrediction(SpecArray);
break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index d9a79f13a..0c0f3260f 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -986,13 +986,8 @@ void SpeculativeJIT::compile(BasicBlock& block)
m_jit.jitAssertHasValidCallFrame();
ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
- for (size_t i = 0; i < m_arguments.size(); ++i) {
- NodeIndex nodeIndex = block.variablesAtHead.argument(i);
- if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i))
- m_arguments[i] = ValueSource(ValueInRegisterFile);
- else
- m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction());
- }
+ for (size_t i = 0; i < m_arguments.size(); ++i)
+ m_arguments[i] = ValueSource(ValueInRegisterFile);
m_state.reset();
m_state.beginBasicBlock(&block);
@@ -2005,10 +2000,10 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
return;
}
- MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset));
- m_jit.xorPtr(resultReg, resultReg);
- MacroAssembler::Jump outOfBounds = m_jit.jump();
- inBounds.link(&m_jit);
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset)));
switch (elementSize) {
case 1:
if (signedness == SignedTypedArray)
@@ -2028,7 +2023,6 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
default:
ASSERT_NOT_REACHED();
}
- outOfBounds.link(&m_jit);
if (elementSize < 4 || signedness == SignedTypedArray) {
integerResult(resultReg, m_compileIndex);
return;
@@ -2167,11 +2161,10 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
FPRTemporary result(this);
FPRReg resultReg = result.fpr();
ASSERT(speculationRequirements != NoTypedArraySpecCheck);
- MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset));
- static const double zero = 0;
- m_jit.loadDouble(&zero, resultReg);
- MacroAssembler::Jump outOfBounds = m_jit.jump();
- inBounds.link(&m_jit);
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset)));
switch (elementSize) {
case 4:
m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
@@ -2188,7 +2181,6 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
default:
ASSERT_NOT_REACHED();
}
- outOfBounds.link(&m_jit);
doubleResult(resultReg, m_compileIndex);
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 6c6948b90..67a22b767 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1244,6 +1244,21 @@ public:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg result, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg result, Structure* structure, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg result, Structure* structure, void* pointer, size_t size)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
@@ -1502,6 +1517,21 @@ public:
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_ESt operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EStI operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, GPRReg arg2)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), arg2);
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
+ JITCompiler::Call callOperation(J_DFGOperation_EStPS operation, GPRReg resultTag, GPRReg resultPayload, Structure* structure, void* pointer, size_t size)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure), TrustedImmPtr(pointer), TrustedImmPtr(size));
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 21d94e9e8..05609baa8 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -1891,7 +1891,7 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- if (isInt32Speculation(prediction)) {
+ if (isInt32Speculation(value.m_type)) {
GPRTemporary result(this);
m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
@@ -1903,7 +1903,7 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- if (isArraySpeculation(prediction)) {
+ if (isArraySpeculation(value.m_type)) {
GPRTemporary result(this);
m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
@@ -1915,7 +1915,7 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- if (isBooleanSpeculation(prediction)) {
+ if (isBooleanSpeculation(value.m_type)) {
GPRTemporary result(this);
m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());
@@ -2975,25 +2975,60 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- 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
- // they'd be contiguous and we could easily tell the C code how to find them.
- // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
- // way, those 50 functions will share the same scratchBuffer for offloading their
- // StrCat operands. It's about as good as we can do, unless we start doing
- // virtual register coalescing to ensure that operands to StrCat get spilled
- // in exactly the place where StrCat wants them, or else have the StrCat
- // refer to those operands' SetLocal instructions to force them to spill in
- // the right place. Basically, any way you cut it, the current approach
- // probably has the best balance of performance and sensibility in the sense
- // that it does not increase the complexity of the DFG JIT just to make StrCat
- // fast and pretty.
+ case StrCat: {
+ size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
+ ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
+ EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
+
+ for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
+ JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+ GPRReg opTagGPR = operand.tagGPR();
+ GPRReg opPayloadGPR = operand.payloadGPR();
+ operand.use();
+
+ m_jit.store32(opTagGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
+ m_jit.store32(opPayloadGPR, reinterpret_cast<char*>(buffer + operandIdx) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
+ }
+
+ flushRegisters();
+ if (scratchSize) {
+ GPRTemporary scratch(this);
+
+ // Tell GC mark phase how much of the scratch buffer is active during call.
+ m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+ m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
+ }
+
+ GPRResult resultPayload(this);
+ GPRResult2 resultTag(this);
+
+ callOperation(operationStrCat, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren());
+
+ if (scratchSize) {
+ GPRTemporary scratch(this);
+
+ m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+ m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
+ }
+
+ // FIXME: make the callOperation above explicitly return a cell result, or jitAssert the tag is a cell tag.
+ cellResult(resultPayload.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ case NewArray: {
+ if (!node.numChildren()) {
+ flushRegisters();
+ GPRResult result(this);
+ GPRResult2 resultTagIgnored(this);
+ callOperation(
+ operationNewEmptyArray, resultTagIgnored.gpr(), result.gpr(),
+ m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
@@ -3021,7 +3056,10 @@ void SpeculativeJIT::compile(Node& node)
GPRResult resultPayload(this);
GPRResult2 resultTag(this);
- callOperation(op == StrCat ? operationStrCat : operationNewArray, resultTag.gpr(), resultPayload.gpr(), static_cast<void *>(buffer), node.numChildren());
+ callOperation(
+ operationNewArray, resultTag.gpr(), resultPayload.gpr(),
+ m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+ static_cast<void *>(buffer), node.numChildren());
if (scratchSize) {
GPRTemporary scratch(this);
@@ -3035,6 +3073,19 @@ void SpeculativeJIT::compile(Node& node)
break;
}
+ case NewArrayWithSize: {
+ SpeculateStrictInt32Operand size(this, node.child1());
+ GPRReg sizeGPR = size.gpr();
+ flushRegisters();
+ GPRResult result(this);
+ GPRResult2 resultTagIgnored(this);
+ callOperation(
+ operationNewArrayWithSize, resultTagIgnored.gpr(), result.gpr(),
+ m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
case NewArrayBuffer: {
flushRegisters();
GPRResult resultPayload(this);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index a6c283584..215f8013d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3035,25 +3035,68 @@ void SpeculativeJIT::compile(Node& node)
break;
}
- 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
- // they'd be contiguous and we could easily tell the C code how to find them.
- // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That
- // way, those 50 functions will share the same scratchBuffer for offloading their
- // StrCat operands. It's about as good as we can do, unless we start doing
- // virtual register coalescing to ensure that operands to StrCat get spilled
- // in exactly the place where StrCat wants them, or else have the StrCat
- // refer to those operands' SetLocal instructions to force them to spill in
- // the right place. Basically, any way you cut it, the current approach
- // probably has the best balance of performance and sensibility in the sense
- // that it does not increase the complexity of the DFG JIT just to make StrCat
- // fast and pretty.
+ if (!node.numChildren()) {
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(
+ operationNewEmptyArray, result.gpr(),
+ m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure());
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
+ ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
+ EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
+
+ for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {
+ JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);
+ GPRReg opGPR = operand.gpr();
+ operand.use();
+
+ m_jit.storePtr(opGPR, buffer + operandIdx);
+ }
+
+ flushRegisters();
+
+ if (scratchSize) {
+ GPRTemporary scratch(this);
+ // Tell GC mark phase how much of the scratch buffer is active during call.
+ m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+ m_jit.storePtr(TrustedImmPtr(scratchSize), scratch.gpr());
+ }
+
+ GPRResult result(this);
+
+ callOperation(
+ operationNewArray, result.gpr(),
+ m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(),
+ static_cast<void*>(buffer), node.numChildren());
+
+ if (scratchSize) {
+ GPRTemporary scratch(this);
+
+ m_jit.move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), scratch.gpr());
+ m_jit.storePtr(TrustedImmPtr(0), scratch.gpr());
+ }
+
+ cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);
+ break;
+ }
+
+ case NewArrayWithSize: {
+ SpeculateStrictInt32Operand size(this, node.child1());
+ GPRReg sizeGPR = size.gpr();
+ flushRegisters();
+ GPRResult result(this);
+ callOperation(operationNewArrayWithSize, result.gpr(), m_jit.graph().globalObjectFor(node.codeOrigin)->arrayStructure(), sizeGPR);
+ cellResult(result.gpr(), m_compileIndex);
+ break;
+ }
+
+ case StrCat: {
size_t scratchSize = sizeof(EncodedJSValue) * node.numChildren();
ScratchBuffer* scratchBuffer = m_jit.globalData()->scratchBufferForSize(scratchSize);
EncodedJSValue* buffer = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
@@ -3078,7 +3121,7 @@ void SpeculativeJIT::compile(Node& node)
GPRResult result(this);
- callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), static_cast<void *>(buffer), node.numChildren());
+ callOperation(operationStrCat, result.gpr(), static_cast<void *>(buffer), node.numChildren());
if (scratchSize) {
GPRTemporary scratch(this);