DFG should be able to optimize foo.apply(bar, arguments)
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 May 2012 00:05:21 +0000 (00:05 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 May 2012 00:05:21 +0000 (00:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=86306

Reviewed by Gavin Barraclough.

Merge r116912 from dfgopt.

Enables compilation of op_jneq_ptr and some forms of op_call_varargs.

Also includes a bunch of bug fixes that were made necessary by the increased
pressure on the CFG simplifier.

This is a 1-2% win on V8.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printCallOp):
(JSC::CodeBlock::CodeBlock):
(JSC::ProgramCodeBlock::canCompileWithDFGInternal):
(JSC::EvalCodeBlock::canCompileWithDFGInternal):
(JSC::FunctionCodeBlock::canCompileWithDFGInternal):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::canCompileWithDFG):
(JSC::CodeBlock::canCompileWithDFGState):
(ProgramCodeBlock):
(EvalCodeBlock):
(FunctionCodeBlock):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::processPhiStack):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
(JSC::DFG::CFGSimplificationPhase::fixPossibleGetLocal):
(JSC::DFG::CFGSimplificationPhase::fixTailOperand):
(JSC::DFG::CFGSimplificationPhase::mergeBlocks):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::getLocalLoadElimination):
(CSEPhase):
(JSC::DFG::CSEPhase::setReplacement):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::debugFail):
(DFG):
(JSC::DFG::canHandleOpcodes):
(JSC::DFG::canCompileOpcodes):
(JSC::DFG::canInlineOpcodes):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):
(DFG):
(JSC::DFG::canCompileOpcodes):
(JSC::DFG::canCompileEval):
(JSC::DFG::canCompileProgram):
(JSC::DFG::canCompileFunctionForCall):
(JSC::DFG::canCompileFunctionForConstruct):
* dfg/DFGCommon.h:
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
(Validate):
(JSC::DFG::Validate::validate):
(JSC::DFG::Validate::checkOperand):
(JSC::DFG::Validate::reportValidationContext):
* jit/JIT.cpp:
(JSC::JIT::emitOptimizationCheck):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::privateCompile):
* jit/JIT.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::compileBinaryArithOp):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::privateCompilePutByIdTransition):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::privateCompilePutByIdTransition):
* tools/CodeProfile.cpp:
(JSC::CodeProfile::sample):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@118270 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.h
Source/JavaScriptCore/dfg/DFGCommon.h
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGValidate.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITArithmetic.cpp
Source/JavaScriptCore/jit/JITPropertyAccess.cpp
Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
Source/JavaScriptCore/tools/CodeProfile.cpp

index faea16b..51e3ff6 100644 (file)
@@ -1,3 +1,94 @@
+2012-05-13  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should be able to optimize foo.apply(bar, arguments)
+        https://bugs.webkit.org/show_bug.cgi?id=86306
+
+        Reviewed by Gavin Barraclough.
+        
+        Merge r116912 from dfgopt.
+        
+        Enables compilation of op_jneq_ptr and some forms of op_call_varargs.
+        
+        Also includes a bunch of bug fixes that were made necessary by the increased
+        pressure on the CFG simplifier.
+        
+        This is a 1-2% win on V8.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printCallOp):
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::ProgramCodeBlock::canCompileWithDFGInternal):
+        (JSC::EvalCodeBlock::canCompileWithDFGInternal):
+        (JSC::FunctionCodeBlock::canCompileWithDFGInternal):
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        (JSC::CodeBlock::canCompileWithDFG):
+        (JSC::CodeBlock::canCompileWithDFGState):
+        (ProgramCodeBlock):
+        (EvalCodeBlock):
+        (FunctionCodeBlock):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::processPhiStack):
+        (JSC::DFG::ByteCodeParser::parse):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::run):
+        (JSC::DFG::CFGSimplificationPhase::fixPossibleGetLocal):
+        (JSC::DFG::CFGSimplificationPhase::fixTailOperand):
+        (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::getLocalLoadElimination):
+        (CSEPhase):
+        (JSC::DFG::CSEPhase::setReplacement):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::debugFail):
+        (DFG):
+        (JSC::DFG::canHandleOpcodes):
+        (JSC::DFG::canCompileOpcodes):
+        (JSC::DFG::canInlineOpcodes):
+        * dfg/DFGCapabilities.h:
+        (JSC::DFG::canCompileOpcode):
+        (JSC::DFG::canInlineOpcode):
+        (DFG):
+        (JSC::DFG::canCompileOpcodes):
+        (JSC::DFG::canCompileEval):
+        (JSC::DFG::canCompileProgram):
+        (JSC::DFG::canCompileFunctionForCall):
+        (JSC::DFG::canCompileFunctionForConstruct):
+        * dfg/DFGCommon.h:
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        (Validate):
+        (JSC::DFG::Validate::validate):
+        (JSC::DFG::Validate::checkOperand):
+        (JSC::DFG::Validate::reportValidationContext):
+        * jit/JIT.cpp:
+        (JSC::JIT::emitOptimizationCheck):
+        (JSC::JIT::privateCompileSlowCases):
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::compileBinaryArithOp):
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::privateCompilePutByIdTransition):
+        * jit/JITPropertyAccess32_64.cpp:
+        (JSC::JIT::privateCompilePutByIdTransition):
+        * tools/CodeProfile.cpp:
+        (JSC::CodeProfile::sample):
+
 2012-05-23  Geoffrey Garen  <ggaren@apple.com>
 
         Refactored WeakBlock to use malloc, clarify behavior
