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