Title: [138737] trunk/Source
Revision
138737
Author
[email protected]
Date
2013-01-03 14:04:39 -0800 (Thu, 03 Jan 2013)

Log Message

CallLinkStatus should be aware of closure calls, and the DFG bytecode parser should use that as its sole internal notion of how to optimize calls
https://bugs.webkit.org/show_bug.cgi?id=106027

Source/_javascript_Core: 

Reviewed by Mark Hahnenberg.
        
Previously, the DFG bytecode parser had its own internal notion of exactly what CallLinkStatus was
meant to do, in the form of a CallType, expectedFunction, intrinsic, etc. This change makes CallLinkStatus
smart enough to do all of that, and also gives it the ability to understand closure calls.

* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::CallLinkStatus):
(JSC):
(JSC::CallLinkStatus::function):
(JSC::CallLinkStatus::internalFunction):
(JSC::CallLinkStatus::intrinsicFor):
(JSC::CallLinkStatus::setIsProved):
(JSC::CallLinkStatus::computeFromLLInt):
(JSC::CallLinkStatus::computeFor):
(JSC::CallLinkStatus::dump):
* bytecode/CallLinkStatus.h:
(JSC):
(JSC::CallLinkStatus::CallLinkStatus):
(CallLinkStatus):
(JSC::CallLinkStatus::takesSlowPath):
(JSC::CallLinkStatus::isSet):
(JSC::CallLinkStatus::isClosureCall):
(JSC::CallLinkStatus::callTarget):
(JSC::CallLinkStatus::executable):
(JSC::CallLinkStatus::structure):
(JSC::CallLinkStatus::isProved):
(JSC::CallLinkStatus::canOptimize):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleCall):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::valueOfFunctionConstant):

Source/WTF: 

Reviewed by Mark Hahnenberg.
        
I got tired of the various idioms for printing a list of things with comma in between, so I wrote a helper.

* WTF.xcodeproj/project.pbxproj:
* wtf/CommaPrinter.h: Added.
(WTF):
(CommaPrinter):
(WTF::CommaPrinter::CommaPrinter):
(WTF::CommaPrinter::dump):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (138736 => 138737)


--- trunk/Source/_javascript_Core/ChangeLog	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-01-03 22:04:39 UTC (rev 138737)
@@ -1,3 +1,41 @@
+2013-01-03  Filip Pizlo  <[email protected]>
+
+        CallLinkStatus should be aware of closure calls, and the DFG bytecode parser should use that as its sole internal notion of how to optimize calls
+        https://bugs.webkit.org/show_bug.cgi?id=106027
+
+        Reviewed by Mark Hahnenberg.
+        
+        Previously, the DFG bytecode parser had its own internal notion of exactly what CallLinkStatus was
+        meant to do, in the form of a CallType, expectedFunction, intrinsic, etc. This change makes CallLinkStatus
+        smart enough to do all of that, and also gives it the ability to understand closure calls.
+
+        * bytecode/CallLinkStatus.cpp:
+        (JSC::CallLinkStatus::CallLinkStatus):
+        (JSC):
+        (JSC::CallLinkStatus::function):
+        (JSC::CallLinkStatus::internalFunction):
+        (JSC::CallLinkStatus::intrinsicFor):
+        (JSC::CallLinkStatus::setIsProved):
+        (JSC::CallLinkStatus::computeFromLLInt):
+        (JSC::CallLinkStatus::computeFor):
+        (JSC::CallLinkStatus::dump):
+        * bytecode/CallLinkStatus.h:
+        (JSC):
+        (JSC::CallLinkStatus::CallLinkStatus):
+        (CallLinkStatus):
+        (JSC::CallLinkStatus::takesSlowPath):
+        (JSC::CallLinkStatus::isSet):
+        (JSC::CallLinkStatus::isClosureCall):
+        (JSC::CallLinkStatus::callTarget):
+        (JSC::CallLinkStatus::executable):
+        (JSC::CallLinkStatus::structure):
+        (JSC::CallLinkStatus::isProved):
+        (JSC::CallLinkStatus::canOptimize):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleCall):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::valueOfFunctionConstant):
+
 2013-01-02  Simon Hausmann  <[email protected]>
 
         [MinGW-w64] Centralize workaround for pow() implementation