index 7645c16..6677b30 100644 (file)
@@ -387,11 +387,13 @@ void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::
             dataLog(" llint(not set)");
 #endif
 #if ENABLE(JIT)
-        JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get();
-        if (target)
-            dataLog(" jit(%p, exec %p)", target, target->executable());
-        else
-            dataLog(" jit(not set)");
+        if (numberOfCallLinkInfos()) {
+            JSFunction* target = getCallLinkInfo(location).lastSeenCallee.get();
+            if (target)
+                dataLog(" jit(%p, exec %p)", target, target->executable());
+            else
+                dataLog(" jit(not set)");
+        }
 #endif
     }
     dataLog("\n");
@@ -1574,7 +1576,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
     , m_optimizationDelayCounter(0)
     , m_reoptimizationRetryCounter(0)
 #if ENABLE(JIT)
-    , m_canCompileWithDFGState(CompileWithDFGUnset)
+    , m_canCompileWithDFGState(DFG::CapabilityLevelNotSet)
 #endif
 {
     setNumParameters(other.numParameters());
@@ -2469,17 +2471,17 @@ JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* s
     return error;
 }
 
-bool ProgramCodeBlock::canCompileWithDFGInternal()
+DFG::CapabilityLevel ProgramCodeBlock::canCompileWithDFGInternal()
 {
     return DFG::canCompileProgram(this);
 }
 
-bool EvalCodeBlock::canCompileWithDFGInternal()
+DFG::CapabilityLevel EvalCodeBlock::canCompileWithDFGInternal()
 {
     return DFG::canCompileEval(this);
 }
 
-bool FunctionCodeBlock::canCompileWithDFGInternal()
+DFG::CapabilityLevel FunctionCodeBlock::canCompileWithDFGInternal()
 {
     if (m_isConstructor)
         return DFG::canCompileFunctionForConstruct(this);
index 2c25fee..549e300 100644 (file)
@@ -382,20 +382,14 @@ namespace JSC {
         }
         virtual CodeBlock* replacement() = 0;
 
-        enum CompileWithDFGState {
-            CompileWithDFGFalse,
-            CompileWithDFGTrue,
-            CompileWithDFGUnset
-        };
-
-        virtual bool canCompileWithDFGInternal() = 0;
-        bool canCompileWithDFG()
+        virtual DFG::CapabilityLevel canCompileWithDFGInternal() = 0;
+        DFG::CapabilityLevel canCompileWithDFG()
         {
-            bool result = canCompileWithDFGInternal();
-            m_canCompileWithDFGState = result ? CompileWithDFGTrue : CompileWithDFGFalse;
+            DFG::CapabilityLevel result = canCompileWithDFGInternal();
+            m_canCompileWithDFGState = result;
             return result;
         }
-        CompileWithDFGState canCompileWithDFGState() { return m_canCompileWithDFGState; }
+        DFG::CapabilityLevel canCompileWithDFGState() { return m_canCompileWithDFGState; }
 
         bool hasOptimizedReplacement()
         {
@@ -1309,7 +1303,7 @@ namespace JSC {
 #endif
         OwnPtr<RareData> m_rareData;
 #if ENABLE(JIT)
-        CompileWithDFGState m_canCompileWithDFGState;
+        DFG::CapabilityLevel m_canCompileWithDFGState;
 #endif
     };
 
@@ -1351,7 +1345,7 @@ namespace JSC {
         virtual void jettison();
         virtual bool jitCompileImpl(ExecState*);
         virtual CodeBlock* replacement();
-        virtual bool canCompileWithDFGInternal();
+        virtual DFG::CapabilityLevel canCompileWithDFGInternal();
 #endif
     };
 
@@ -1386,7 +1380,7 @@ namespace JSC {
         virtual void jettison();
         virtual bool jitCompileImpl(ExecState*);
         virtual CodeBlock* replacement();
-        virtual bool canCompileWithDFGInternal();
+        virtual DFG::CapabilityLevel canCompileWithDFGInternal();
 #endif
 
     private:
@@ -1424,7 +1418,7 @@ namespace JSC {
         virtual void jettison();
         virtual bool jitCompileImpl(ExecState*);
         virtual CodeBlock* replacement();
-        virtual bool canCompileWithDFGInternal();
+        virtual DFG::CapabilityLevel canCompileWithDFGInternal();
 #endif
     };
 
index 0ae5069..2ee5b6d 100644 (file)
@@ -1068,6 +1068,7 @@ bool AbstractState::execute(unsigned indexInBlock)
         
     case TearOffActivation:
     case TearOffArguments:
+    case CheckArgumentsNotCreated:
         // Does nothing that is user-visible.
         break;
         
index 3d843c2..5a182a5 100644 (file)
@@ -2361,8 +2361,52 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             handleCall(interpreter, currentInstruction, Construct, CodeForConstruct);
             NEXT_OPCODE(op_construct);
             
+        case op_call_varargs: {
+            ASSERT(m_inlineStackTop->m_inlineCallFrame);
+            ASSERT(currentInstruction[3].u.operand == m_inlineStackTop->m_codeBlock->argumentsRegister());
+            // It would be cool to funnel this into handleCall() so that it can handle
+            // inlining. But currently that won't be profitable anyway, since none of the
+            // uses of call_varargs will be inlineable. So we set this up manually and
+            // without inline/intrinsic detection.
+            
+            Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call_varargs);
+            
+            PredictedType prediction = PredictNone;
+            if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
+                m_currentProfilingIndex = m_currentIndex + OPCODE_LENGTH(op_call_varargs);
+                prediction = getPrediction();
+            }
+            
+            addToGraph(CheckArgumentsNotCreated);
+            
+            unsigned argCount = m_inlineStackTop->m_inlineCallFrame->arguments.size();
+            if (RegisterFile::CallFrameHeaderSize + argCount > m_parameterSlots)
+                m_parameterSlots = RegisterFile::CallFrameHeaderSize + argCount;
+            
+            addVarArgChild(get(currentInstruction[1].u.operand)); // callee
+            addVarArgChild(get(currentInstruction[2].u.operand)); // this
+            for (unsigned argument = 1; argument < argCount; ++argument)
+                addVarArgChild(get(argumentToOperand(argument)));
+            
+            NodeIndex call = addToGraph(Node::VarArg, Call, OpInfo(0), OpInfo(prediction));
+            if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result)
+                set(putInstruction[1].u.operand, call);
+            
+            NEXT_OPCODE(op_call_varargs);
+        }
+            
         case op_call_put_result:
             NEXT_OPCODE(op_call_put_result);
