DFG assumes that NewFunction will never pass its input through
https://bugs.webkit.org/show_bug.cgi?id=118798
Source/JavaScriptCore:
Reviewed by Sam Weinig.
Previously the DFG was assuming that NewFunction always returns a function. That's not
the case. It may return whatever was passed to it, if it wasn't passed SpecEmpty.
This fact needed to be wired through the compiler.
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::makeTop):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
LayoutTests:
Reviewed by Sam Weinig.
* fast/js/dfg-use-function-as-variable-expected.txt: Added.
* fast/js/dfg-use-function-as-variable-merge-structure-expected.txt: Added.
* fast/js/dfg-use-function-as-variable-merge-structure.html: Added.
* fast/js/dfg-use-function-as-variable-not-constant-expected.txt: Added.
* fast/js/dfg-use-function-as-variable-not-constant.html: Added.
* fast/js/dfg-use-function-as-variable-with-closure-expected.txt: Added.
* fast/js/dfg-use-function-as-variable-with-closure.html: Added.
* fast/js/dfg-use-function-as-variable.html: Added.
* fast/js/jsc-test-list:
* fast/js/script-tests/dfg-use-function-as-variable-merge-structure.js: Added.
(.x):
(run_tests):
* fast/js/script-tests/dfg-use-function-as-variable-not-constant.js: Added.
(run_tests.x):
(run_tests):
* fast/js/script-tests/dfg-use-function-as-variable-with-closure.js: Added.
(run_tests.x):
(run_tests.y):
(run_tests):
* fast/js/script-tests/dfg-use-function-as-variable.js: Added.
(run_tests.x):
(run_tests):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@152813 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 0b819ad..bdfa6c8 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,32 @@
+2013-07-17 Filip Pizlo <fpizlo@apple.com>
+
+ DFG assumes that NewFunction will never pass its input through
+ https://bugs.webkit.org/show_bug.cgi?id=118798
+
+ Reviewed by Sam Weinig.
+
+ Previously the DFG was assuming that NewFunction always returns a function. That's not
+ the case. It may return whatever was passed to it, if it wasn't passed SpecEmpty.
+
+ This fact needed to be wired through the compiler.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::executeEffects):
+ * dfg/DFGAbstractValue.h:
+ (JSC::DFG::AbstractValue::makeTop):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::dump):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
2013-07-17 Geoffrey Garen <ggaren@apple.com>
JSStringCreateWithCFString should not convert the empty string into the NULL string
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 76e69ee..2ac79c7 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1226,7 +1226,19 @@
forNode(node).makeTop();
break;
- case NewFunction:
+ case NewFunction: {
+ AbstractValue& value = forNode(node);
+ value = forNode(node->child1());
+
+ if (!(value.m_type & SpecEmpty)) {
+ m_foundConstants = true;
+ break;
+ }
+
+ value.set((value.m_type & ~SpecEmpty) | SpecFunction);
+ break;
+ }
+
case NewFunctionExpression:
case NewFunctionNoCheck:
forNode(node).set(m_codeBlock->globalObjectFor(node->codeOrigin)->functionStructure());
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index 8d25be9..25757b5 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -65,7 +65,7 @@
void makeTop()
{
- m_type = SpecTop;
+ m_type |= SpecTop; // The state may have included SpecEmpty, in which case we want this to become SpecEmptyOrTop.
m_arrayModes = ALL_ARRAY_MODES;
m_currentKnownStructure.makeTop();
m_futurePossibleStructure.makeTop();
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 849db6d..612f6f0 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -215,6 +215,14 @@
else
out.print(comma, "executable(not function: ", RawPointer(node->executable()), ")");
}
+ if (node->hasFunctionDeclIndex()) {
+ FunctionExecutable* executable = m_codeBlock->functionDecl(node->functionDeclIndex());
+ out.print(comma, executable->inferredName().string(), "#", executable->hashFor(CodeForCall));
+ }
+ if (node->hasFunctionExprIndex()) {
+ FunctionExecutable* executable = m_codeBlock->functionExpr(node->functionExprIndex());
+ out.print(comma, executable->inferredName().string(), "#", executable->hashFor(CodeForCall));
+ }
if (node->hasStorageAccessData()) {
StorageAccessData& storageAccessData = m_storageAccessData[node->storageAccessDataIndex()];
out.print(comma, "id", storageAccessData.identifierNumber, "{", m_codeBlock->identifier(storageAccessData.identifierNumber).string(), "}");
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 310f244..c797bcc 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1412,7 +1412,7 @@
return JSValue::encode(argumentsValue.get(exec, index));
}
-JSCell* DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable)
+JSCell* DFG_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable)
{
ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info));
VM& vm = exec->vm();
@@ -1420,6 +1420,14 @@
return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
}
+EncodedJSValue DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable)
+{
+ ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info));
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ return JSValue::encode(JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope()));
+}
+
JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell)
{
ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info));
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index c314e8e..2c7a5f7 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -61,6 +61,7 @@
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_E)(ExecState*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EAZ)(ExecState*, JSArray*, int32_t);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EC)(ExecState*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECI)(ExecState*, JSCell*, Identifier*);
typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
@@ -206,7 +207,8 @@
EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState*, int32_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal(ExecState*, int32_t, InlineCallFrame*, int32_t) WTF_INTERNAL;
EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int32_t) WTF_INTERNAL;
-JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*) WTF_INTERNAL;
+JSCell* DFG_OPERATION operationNewFunctionNoCheck(ExecState*, JSCell*) WTF_INTERNAL;
+EncodedJSValue DFG_OPERATION operationNewFunction(ExecState*, JSCell*) WTF_INTERNAL;
JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*) WTF_INTERNAL;
double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
size_t DFG_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index b166309..980e6b4 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -453,7 +453,15 @@
break;
}
- case NewFunction:
+ case NewFunction: {
+ SpeculatedType child = node->child1()->prediction();
+ if (child & SpecEmpty)
+ changed |= mergePrediction((child & ~SpecEmpty) | SpecFunction);
+ else
+ changed |= mergePrediction(child);
+ break;
+ }
+
case NewFunctionNoCheck:
case NewFunctionExpression: {
changed |= setPrediction(SpecFunction);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 6d1defa..b64ca63 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1155,6 +1155,11 @@
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EC operation, GPRReg result, JSCell* cell)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
+ return appendCallWithExceptionCheckSetResult(operation, result);
+ }
JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
@@ -1376,6 +1381,11 @@
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
+ JITCompiler::Call callOperation(J_DFGOperation_EC operation, GPRReg resultTag, GPRReg resultPayload, JSCell* cell)
+ {
+ m_jit.setupArgumentsWithExecState(TrustedImmPtr(cell));
+ return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+ }
JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 3595753..b10bf89 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -4897,11 +4897,13 @@
case NewFunction: {
JSValueOperand value(this, node->child1());
- GPRTemporary result(this, value, false);
+ GPRTemporary resultTag(this, op1);
+ GPRTemporary resultPayload(this, op1, false);
GPRReg valueTagGPR = value.tagGPR();
GPRReg valuePayloadGPR = value.payloadGPR();
- GPRReg resultGPR = result.gpr();
+ GPRReg resultTagGPR = resultTag.gpr();
+ GPRReg resultPayloadGPR = resultPayload.gpr();
m_jit.move(valuePayloadGPR, resultGPR);
@@ -4909,10 +4911,10 @@
addSlowPathGenerator(
slowPathCall(
- notCreated, this, operationNewFunction, resultGPR,
+ notCreated, this, operationNewFunction, resultTagGPR, resultPayloadGPR,
m_jit.codeBlock()->functionDecl(node->functionDeclIndex())));
- cellResult(resultGPR, node);
+ jsValueResult(resultTagGPR, resultPayloadGPR, node);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 8044049..65a97a0 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -4752,7 +4752,7 @@
notCreated, this, operationNewFunction,
resultGPR, m_jit.codeBlock()->functionDecl(node->functionDeclIndex())));
- cellResult(resultGPR, node);
+ jsValueResult(resultGPR, node);
break;
}