Modified: trunk/Source/_javascript_Core/bytecode/CallLinkStatus.cpp (138736 => 138737)


--- trunk/Source/_javascript_Core/bytecode/CallLinkStatus.cpp	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/_javascript_Core/bytecode/CallLinkStatus.cpp	2013-01-03 22:04:39 UTC (rev 138737)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,9 +28,64 @@
 
 #include "CodeBlock.h"
 #include "LLIntCallLinkInfo.h"
+#include <wtf/CommaPrinter.h>
 
 namespace JSC {
 
+CallLinkStatus::CallLinkStatus(JSValue value)
+    : m_callTarget(value)
+    , m_executable(0)
+    , m_structure(0)
+    , m_couldTakeSlowPath(false)
+    , m_isProved(false)
+{
+    if (!value || !value.isCell())
+        return;
+    
+    m_structure = value.asCell()->structure();
+    
+    if (!value.asCell()->inherits(&JSFunction::s_info))
+        return;
+    
+    m_executable = jsCast<JSFunction*>(value.asCell())->executable();
+}
+
+JSFunction* CallLinkStatus::function() const
+{
+    if (!m_callTarget || !m_callTarget.isCell())
+        return 0;
+    
+    if (!m_callTarget.asCell()->inherits(&JSFunction::s_info))
+        return 0;
+    
+    return jsCast<JSFunction*>(m_callTarget.asCell());
+}
+
+InternalFunction* CallLinkStatus::internalFunction() const
+{
+    if (!m_callTarget || !m_callTarget.isCell())
+        return 0;
+    
+    if (!m_callTarget.asCell()->inherits(&InternalFunction::s_info))
+        return 0;
+    
+    return jsCast<InternalFunction*>(m_callTarget.asCell());
+}
+
+Intrinsic CallLinkStatus::intrinsicFor(CodeSpecializationKind kind) const
+{
+    if (!m_executable)
+        return NoIntrinsic;
+    
+    return m_executable->intrinsicFor(kind);
+}
+
+CallLinkStatus& CallLinkStatus::setIsProved(bool isProved)
+{
+    m_isProved = isProved;
+    return *this;
+}
+
 CallLinkStatus CallLinkStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex)
 {
     UNUSED_PARAM(profiledBlock);
@@ -39,9 +94,9 @@
     Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex;
     LLIntCallLinkInfo* callLinkInfo = instruction[4].u.callLinkInfo;
     
-    return CallLinkStatus(callLinkInfo->lastSeenCallee.get(), false, false);
+    return CallLinkStatus(callLinkInfo->lastSeenCallee.get());
 #else
-    return CallLinkStatus(0, false, false);
+    return CallLinkStatus();
 #endif
 }
 
@@ -54,18 +109,44 @@
         return computeFromLLInt(profiledBlock, bytecodeIndex);
     
     if (profiledBlock->couldTakeSlowCase(bytecodeIndex))
-        return CallLinkStatus(0, true);
+        return CallLinkStatus::takesSlowPath();
     
     CallLinkInfo& callLinkInfo = profiledBlock->getCallLinkInfo(bytecodeIndex);
+    if (callLinkInfo.stub)
+        return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure());
+    
     JSFunction* target = callLinkInfo.lastSeenCallee.get();
     if (!target)
         return computeFromLLInt(profiledBlock, bytecodeIndex);
-    
-    return CallLinkStatus(target, false, !!callLinkInfo.stub);
+
+    return CallLinkStatus(target);
 #else
-    return CallLinkStatus(0, false, false);
+    return CallLinkStatus();
 #endif
 }
 
+void CallLinkStatus::dump(PrintStream& out)
+{
+    if (!isSet()) {
+        out.print("Not Set");
+        return;
+    }
+    
+    CommaPrinter comma;
+    
+    if (m_isProved)
+        out.print(comma, "Statically Proved");
+    
+    if (m_couldTakeSlowPath)
+        out.print(comma, "Could Take Slow Path");
+    
+    if (m_callTarget)
+        out.print(comma, "Known target: ", m_callTarget);
+    
+    ASSERT(!!m_executable == !!m_structure);
+    if (m_executable)
+        out.print(comma, "Executable/CallHash/Structure: ", RawPointer(m_executable), "/", m_executable->hashFor(CodeForCall), "/", RawPointer(m_structure));
+}
+
 } // namespace JSC
 