+            
+        case op_jneq_ptr:
+            // Statically speculate for now. It makes sense to let speculate-only jneq_ptr
+            // support simmer for a while before making it more general, since it's
+            // already gnarly enough as it is.
+            addToGraph(
+                CheckFunction, OpInfo(currentInstruction[2].u.jsCell.get()),
+                get(currentInstruction[1].u.operand));
+            addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr)));
+            LAST_OPCODE(op_jneq_ptr);
 
         case op_resolve: {
             PredictedType prediction = getPrediction();
@@ -2484,8 +2528,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             ASSERT_NOT_REACHED();
             return false;
         }
-        
-        ASSERT(canCompileOpcode(opcodeID));
     }
 }
 
@@ -2501,6 +2543,9 @@ void ByteCodeParser::processPhiStack()
         if (!entry.m_block->isReachable)
             continue;
         
+        if (!entry.m_block->isReachable)
+            continue;
+        
         PredecessorList& predecessors = entry.m_block->m_predecessors;
         unsigned varNo = entry.m_varNo;
         VariableAccessData* dataForPhi = m_graph[entry.m_phi].variableAccessData();
@@ -2944,14 +2989,14 @@ bool ByteCodeParser::parse()
     dataLog("Processing argument phis.\n");
 #endif
     processPhiStack<ArgumentPhiStack>();
-    
+
     for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
         BasicBlock* block = m_graph.m_blocks[blockIndex].get();
         ASSERT(block);
         if (!block->isReachable)
             m_graph.m_blocks[blockIndex].clear();
     }
-
+    
     fixVariableAccessPredictions();
     
     m_graph.m_preservedVars = m_preservedVars;
index be3401a..32af1b1 100644 (file)
@@ -279,12 +279,23 @@ private:
         Node& child = m_graph[edge];
         if (child.op() != GetLocal)
             return;
-        if (child.variableAccessData()->isCaptured())
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLog("    Considering GetLocal at @%u.\n", edge.index());
+#endif
+        if (child.variableAccessData()->isCaptured()) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog("        It's captured.\n");
+#endif
             return;
+        }
         NodeIndex originalNodeIndex = block->variablesAtTail.operand(child.local());
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLog("        Dealing with original @%u.\n", originalNodeIndex);
+#endif
         ASSERT(originalNodeIndex != NoNode);
         Node* originalNode = &m_graph[originalNodeIndex];
-        ASSERT(originalNode->shouldGenerate());
+        if (changeRef)
+            ASSERT(originalNode->shouldGenerate());
         // Possibilities:
         // SetLocal -> the secondBlock is getting the value of something that is immediately
         //     available in the first block with a known NodeIndex.