Modified: trunk/Source/_javascript_Core/bytecode/CallLinkStatus.h (138736 => 138737)


--- trunk/Source/_javascript_Core/bytecode/CallLinkStatus.h	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/_javascript_Core/bytecode/CallLinkStatus.h	2013-01-03 22:04:39 UTC (rev 138737)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,44 +26,75 @@
 #ifndef CallLinkStatus_h
 #define CallLinkStatus_h
 
+#include "CodeSpecializationKind.h"
+#include "Intrinsic.h"
+#include "JSValue.h"
+
 namespace JSC {
 
+class CodeBlock;
+class ExecutableBase;
+class InternalFunction;
 class JSFunction;
-class CodeBlock;
+class Structure;
 
 class CallLinkStatus {
 public:
     CallLinkStatus()
-        : m_callTarget(0)
+        : m_executable(0)
+        , m_structure(0)
         , m_couldTakeSlowPath(false)
-        , m_isClosureCall(false)
+        , m_isProved(false)
     {
     }
     
-    CallLinkStatus(JSFunction* callTarget, bool couldTakeSlowPath, bool isClosureCall = false)
-        : m_callTarget(callTarget)
-        , m_couldTakeSlowPath(couldTakeSlowPath)
-        , m_isClosureCall(isClosureCall)
+    static CallLinkStatus takesSlowPath()
     {
+        CallLinkStatus result;
+        result.m_couldTakeSlowPath = true;
+        return result;
     }
     
+    explicit CallLinkStatus(JSValue);
+    
+    CallLinkStatus(ExecutableBase* executable, Structure* structure)
+        : m_executable(executable)
+        , m_structure(structure)
+        , m_couldTakeSlowPath(false)
+        , m_isProved(false)
+    {
+    }
+    
+    CallLinkStatus& setIsProved(bool);
+    
     static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex);
     
-    bool isSet() const { return !!m_callTarget || m_couldTakeSlowPath; }
+    bool isSet() const { return m_callTarget || m_executable || m_couldTakeSlowPath; }
     
     bool operator!() const { return !isSet(); }
     
     bool couldTakeSlowPath() const { return m_couldTakeSlowPath; }
-    bool isClosureCall() const { return m_isClosureCall; }
+    bool isClosureCall() const { return !m_callTarget; }
     
-    JSFunction* callTarget() const { return m_callTarget; }
+    JSValue callTarget() const { return m_callTarget; }
+    JSFunction* function() const;
+    InternalFunction* internalFunction() const;
+    Intrinsic intrinsicFor(CodeSpecializationKind) const;
+    ExecutableBase* executable() const { return m_executable; }
+    Structure* structure() const { return m_structure; }
+    bool isProved() const { return m_isProved; }
+    bool canOptimize() const { return (m_callTarget || m_executable) && !m_couldTakeSlowPath; }
     
+    void dump(PrintStream&);
+    
 private:
     static CallLinkStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex);
     
-    JSFunction* m_callTarget;
+    JSValue m_callTarget;
+    ExecutableBase* m_executable;
+    Structure* m_structure;
     bool m_couldTakeSlowPath;
-    bool m_isClosureCall;
+    bool m_isProved;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (138736 => 138737)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2013-01-03 22:04:39 UTC (rev 138737)
@@ -1283,115 +1283,78 @@
     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
     
     NodeIndex callTarget = get(currentInstruction[1].u.operand);
-    enum {
-        ConstantFunction,
-        ConstantInternalFunction,
-        LinkedFunction,
-        UnknownFunction
-    } callType;
-            
-    CallLinkStatus callLinkStatus = CallLinkStatus::computeFor(
-        m_inlineStackTop->m_profiledBlock, m_currentIndex);
     