@@ -304,15 +315,24 @@ private:
         }
         switch (originalNode->op()) {
         case SetLocal: {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog("        It's a SetLocal.\n");
+#endif
             m_graph.changeIndex(edge, originalNode->child1().index(), changeRef);
             break;
         }
         case GetLocal: {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog("        It's a GetLocal.\n");
+#endif
             m_graph.changeIndex(edge, originalNodeIndex, changeRef);
             break;
         }
         case Phi:
         case SetArgument: {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+            dataLog("        It's Phi/SetArgument.\n");
+#endif
             // Keep the GetLocal!
             break;
         }
@@ -445,12 +465,6 @@ private:
 
         Node& secondNode = m_graph[atSecondTail];
         
-        if (secondNode.variableAccessData()->isCaptured()) {
-            // The second block did something to a variable that is captured, so reflect this.
-            firstBlock->variablesAtTail.operand(operand) = atSecondTail;
-            return;
-        }
-        
         switch (secondNode.op()) {
         case SetLocal:
         case Flush: {
@@ -470,13 +484,35 @@ private:
         }
 
         case GetLocal: {
-            // Keep what was in the first block, and adjust the substitution to account for
-            // the fact that successors will refer to the child of the GetLocal.
-            ASSERT(firstBlock->variablesAtTail.operand(operand) != NoNode);
-            substitutions.operand(operand) =
-                OperandSubstitution(
-                    secondNode.child1().index(),
-                    skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
+            // If it's a GetLocal on a captured var, then definitely keep what was
+            // in the second block. In particular, it's possible that the first
+            // block doesn't even know about this variable.
+            if (secondNode.variableAccessData()->isCaptured()) {
+                firstBlock->variablesAtTail.operand(operand) = atSecondTail;
+                break;
+            }
+            
+            // It's possible that the second block had a GetLocal and the first block
+            // had a SetArgument or a Phi. Then update the tail. Otherwise keep what was in the
+            // first block.
+            NodeIndex atFirstTail = firstBlock->variablesAtTail.operand(operand);
+            ASSERT(atFirstTail != NoNode);
+            switch (m_graph[atFirstTail].op()) {
+            case SetArgument:
+            case Phi:
+                firstBlock->variablesAtTail.operand(operand) = atSecondTail;
+                break;
+
+            default:
+                // Keep what was in the first block, and adjust the substitution to account for
+                // the fact that successors will refer to the child of the GetLocal.
+                ASSERT(firstBlock->variablesAtTail.operand(operand) != NoNode);
+                substitutions.operand(operand) =
+                    OperandSubstitution(
+                        secondNode.child1().index(),
+                        skipGetLocal(firstBlock->variablesAtTail.operand(operand)));
+                break;
+            }
             break;
         }
             
@@ -524,7 +560,11 @@ private:
             NodeIndex nodeIndex = secondBlock->at(i);
             Node& node = m_graph[nodeIndex];
             
-            if (node.op() == Phantom && !!node.child1()) {
+            switch (node.op()) {
+            case Phantom: {
+                if (!node.child1())
+                    break;
+                
                 ASSERT(node.shouldGenerate());
                 Node& possibleLocalOp = m_graph[node.child1()];
                 if (possibleLocalOp.hasLocal()) {
@@ -534,6 +574,25 @@ private:
                     if (setLocal.op() == SetLocal)
                         m_graph.changeEdge(node.children.child1(), setLocal.child1());
                 }
+                break;
+            }
+                
+            case Flush: {
+                // The flush could use a GetLocal, SetLocal, SetArgument, or a Phi.
+                // If it uses a GetLocal, it'll be taken care of below. If it uses a
+                // SetLocal or SetArgument, then it must be using a node from the
+                // same block. But if it uses a Phi, then we should redirect it to
+                // use whatever the first block advertised as a tail operand.
+                if (m_graph[node.child1()].op() != Phi)
+                    break;
+                
+                NodeIndex atFirstIndex = firstBlock->variablesAtTail.operand(node.local());
+                m_graph.changeEdge(node.children.child1(), Edge(atFirstIndex));
+                break;
+            }
+                
+            default:
+                break;
             }
             
             bool changeRef = node.shouldGenerate();
index 36376ba..2b488cf 100644 (file)
@@ -441,6 +441,31 @@ private:
         return NoNode;
     }
     
+    NodeIndex getLocalLoadElimination(VariableAccessData* variableAccessData)
+    {
+        for (unsigned i = m_indexInBlock; i--;) {
+            NodeIndex index = m_currentBlock->at(i);
+            Node& node = m_graph[index];
+            switch (node.op()) {
+            case GetLocal:
+                if (node.variableAccessData() == variableAccessData)
+                    return index;
+                break;
+                
+            case SetLocal:
+                if (node.variableAccessData() == variableAccessData)
+                    return node.child1().index();
+                break;
+                
+            default:
+                if (m_graph.clobbersWorld(index))
+                    return NoNode;
+                break;
+            }
+        }
+        return NoNode;
+    }
+    
     void performSubstitution(Edge& child, bool addRef = true)
     {
         // Check if this operand is actually unused.
@@ -462,15 +487,15 @@ private:
             m_graph[child].ref();
     }
     
-    void setReplacement(NodeIndex replacement)
+    bool setReplacement(NodeIndex replacement)
     {
         if (replacement == NoNode)
-            return;
+            return false;
         
         // Be safe. Don't try to perform replacements if the predictions don't
         // agree.
         if (m_graph[m_compileIndex].prediction() != m_graph[replacement].prediction())
-            return;
+            return false;
         
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("   Replacing @%u -> @%u", m_compileIndex, replacement);
@@ -482,6 +507,8 @@ private:
         
         // At this point we will eliminate all references to this node.
         m_replacements[m_compileIndex] = replacement;
+        
+        return true;
     }
     
     void eliminate()
@@ -569,6 +596,22 @@ private:
             setReplacement(pureCSE(node));
             break;
             
+        case GetLocal: {
+            VariableAccessData* variableAccessData = node.variableAccessData();
+            if (!variableAccessData->isCaptured())
+                break;
+            NodeIndex possibleReplacement = getLocalLoadElimination(variableAccessData);
+            if (!setReplacement(possibleReplacement))
+                break;
+            NodeIndex oldTailIndex = m_currentBlock->variablesAtTail.operand(
+                variableAccessData->local());
+            if (oldTailIndex == m_compileIndex) {
+                m_currentBlock->variablesAtTail.operand(variableAccessData->local()) =
+                    possibleReplacement;
+            }
+            break;
+        }
+            
         case JSConstant:
             // This is strange, but necessary. Some phases will convert nodes to constants,
             // which may result in duplicated constants. We use CSE to clean this up.
index 450a5d8..910c3d9 100644 (file)
@@ -34,33 +34,56 @@ namespace JSC { namespace DFG {
 
 #if ENABLE(DFG_JIT)
 
-static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID)
+static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, bool result)
 {
+    ASSERT_UNUSED(result, !result);
 #if DFG_ENABLE(DEBUG_VERBOSE)
     dataLog("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
 #else
     UNUSED_PARAM(codeBlock);
     UNUSED_PARAM(opcodeID);
+    UNUSED_PARAM(result);
 #endif
 }
 
-template<bool (*canHandleOpcode)(OpcodeID)>
-bool canHandleOpcodes(CodeBlock* codeBlock)
+static inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel result)
+{
+    ASSERT(result != CanCompile);
+#if DFG_ENABLE(DEBUG_VERBOSE)
+    if (result == CannotCompile)
+        dataLog("Cannot handle code block %p because of opcode %s.\n", codeBlock, opcodeNames[opcodeID]);
+    else {
+        ASSERT(result == ShouldProfile);
+        dataLog("Cannot compile code block %p because of opcode %s, but inlining might be possible.\n", codeBlock, opcodeNames[opcodeID]);
+    }
+#else
+    UNUSED_PARAM(codeBlock);
+    UNUSED_PARAM(opcodeID);
+    UNUSED_PARAM(result);
+#endif
+}
+
+template<typename ReturnType, ReturnType (*canHandleOpcode)(OpcodeID, CodeBlock*, Instruction*)>
+ReturnType canHandleOpcodes(CodeBlock* codeBlock, ReturnType initialValue)
 {
     Interpreter* interpreter = codeBlock->globalData()->interpreter;
     Instruction* instructionsBegin = codeBlock->instructions().begin();
     unsigned instructionCount = codeBlock->instructions().size();
+    ReturnType result = initialValue;
     
     for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
         switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
-#define DEFINE_OP(opcode, length)               \
-        case opcode:                            \
-            if (!canHandleOpcode(opcode)) {     \
-                debugFail(codeBlock, opcode);   \
-                return false;                   \
-            }                                   \
-            bytecodeOffset += length;           \
-            break;
+#define DEFINE_OP(opcode, length) \
+        case opcode: { \
+            ReturnType current = canHandleOpcode( \
+                opcode, codeBlock, instructionsBegin + bytecodeOffset); \
+            if (current < result) { \
+                result = current; \
+                debugFail(codeBlock, opcode, current); \
+            } \
+            bytecodeOffset += length; \
+            break; \
+        }
             FOR_EACH_OPCODE_ID(DEFINE_OP)
 #undef DEFINE_OP
         default:
@@ -69,19 +92,19 @@ bool canHandleOpcodes(CodeBlock* codeBlock)
         }
     }
     
-    return true;
+    return result;
 }
 
-bool canCompileOpcodes(CodeBlock* codeBlock)
+CapabilityLevel canCompileOpcodes(CodeBlock* codeBlock)
 {
     if (!MacroAssembler::supportsFloatingPoint())
-        return false;
-    return canHandleOpcodes<canCompileOpcode>(codeBlock);
+        return CannotCompile;
+    return canHandleOpcodes<CapabilityLevel, canCompileOpcode>(codeBlock, CanCompile);
 }
 
 bool canInlineOpcodes(CodeBlock* codeBlock)
 {
-    return canHandleOpcodes<canInlineOpcode>(codeBlock);
+    return canHandleOpcodes<bool, canInlineOpcode>(codeBlock, true);
 }
 
 #endif
index e04f78c..82ff03d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,6 +27,7 @@
 #define DFGCapabilities_h
 
 #include "Intrinsic.h"
+#include "DFGCommon.h"
 #include "DFGNode.h"
 #include "Executable.h"
 #include "Options.h"
@@ -67,7 +68,7 @@ inline bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
 }
 
 // Opcode checking.