-#if DFG_ENABLE(DEBUG_VERBOSE)
-    dataLogF("For call at @%lu bc#%u: ", m_graph.size(), m_currentIndex);
-    if (callLinkStatus.isSet()) {
-        if (callLinkStatus.couldTakeSlowPath())
-            dataLogF("could take slow path, ");
-        dataLogF("target = %p\n", callLinkStatus.callTarget());
-    } else
-        dataLogF("not set.\n");
-#endif
+    CallLinkStatus callLinkStatus;
+
+    if (m_graph.isConstant(callTarget))
+        callLinkStatus = CallLinkStatus(m_graph.valueOfJSConstant(callTarget)).setIsProved(true);
+    else
+        callLinkStatus = CallLinkStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_currentIndex);
     
-    if (m_graph.isFunctionConstant(callTarget)) {
-        callType = ConstantFunction;
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Call at [@%lu, bc#%u] has a function constant: %p, exec %p.\n",
-                m_graph.size(), m_currentIndex,
-                m_graph.valueOfFunctionConstant(callTarget),
-                m_graph.valueOfFunctionConstant(callTarget)->executable());
+    dataLog("For call at @", m_graph.size(), " bc#", m_currentIndex, ": ", callLinkStatus, "\n");
 #endif
-    } else if (m_graph.isInternalFunctionConstant(callTarget)) {
-        callType = ConstantInternalFunction;
-#if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Call at [@%lu, bc#%u] has an internal function constant: %p.\n",
-                m_graph.size(), m_currentIndex,
-                m_graph.valueOfInternalFunctionConstant(callTarget));
-#endif
-    } else if (callLinkStatus.isSet() && !callLinkStatus.couldTakeSlowPath()
-               && !callLinkStatus.isClosureCall() // We will eventually optimize this, I promise.
-               && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) {
-        callType = LinkedFunction;
-#if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Call at [@%lu, bc#%u] is linked to: %p, exec %p.\n",
-                m_graph.size(), m_currentIndex, callLinkStatus.callTarget(),
-                callLinkStatus.callTarget()->executable());
-#endif
-    } else {
-        callType = UnknownFunction;
-#if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Call at [@%lu, bc#%u] is has an unknown or ambiguous target.\n",
-                m_graph.size(), m_currentIndex);
-#endif
+    
+    if (!callLinkStatus.canOptimize()) {
+        // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically
+        // that we cannot optimize them.
+        
+        addCall(interpreter, currentInstruction, op);
+        return;
     }
-    if (callType != UnknownFunction) {
-        int argumentCountIncludingThis = currentInstruction[2].u.operand;
-        int registerOffset = currentInstruction[3].u.operand;
+    
+    int argumentCountIncludingThis = currentInstruction[2].u.operand;
+    int registerOffset = currentInstruction[3].u.operand;
 
-        // Do we have a result?
-        bool usesResult = false;
-        int resultOperand = 0; // make compiler happy
-        unsigned nextOffset = m_currentIndex + OPCODE_LENGTH(op_call);
-        Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call);
-        SpeculatedType prediction = SpecNone;
-        if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
-            resultOperand = putInstruction[1].u.operand;
-            usesResult = true;
-            m_currentProfilingIndex = nextOffset;
-            prediction = getPrediction();
-            nextOffset += OPCODE_LENGTH(op_call_put_result);
-        }
+    // Do we have a result?
+    bool usesResult = false;
+    int resultOperand = 0; // make compiler happy
+    unsigned nextOffset = m_currentIndex + OPCODE_LENGTH(op_call);
+    Instruction* putInstruction = currentInstruction + OPCODE_LENGTH(op_call);
+    SpeculatedType prediction = SpecNone;
+    if (interpreter->getOpcodeID(putInstruction->u.opcode) == op_call_put_result) {
+        resultOperand = putInstruction[1].u.operand;
+        usesResult = true;
+        m_currentProfilingIndex = nextOffset;
+        prediction = getPrediction();
+        nextOffset += OPCODE_LENGTH(op_call_put_result);
+    }
 