-inline bool canCompileOpcode(OpcodeID opcodeID)
+inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instruction*)
 {
     switch (opcodeID) {
     case op_enter:
@@ -169,14 +170,18 @@ inline bool canCompileOpcode(OpcodeID opcodeID)
     case op_new_func_exp:
     case op_get_argument_by_val:
     case op_get_arguments_length:
-        return true;
+    case op_jneq_ptr:
+        return CanCompile;
         
+    case op_call_varargs:
+        return ShouldProfile;
+
     default:
-        return false;
+        return CannotCompile;
     }
 }
 
-inline bool canInlineOpcode(OpcodeID opcodeID)
+inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc)
 {
     switch (opcodeID) {
         
@@ -194,7 +199,6 @@ inline bool canInlineOpcode(OpcodeID opcodeID)
         
     // Inlining doesn't correctly remap regular expression operands.
     case op_new_regexp:
-        return false;
         
     // We don't support inlining code that creates activations or has nested functions.
     case op_create_activation:
@@ -203,12 +207,17 @@ inline bool canInlineOpcode(OpcodeID opcodeID)
     case op_new_func_exp:
         return false;
         
+    // Inlining supports op_call_varargs if it's a call that just forwards the caller's
+    // arguments.
+    case op_call_varargs:
+        return pc[3].u.operand == codeBlock->argumentsRegister();
+        
     default:
-        return canCompileOpcode(opcodeID);
+        return canCompileOpcode(opcodeID, codeBlock, pc) == CanCompile;
     }
 }
 