-        if (callType == ConstantInternalFunction) {
-            if (handleConstantInternalFunction(usesResult, resultOperand, m_graph.valueOfInternalFunctionConstant(callTarget), registerOffset, argumentCountIncludingThis, prediction, kind))
-                return;
-            
-            // Can only handle this using the generic call handler.
-            addCall(interpreter, currentInstruction, op);
+    if (InternalFunction* function = callLinkStatus.internalFunction()) {
+        if (handleConstantInternalFunction(usesResult, resultOperand, function, registerOffset, argumentCountIncludingThis, prediction, kind))
             return;
-        }
+            
+        // Can only handle this using the generic call handler.
+        addCall(interpreter, currentInstruction, op);
+        return;
+    }
         
-        JSFunction* expectedFunction;
-        Intrinsic intrinsic;
-        bool certainAboutExpectedFunction;
-        if (callType == ConstantFunction) {
-            expectedFunction = m_graph.valueOfFunctionConstant(callTarget);
-            intrinsic = expectedFunction->executable()->intrinsicFor(kind);
-            certainAboutExpectedFunction = true;
-        } else {
-            ASSERT(callType == LinkedFunction);
-            expectedFunction = callLinkStatus.callTarget();
-            intrinsic = expectedFunction->executable()->intrinsicFor(kind);
-            certainAboutExpectedFunction = false;
-        }
-                
-        if (intrinsic != NoIntrinsic) {
-            if (!certainAboutExpectedFunction)
-                emitFunctionCheck(expectedFunction, callTarget, registerOffset, kind);
+    JSFunction* expectedFunction = callLinkStatus.function();
+    if (!expectedFunction) {
+        // For now we have no way of reasoning about what it means to not have a specific function. This will
+        // change soon, though.
+        
+        addCall(interpreter, currentInstruction, op);
+        return;
+    }
+        
+    Intrinsic intrinsic = callLinkStatus.intrinsicFor(kind);
+    if (intrinsic != NoIntrinsic) {
+        if (!callLinkStatus.isProved())
+            emitFunctionCheck(expectedFunction, callTarget, registerOffset, kind);
             
-            if (handleIntrinsic(usesResult, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
-                if (!certainAboutExpectedFunction) {
-                    // Need to keep the call target alive for OSR. We could easily optimize this out if we wanted
-                    // to, since at this point we know that the call target is a constant. It's just that OSR isn't
-                    // smart enough to figure that out, since it doesn't understand CheckFunction.
-                    addToGraph(Phantom, callTarget);
-                }
-                
-                return;
+        if (handleIntrinsic(usesResult, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
+            if (!callLinkStatus.isProved()) {
+                // Need to keep the call target alive for OSR. We could easily optimize this out if we wanted
+                // to, since at this point we know that the call target is a constant. It's just that OSR isn't
+                // smart enough to figure that out, since it doesn't understand CheckFunction.
+                addToGraph(Phantom, callTarget);
             }
-        } else if (handleInlining(usesResult, callTarget, resultOperand, certainAboutExpectedFunction, expectedFunction, registerOffset, argumentCountIncludingThis, nextOffset, kind))
+                
             return;
-    }
+        }
+    } else if (handleInlining(usesResult, callTarget, resultOperand, callLinkStatus.isProved(), expectedFunction, registerOffset, argumentCountIncludingThis, nextOffset, kind))
+        return;
     
     addCall(interpreter, currentInstruction, op);
 }

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (138736 => 138737)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2013-01-03 22:04:39 UTC (rev 138737)
@@ -331,10 +331,6 @@
         ASSERT(function);
         return jsCast<JSFunction*>(function);
     }
-    InternalFunction* valueOfInternalFunctionConstant(NodeIndex nodeIndex)
-    {
-        return jsCast<InternalFunction*>(valueOfJSConstant(nodeIndex).asCell());
-    }
 
     static const char *opName(NodeType);
     

Modified: trunk/Source/WTF/ChangeLog (138736 => 138737)