-bool canCompileOpcodes(CodeBlock*);
+CapabilityLevel canCompileOpcodes(CodeBlock*);
 bool canInlineOpcodes(CodeBlock*);
 #else // ENABLE(DFG_JIT)
 inline bool mightCompileEval(CodeBlock*) { return false; }
@@ -218,30 +227,42 @@ inline bool mightCompileFunctionForConstruct(CodeBlock*) { return false; }
 inline bool mightInlineFunctionForCall(CodeBlock*) { return false; }
 inline bool mightInlineFunctionForConstruct(CodeBlock*) { return false; }
 
-inline bool canCompileOpcode(OpcodeID) { return false; }
-inline bool canInlineOpcode(OpcodeID) { return false; }
-inline bool canCompileOpcodes(CodeBlock*) { return false; }
+inline CapabilityLevel canCompileOpcode(OpcodeID, CodeBlock*, Instruction*) { return false; }
+inline bool canInlineOpcode(OpcodeID, CodeBlock*, Instruction*) { return false; }
+inline CapabilityLevel canCompileOpcodes(CodeBlock*) { return false; }
 inline bool canInlineOpcodes(CodeBlock*) { return false; }
 #endif // ENABLE(DFG_JIT)
 
-inline bool canCompileEval(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileEval(CodeBlock* codeBlock)
 {
-    return mightCompileEval(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileEval(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileProgram(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileProgram(CodeBlock* codeBlock)
 {
-    return mightCompileProgram(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileProgram(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileFunctionForCall(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileFunctionForCall(CodeBlock* codeBlock)
 {
-    return mightCompileFunctionForCall(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileFunctionForCall(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
-inline bool canCompileFunctionForConstruct(CodeBlock* codeBlock)
+inline CapabilityLevel canCompileFunctionForConstruct(CodeBlock* codeBlock)
 {
-    return mightCompileFunctionForConstruct(codeBlock) && canCompileOpcodes(codeBlock);
+    if (!mightCompileFunctionForConstruct(codeBlock))
+        return CannotCompile;
+    
+    return canCompileOpcodes(codeBlock);
 }
 
 inline bool canInlineFunctionForCall(CodeBlock* codeBlock)
index c4373d7..c06147b 100644 (file)
@@ -130,6 +130,8 @@ enum SpillRegistersMode { NeedToSpill, DontSpill };
 
 enum NoResultTag { NoResult };
 
+enum CapabilityLevel { CannotCompile, ShouldProfile, CanCompile, CapabilityLevelNotSet };
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index f0b5c6d..ba07488 100644 (file)
@@ -169,7 +169,8 @@ void Graph::dump(NodeIndex nodeIndex)
             dataLog("%s@%u%s",
                     useKindToString(m_varArgChildren[childIdx].useKind()),
                     m_varArgChildren[childIdx].index(),
-                    predictionToAbbreviatedString(at(childIdx).prediction()));
+                    predictionToAbbreviatedString(
+                        at(m_varArgChildren[childIdx]).prediction()));
         }
     } else {
         if (!!node.child1()) {
index 9c6758a..88982b5 100644 (file)
@@ -197,6 +197,7 @@ namespace JSC { namespace DFG {
     macro(TearOffArguments, NodeMustGenerate) \
     macro(GetMyArgumentsLength, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
     macro(GetMyArgumentByVal, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
+    macro(CheckArgumentsNotCreated, NodeMustGenerate) \
     \
     /* Nodes for creating functions. */\
     macro(NewFunctionNoCheck, NodeResultJS) \
index eeb2ee6..dcb8e94 100644 (file)
@@ -663,6 +663,7 @@ private:
         case TearOffActivation:
         case TearOffArguments:
         case CheckNumber:
+        case CheckArgumentsNotCreated:
             changed |= mergeDefaultFlags(node);
             break;
             
index 5c5d582..648e114 100644 (file)
@@ -3830,6 +3830,19 @@ void SpeculativeJIT::compile(Node& node)
         break;
     }
         
+    case CheckArgumentsNotCreated: {
+        // FIXME: We should have a way to count such failures. This will be part of
+        // https://bugs.webkit.org/show_bug.cgi?id=86327
+        speculationCheck(
+            Uncountable, JSValueRegs(), NoNode,
+            m_jit.branch32(
+                JITCompiler::NotEqual,
+                JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+                TrustedImm32(JSValue::EmptyValueTag)));
+        noResult(m_compileIndex);
+        break;
+    }
+        
     case GetMyArgumentsLength: {
         GPRTemporary resultPayload(this);
         GPRTemporary resultTag(this);
index 7f6b631..d356840 100644 (file)
@@ -964,8 +964,8 @@ void SpeculativeJIT::emitCall(Node& node)
     GPRReg calleeGPR = callee.gpr();
     use(calleeEdge);
     
-    // The call instruction's first child is either the function (normal call) or the
-    // receiver (method call). subsequent children are the arguments.
+    // The call instruction's first child is the function; the subsequent children are the
+    // arguments.
     int numPassedArgs = node.numChildren() - 1;
     
     m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs + dummyThisArgument), callFramePayloadSlot(RegisterFile::ArgumentCount));
@@ -3846,6 +3846,19 @@ void SpeculativeJIT::compile(Node& node)
         break;
     }
         
+    case CheckArgumentsNotCreated: {
+        // FIXME: We should have a way to count such failures. This will be part of
+        // https://bugs.webkit.org/show_bug.cgi?id=86327
+        speculationCheck(
+            Uncountable, JSValueRegs(), NoNode,
+            m_jit.branchTestPtr(
+                JITCompiler::NonZero,
+                JITCompiler::addressFor(
+                    m_jit.argumentsRegisterFor(node.codeOrigin))));
+        noResult(m_compileIndex);
+        break;
+    }
+        
     case GetMyArgumentsLength: {
         GPRTemporary result(this);
         GPRReg resultGPR = result.gpr();
index 6f7e0df..2b26123 100644 (file)
@@ -69,6 +69,8 @@ public:
         } \
     } while (0)
 
+    #define notSet (static_cast<size_t>(-1))
+
     void validate()
     {
         // NB. This code is not written for performance, since it is not intended to run
@@ -202,6 +204,22 @@ public:
                 }
             }
             
+            Operands<size_t> getLocalPositions(
+                block->variablesAtHead.numberOfArguments(),
+                block->variablesAtHead.numberOfLocals());
+            Operands<size_t> setLocalPositions(
+                block->variablesAtHead.numberOfArguments(),
+                block->variablesAtHead.numberOfLocals());
+            
+            for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
+                getLocalPositions.argument(i) = notSet;
+                setLocalPositions.argument(i) = notSet;
+            }
+            for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
+                getLocalPositions.local(i) = notSet;
+                setLocalPositions.local(i) = notSet;
+            }
+            
             for (size_t i = 0; i < block->size(); ++i) {
                 NodeIndex nodeIndex = block->at(i);
                 Node& node = m_graph[nodeIndex];
@@ -213,6 +231,37 @@ public:
                         continue;
                     VALIDATE((nodeIndex, edge), nodesInThisBlock.get(nodeIndex));
                 }
+                
+                if (!node.shouldGenerate())
+                    continue;
+                switch (node.op()) {
+                case GetLocal:
+                    if (node.variableAccessData()->isCaptured())
+                        break;
+                    VALIDATE((nodeIndex, blockIndex), getLocalPositions.operand(node.local()) == notSet);
+                    getLocalPositions.operand(node.local()) = i;
+                    break;
+                case SetLocal:
+                    if (node.variableAccessData()->isCaptured())
+                        break;
+                    // Only record the first SetLocal. There may be multiple SetLocals
+                    // because of flushing.
+                    if (setLocalPositions.operand(node.local()) != notSet)
+                        break;
+                    setLocalPositions.operand(node.local()) = i;
+                    break;
+                default:
+                    break;
+                }
+            }
+            
+            for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
+                checkOperand(
+                    blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i));
+            }
+            for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
+                checkOperand(
+                    blockIndex, getLocalPositions, setLocalPositions, i);
             }
         }
     }
@@ -221,6 +270,24 @@ private:
     Graph& m_graph;
     GraphDumpMode m_graphDumpMode;
     
+    void checkOperand(
+        BlockIndex blockIndex, Operands<size_t>& getLocalPositions,
+        Operands<size_t>& setLocalPositions, int operand)
+    {
+        if (getLocalPositions.operand(operand) == notSet)
+            return;
+        if (setLocalPositions.operand(operand) == notSet)
+            return;
+        
+        BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+        
+        VALIDATE(
+            (block->at(getLocalPositions.operand(operand)),
+             block->at(setLocalPositions.operand(operand)),
+             blockIndex),
+            getLocalPositions.operand(operand) < setLocalPositions.operand(operand));
+    }
+    
     void reportValidationContext(NodeIndex nodeIndex)
     {
         dataLog("@%u", nodeIndex);
@@ -256,6 +323,12 @@ private:
     }
     
     void reportValidationContext(
+        NodeIndex nodeIndex, NodeIndex nodeIndex2, BlockIndex blockIndex)
+    {
+        dataLog("@%u and @%u in Block #%u", nodeIndex, nodeIndex2, blockIndex);
+    }
+    
+    void reportValidationContext(
         NodeIndex nodeIndex, BlockIndex blockIndex, NodeIndex expectedNodeIndex, Edge incomingEdge)
     {
         dataLog("@%u in Block #%u, searching for @%u from @%u", nodeIndex, blockIndex, expectedNodeIndex, incomingEdge.index());
index c2aec54..ff5615f 100644 (file)
@@ -96,7 +96,7 @@ JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock)
 #if ENABLE(DFG_JIT)
 void JIT::emitOptimizationCheck(OptimizationCheckKind kind)
 {
-    if (!shouldEmitProfiling())
+    if (!canBeOptimized())
         return;
     
     Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop : Options::executionCounterIncrementForReturn), AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter()));
@@ -417,7 +417,7 @@ void JIT::privateCompileSlowCases()
         
 #if ENABLE(VALUE_PROFILER)
         RareCaseProfile* rareCaseProfile = 0;
-        if (m_canBeOptimized)
+        if (shouldEmitProfiling())
             rareCaseProfile = m_codeBlock->addRareCaseProfile(m_bytecodeOffset);
 #endif
 
@@ -497,7 +497,7 @@ void JIT::privateCompileSlowCases()
         ASSERT_WITH_MESSAGE(firstTo == (iter - 1)->to, "Too many jumps linked in slow case codegen.");
         
 #if ENABLE(VALUE_PROFILER)
-        if (m_canBeOptimized)
+        if (shouldEmitProfiling())
             add32(TrustedImm32(1), AbsoluteAddress(&rareCaseProfile->m_counter));
 #endif
 
@@ -565,7 +565,24 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
 #endif
     
 #if ENABLE(VALUE_PROFILER)
-    m_canBeOptimized = m_codeBlock->canCompileWithDFG();
+    DFG::CapabilityLevel level = m_codeBlock->canCompileWithDFG();
+    switch (level) {
+    case DFG::CannotCompile:
+        m_canBeOptimized = false;
+        m_shouldEmitProfiling = false;
+        break;
+    case DFG::ShouldProfile:
+        m_canBeOptimized = false;
+        m_shouldEmitProfiling = true;
+        break;
+    case DFG::CanCompile:
+        m_canBeOptimized = true;
+        m_shouldEmitProfiling = true;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
 #endif
 
     // Just add a little bit of randomness to the codegen
@@ -619,7 +636,7 @@ JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffo
     Label functionBody = label();
     
 #if ENABLE(VALUE_PROFILER)
-    if (m_canBeOptimized)
+    if (canBeOptimized())
         add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->m_executionEntryCount));
 #endif
 