--- trunk/Source/WTF/ChangeLog	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/WTF/ChangeLog	2013-01-03 22:04:39 UTC (rev 138737)
@@ -1,3 +1,19 @@
+2013-01-03  Filip Pizlo  <[email protected]>
+
+        CallLinkStatus should be aware of closure calls, and the DFG bytecode parser should use that as its sole internal notion of how to optimize calls
+        https://bugs.webkit.org/show_bug.cgi?id=106027
+
+        Reviewed by Mark Hahnenberg.
+        
+        I got tired of the various idioms for printing a list of things with comma in between, so I wrote a helper.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CommaPrinter.h: Added.
+        (WTF):
+        (CommaPrinter):
+        (WTF::CommaPrinter::CommaPrinter):
+        (WTF::CommaPrinter::dump):
+
 2013-01-02  Simon Hausmann  <[email protected]>
 
         [MinGW-w64] Centralize workaround for pow() implementation

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (138736 => 138737)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2013-01-03 21:51:08 UTC (rev 138736)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2013-01-03 22:04:39 UTC (rev 138737)
@@ -26,6 +26,7 @@
 		0F9D3361165DBA73005AD387 /* FilePrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D335C165DBA73005AD387 /* FilePrintStream.h */; };
 		0F9D3362165DBA73005AD387 /* PrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D335D165DBA73005AD387 /* PrintStream.cpp */; };
 		0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D335E165DBA73005AD387 /* PrintStream.h */; };
+		0FC4EDE61696149600F65041 /* CommaPrinter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC4EDE51696149600F65041 /* CommaPrinter.h */; };
 		0FD81AC5154FB22E00983E72 /* FastBitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD81AC4154FB22E00983E72 /* FastBitVector.h */; settings = {ATTRIBUTES = (); }; };
 		0FDDBFA71666DFA300C55FEF /* StringPrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */; };
 		0FDDBFA81666DFA300C55FEF /* StringPrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */; };
@@ -326,6 +327,7 @@
 		0F9D335C165DBA73005AD387 /* FilePrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilePrintStream.h; sourceTree = "<group>"; };
 		0F9D335D165DBA73005AD387 /* PrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrintStream.cpp; sourceTree = "<group>"; };
 		0F9D335E165DBA73005AD387 /* PrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrintStream.h; sourceTree = "<group>"; };
+		0FC4EDE51696149600F65041 /* CommaPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommaPrinter.h; sourceTree = "<group>"; };
 		0FD81AC4154FB22E00983E72 /* FastBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastBitVector.h; sourceTree = "<group>"; };
 		0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringPrintStream.cpp; sourceTree = "<group>"; };
 		0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringPrintStream.h; sourceTree = "<group>"; };
@@ -699,6 +701,7 @@
 				EB95E1EF161A72410089A2F5 /* ByteOrder.h */,
 				A8A4726A151A825A004123FF /* CheckedArithmetic.h */,
 				A8A4726B151A825A004123FF /* CheckedBoolean.h */,
+				0FC4EDE51696149600F65041 /* CommaPrinter.h */,
 				A8A47270151A825A004123FF /* Compiler.h */,
 				A8A47271151A825A004123FF /* Complex.h */,
 				A8A47273151A825A004123FF /* CryptographicallyRandomNumber.cpp */,
@@ -1248,6 +1251,7 @@
 				0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */,
 				0F87105A16643F190090B0AD /* RawPointer.h in Headers */,
 				0FDDBFA81666DFA300C55FEF /* StringPrintStream.h in Headers */,
+				0FC4EDE61696149600F65041 /* CommaPrinter.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

Added: trunk/Source/WTF/wtf/CommaPrinter.h (0 => 138737)


--- trunk/Source/WTF/wtf/CommaPrinter.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/CommaPrinter.h	2013-01-03 22:04:39 UTC (rev 138737)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef CommaPrinter_h
+#define CommaPrinter_h
+
+#include "PrintStream.h"
+
+namespace WTF {
+
+class CommaPrinter {
+public:
+    CommaPrinter(const char* comma = ", ")
+        : m_comma(comma)
+        , m_isFirst(true)
+    {
+    }
+    
+    void dump(PrintStream& out) const
+    {
+        if (m_isFirst) {
+            m_isFirst = false;
+            return;
+        }
+        
+        out.print(m_comma);
+    }
+    
+private:
+    const char* m_comma;
+    mutable bool m_isFirst;
+};
+
+} // namespace WTF
+
+using WTF::CommaPrinter;
+
+#endif // CommaPrinter_h
+
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to