index 6dc0137..d114310 100644 (file)
@@ -836,7 +836,7 @@ namespace JSC {
 
 #if ENABLE(DFG_JIT)
         bool canBeOptimized() { return m_canBeOptimized; }
-        bool shouldEmitProfiling() { return m_canBeOptimized; }
+        bool shouldEmitProfiling() { return m_shouldEmitProfiling; }
 #else
         bool canBeOptimized() { return false; }
         // Enables use of value profiler with tiered compilation turned off,
@@ -885,6 +885,7 @@ namespace JSC {
 
 #if ENABLE(VALUE_PROFILER)
         bool m_canBeOptimized;
+        bool m_shouldEmitProfiling;
 #endif
     } JIT_CLASS_ALIGNMENT;
 
index a9390e3..b66e2cd 100644 (file)
@@ -818,7 +818,7 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsign
     else {
         ASSERT(opcodeID == op_mul);
 #if ENABLE(VALUE_PROFILER)
-        if (m_canBeOptimized) {
+        if (shouldEmitProfiling()) {
             // We want to be able to measure if this is taking the slow case just
             // because of negative zero. If this produces positive zero, then we
             // don't want the slow case to be taken because that will throw off
index 8c7148c..5d39735 100644 (file)
@@ -513,7 +513,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
     // If we succeed in all of our checks, and the code was optimizable, then make sure we
     // decrement the rare case counter.
 #if ENABLE(VALUE_PROFILER)
-    if (m_codeBlock->canCompileWithDFG()) {
+    if (m_codeBlock->canCompileWithDFG() >= DFG::ShouldProfile) {
         sub32(
             TrustedImm32(1),
             AbsoluteAddress(&m_codeBlock->rareCaseProfileForBytecodeOffset(stubInfo->bytecodeIndex)->m_counter));
index 550ad0b..bd57484 100644 (file)
@@ -479,7 +479,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
     // If we succeed in all of our checks, and the code was optimizable, then make sure we
     // decrement the rare case counter.
 #if ENABLE(VALUE_PROFILER)
-    if (m_codeBlock->canCompileWithDFG()) {
+    if (m_codeBlock->canCompileWithDFG() >= DFG::ShouldProfile) {
         sub32(
             TrustedImm32(1),
             AbsoluteAddress(&m_codeBlock->rareCaseProfileForBytecodeOffset(stubInfo->bytecodeIndex)->m_counter));
index beed4b2..0020c72 100644 (file)
@@ -107,7 +107,7 @@ void CodeProfile::sample(void* pc, void** framePointer)
             CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID);
             if (codeBlock->getJITType() == JITCode::DFGJIT)
                 type = DFGJIT;
-            else if (codeBlock->canCompileWithDFGState() == CodeBlock::CompileWithDFGFalse)
+            else if (codeBlock->canCompileWithDFGState() != DFG::CanCompile)
                 type = BaselineOnly;
             else if (codeBlock->replacement())
                 type = BaselineOSR;