SpeculatedType dumping should not use the static char buffer[thingy] idiom
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Nov 2012 06:01:40 +0000 (06:01 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Nov 2012 06:01:40 +0000 (06:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=103584

Reviewed by Michael Saboff.

Source/JavaScriptCore:

Changed SpeculatedType to be "dumpable" by saying things like:

dataLog("thingy = ", SpeculationDump(thingy))

Removed the old stringification functions, and changed all code that referred to them
to use the new dataLog()/print() style.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::dumpSpeculationAbbreviated):
* bytecode/SpeculatedType.h:
* bytecode/ValueProfile.h:
(JSC::ValueProfileBase::dump):
* bytecode/VirtualRegister.h:
(WTF::printInternal):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::dump):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::predictArgumentTypes):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGStructureAbstractValue.h:
* dfg/DFGVariableAccessDataDump.cpp: Added.
(JSC::DFG::VariableAccessDataDump::VariableAccessDataDump):
(JSC::DFG::VariableAccessDataDump::dump):
* dfg/DFGVariableAccessDataDump.h: Added.
(VariableAccessDataDump):

Source/WTF:

Added a StringPrintStream, and made it easy to create dumpers for typedefs to primitives.

* GNUmakefile.list.am:
* WTF.gypi:
* WTF.pro:
* WTF.vcproj/WTF.vcproj:
* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/PrintStream.cpp:
(WTF::dumpCharacter):
* wtf/PrintStream.h:
(WTF::printInternal):
* wtf/StringPrintStream.cpp: Added.
(WTF::StringPrintStream::StringPrintStream):
(WTF::StringPrintStream::~StringPrintStream):
(WTF::StringPrintStream::vprintf):
(WTF::StringPrintStream::toCString):
(WTF::StringPrintStream::increaseSize):
* wtf/StringPrintStream.h: Added.
(StringPrintStream):
(WTF::toCString):

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

27 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/bytecode/ValueProfile.h
Source/JavaScriptCore/bytecode/VirtualRegister.h
Source/JavaScriptCore/dfg/DFGAbstractValue.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp [new file with mode: 0644]
Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h [new file with mode: 0644]
Source/WTF/ChangeLog
Source/WTF/GNUmakefile.list.am
Source/WTF/WTF.gypi
Source/WTF/WTF.pro
Source/WTF/WTF.vcproj/WTF.vcproj
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/PrintStream.cpp
Source/WTF/wtf/PrintStream.h
Source/WTF/wtf/StringPrintStream.cpp [new file with mode: 0644]
Source/WTF/wtf/StringPrintStream.h [new file with mode: 0644]

index a77e9e451f09ad399d171da4dae9f5153f3402d9..7e5656025e5715e26a03638072a390e1b3aac605 100644 (file)
@@ -100,6 +100,7 @@ SET(JavaScriptCore_SOURCES
     dfg/DFGStructureCheckHoistingPhase.cpp
     dfg/DFGThunks.cpp
     dfg/DFGValueSource.cpp
+    dfg/DFGVariableAccessDataDump.cpp
     dfg/DFGVariableEvent.cpp
     dfg/DFGVariableEventStream.cpp
     dfg/DFGValidate.cpp
index f534ea5f742199d50f2da60796a042ad06612da5..9ab660ba24c00cdfdcf3bec78e89ca386d041ad0 100644 (file)
@@ -1,3 +1,47 @@
+2012-11-28  Filip Pizlo  <fpizlo@apple.com>
+
+        SpeculatedType dumping should not use the static char buffer[thingy] idiom
+        https://bugs.webkit.org/show_bug.cgi?id=103584
+
+        Reviewed by Michael Saboff.
+
+        Changed SpeculatedType to be "dumpable" by saying things like:
+        
+        dataLog("thingy = ", SpeculationDump(thingy))
+        
+        Removed the old stringification functions, and changed all code that referred to them
+        to use the new dataLog()/print() style.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * bytecode/SpeculatedType.cpp:
+        (JSC::dumpSpeculation):
+        (JSC::speculationToAbbreviatedString):
+        (JSC::dumpSpeculationAbbreviated):
+        * bytecode/SpeculatedType.h:
+        * bytecode/ValueProfile.h:
+        (JSC::ValueProfileBase::dump):
+        * bytecode/VirtualRegister.h:
+        (WTF::printInternal):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::AbstractValue::dump):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::injectLazyOperandSpeculation):
+        (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        (JSC::DFG::Graph::predictArgumentTypes):
+        * dfg/DFGGraph.h:
+        (Graph):
+        * dfg/DFGStructureAbstractValue.h:
+        * dfg/DFGVariableAccessDataDump.cpp: Added.
+        (JSC::DFG::VariableAccessDataDump::VariableAccessDataDump):
+        (JSC::DFG::VariableAccessDataDump::dump):
+        * dfg/DFGVariableAccessDataDump.h: Added.
+        (VariableAccessDataDump):
+
 2012-11-28  Michael Saboff  <msaboff@apple.com>
 
         Change Bytecompiler s_dumpsGeneratedCode to an Options value
index d7afaf18a228711e685c7ab5cc7998f6a5a969dc..c42ee7dfef4be8c853bfb349aafb7a6f6d13c317 100644 (file)
@@ -250,6 +250,8 @@ javascriptcore_sources += \
        Source/JavaScriptCore/dfg/DFGValidate.cpp \
        Source/JavaScriptCore/dfg/DFGValidate.h \
        Source/JavaScriptCore/dfg/DFGVariableAccessData.h \
+       Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp \
+       Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h \
        Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp \
        Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.h \
        Source/JavaScriptCore/disassembler/Disassembler.cpp \
index faa60ac04c396e3fc025b413637f7e24017d22a4..a2c4b5f522ed7b64694af32e6191306d0f9f5317 100644 (file)
                0FD82E56141DAF0800179C94 /* DFGOSREntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */; };
                0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */; };
+               0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
+               0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
                0FEB3ECD16237F4D00AB67AD /* TypedArrayDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FD82E52141DAEDE00179C94 /* DFGOSREntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSREntry.cpp; path = dfg/DFGOSREntry.cpp; sourceTree = "<group>"; };
                0FD82E53141DAEDE00179C94 /* DFGOSREntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSREntry.h; path = dfg/DFGOSREntry.h; sourceTree = "<group>"; };
                0FD82E84141F3FDA00179C94 /* SpeculatedType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeculatedType.cpp; sourceTree = "<group>"; };
+               0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = "<group>"; };
+               0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = "<group>"; };
                0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = "<group>"; };
                0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = "<group>"; };
                0FEB3ECB16237F4700AB67AD /* TypedArrayDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypedArrayDescriptor.h; sourceTree = "<group>"; };
                                0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */,
                                0F2BDC401522801700CD8910 /* DFGValueSource.h */,
                                0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */,
+                               0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */,
+                               0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */,
                                0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */,
                                0F2BDC411522801700CD8910 /* DFGVariableEvent.h */,
                                0F2BDC421522801700CD8910 /* DFGVariableEventStream.cpp */,
                                A77F1825164192C700640A47 /* ParserModes.h in Headers */,
                                0FAF7EFE165BA91F000C8455 /* JITDisassembler.h in Headers */,
                                0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */,
+                               0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */,
                                0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
                                0F9D3370165DBB90005AD387 /* Disassembler.cpp in Sources */,
+                               0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index e15b21dae701f15091b87de66929db699f528a72..e1caa725f3a8d189e2ad26fe2da5edb4a2aab9eb 100644 (file)
@@ -136,6 +136,7 @@ SOURCES += \
     dfg/DFGStructureCheckHoistingPhase.cpp \
     dfg/DFGThunks.cpp \
     dfg/DFGValueSource.cpp \
+    dfg/DFGVariableAccessDataDump.cpp \
     dfg/DFGVariableEvent.cpp \
     dfg/DFGVariableEventStream.cpp \
     dfg/DFGValidate.cpp \
index 399ab29c8f8a75cb2cd03bf9c0ccbd6d83978ccd..a07ca2b22c61e89b90d3785cfcd7c69a3f12daf0 100644 (file)
 #include "JSFunction.h"
 #include "ValueProfile.h"
 #include <wtf/BoundsCheckedPointer.h>
+#include <wtf/StringPrintStream.h>
 
 namespace JSC {
 
-const char* speculationToString(SpeculatedType value)
+void dumpSpeculation(PrintStream& out, SpeculatedType value)
 {
-    if (value == SpecNone)
-        return "None";
+    if (value == SpecNone) {
+        out.print("None");
+        return;
+    }
     
-    static const int size = 256;
-    static char description[size];
-    BoundsCheckedPointer<char> ptr(description, size);
+    StringPrintStream myOut;
     
     bool isTop = true;
     
     if (value & SpecCellOther)
-        ptr.strcat("Othercell");
+        myOut.print("Othercell");
     else
         isTop = false;
     
     if (value & SpecObjectOther)
-        ptr.strcat("Otherobj");
+        myOut.print("Otherobj");
     else
         isTop = false;
     
     if (value & SpecFinalObject)
-        ptr.strcat("Final");
+        myOut.print("Final");
     else
         isTop = false;
 
     if (value & SpecArray)
-        ptr.strcat("Array");
+        myOut.print("Array");
     else
         isTop = false;
     
     if (value & SpecInt8Array)
-        ptr.strcat("Int8array");
+        myOut.print("Int8array");
     else
         isTop = false;
     
     if (value & SpecInt16Array)
-        ptr.strcat("Int16array");
+        myOut.print("Int16array");
     else
         isTop = false;
     
     if (value & SpecInt32Array)
-        ptr.strcat("Int32array");
+        myOut.print("Int32array");
     else
         isTop = false;
     
     if (value & SpecUint8Array)
-        ptr.strcat("Uint8array");
+        myOut.print("Uint8array");
     else
         isTop = false;
 
     if (value & SpecUint8ClampedArray)
-        ptr.strcat("Uint8clampedarray");
+        myOut.print("Uint8clampedarray");
     else
         isTop = false;
     
     if (value & SpecUint16Array)
-        ptr.strcat("Uint16array");
+        myOut.print("Uint16array");
     else
         isTop = false;
     
     if (value & SpecUint32Array)
-        ptr.strcat("Uint32array");
+        myOut.print("Uint32array");
     else
         isTop = false;
     
     if (value & SpecFloat32Array)
-        ptr.strcat("Float32array");
+        myOut.print("Float32array");
     else
         isTop = false;
     
     if (value & SpecFloat64Array)
-        ptr.strcat("Float64array");
+        myOut.print("Float64array");
     else
         isTop = false;
     
     if (value & SpecFunction)
-        ptr.strcat("Function");
+        myOut.print("Function");
     else
         isTop = false;
     
     if (value & SpecMyArguments)
-        ptr.strcat("Myarguments");
+        myOut.print("Myarguments");
     else
         isTop = false;
     
     if (value & SpecForeignArguments)
-        ptr.strcat("Foreignarguments");
+        myOut.print("Foreignarguments");
     else
         isTop = false;
     
     if (value & SpecString)
-        ptr.strcat("String");
+        myOut.print("String");
     else
         isTop = false;
     
     if (value & SpecInt32)
-        ptr.strcat("Int");
+        myOut.print("Int");
     else
         isTop = false;
     
     if (value & SpecDoubleReal)
-        ptr.strcat("Doublereal");
+        myOut.print("Doublereal");
     else
         isTop = false;
     
     if (value & SpecDoubleNaN)
-        ptr.strcat("Doublenan");
+        myOut.print("Doublenan");
     else
         isTop = false;
     
     if (value & SpecBoolean)
-        ptr.strcat("Bool");
+        myOut.print("Bool");
     else
         isTop = false;
     
     if (value & SpecOther)
-        ptr.strcat("Other");
+        myOut.print("Other");
     else
         isTop = false;
     
-    if (isTop) {
-        ptr = description;
-        ptr.strcat("Top");
-    }
+    if (isTop)
+        out.print("Top");
+    else
+        out.print(myOut.toCString());
     
     if (value & SpecEmpty)
-        ptr.strcat("Empty");
-    
-    *ptr++ = 0;
-    
-    return description;
+        out.print("Empty");
 }
 
-const char* speculationToAbbreviatedString(SpeculatedType prediction)
+// We don't expose this because we don't want anyone relying on the fact that this method currently
+// just returns string constants.
+static const char* speculationToAbbreviatedString(SpeculatedType prediction)
 {
     if (isFinalObjectSpeculation(prediction))
         return "<Final>";
@@ -218,6 +217,11 @@ const char* speculationToAbbreviatedString(SpeculatedType prediction)
     return "";
 }
 
+void dumpSpeculationAbbreviated(PrintStream& out, SpeculatedType value)
+{
+    out.print(speculationToAbbreviatedString(value));
+}
+
 SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
 {
     if (classInfo == &JSFinalObject::s_info)
index 656bc79ee40633f166a2f459d3d98ed6d3c6020a..261a26b0ecd862257e5bf1c9ad75cb9f42a62902 100644 (file)
@@ -289,8 +289,11 @@ inline bool isEmptySpeculation(SpeculatedType value)
     return value == SpecEmpty;
 }
 
-const char* speculationToString(SpeculatedType value);
-const char* speculationToAbbreviatedString(SpeculatedType value);
+void dumpSpeculation(PrintStream&, SpeculatedType);
+void dumpSpeculationAbbreviated(PrintStream&, SpeculatedType);
+
+MAKE_PRINT_ADAPTOR(SpeculationDump, SpeculatedType, dumpSpeculation);
+MAKE_PRINT_ADAPTOR(AbbreviatedSpeculationDump, SpeculatedType, dumpSpeculationAbbreviated);
 
 // Merge two predictions. Note that currently this just does left | right. It may
 // seem tempting to do so directly, but you would be doing so at your own peril,
index 1fea6073df53e4c73a36d29877ea3842432ece87..e56e6eb6e25e6706e34e99e42f6fb8cc996231a4 100644 (file)
@@ -112,10 +112,7 @@ struct ValueProfileBase {
     
     void dump(PrintStream& out)
     {
-        out.printf(
-            "samples = %u, prediction = %s",
-            totalNumberOfSamples(),
-            speculationToString(m_prediction));
+        out.print("samples = ", totalNumberOfSamples(), " prediction = ", SpeculationDump(m_prediction));
         out.printf(", value = ");
         if (m_singletonValueIsTop)
             out.printf("TOP");
index b95f8b8faaf973d085dfdf64fa18c2234b6c001f..a6dc8d5656cf5de46cc567077d805baeb8f6e5ed 100644 (file)
@@ -27,6 +27,7 @@
 #define VirtualRegister_h
 
 #include <wtf/Platform.h>
+#include <wtf/PrintStream.h>
 
 namespace JSC {
 
@@ -37,4 +38,13 @@ COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit)
 
 } // namespace JSC
 
+namespace WTF {
+
+inline void printInternal(PrintStream& out, JSC::VirtualRegister value)
+{
+    out.print(static_cast<int>(value));
+}
+
+} // namespace WTF
+
 #endif // VirtualRegister_h
index 5de9472dc56dd781db0e2ef173daee620fc5445a..0ce01ab562329dd4a7ccdf11e278f290acd1eaa8 100644 (file)
@@ -374,7 +374,7 @@ struct AbstractValue {
     void dump(PrintStream& out) const
     {
         out.print(
-            "(", speculationToString(m_type), ", ", arrayModesToString(m_arrayModes), ", ",
+            "(", SpeculationDump(m_type), ", ", arrayModesToString(m_arrayModes), ", ",
             m_currentKnownStructure, ", ", m_futurePossibleStructure);
         if (!!m_value)
             out.print(", ", m_value.description());
@@ -532,15 +532,6 @@ private:
 
 } } // namespace JSC::DFG
 
-namespace WTF {
-
-inline void printInternal(PrintStream& out, const JSC::DFG::AbstractValue& value)
-{
-    value.dump(out);
-}
-
-} // namespace WTF
-
 #endif // ENABLE(DFG_JIT)
 
 #endif // DFGAbstractValue_h
index 483491fe634281b3d1a08b3c5b9aba0a2afa5ee4..c5ffb1fc63c641c18b1ffa89991abf701174ffd6 100644 (file)
@@ -267,8 +267,7 @@ private:
             m_inlineStackTop->m_lazyOperands.prediction(
                 LazyOperandValueProfileKey(m_currentIndex, node.local()));
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Lazy operand [@%u, bc#%u, r%d] prediction: %s\n",
-                nodeIndex, m_currentIndex, node.local(), speculationToString(prediction));
+        dataLog("Lazy operand [@", nodeIndex, ", bc#", m_currentIndex, ", r", node.local(), "] prediction: ", SpeculationDump(prediction), "\n");
 #endif
         node.variableAccessData()->predict(prediction);
         return nodeIndex;
@@ -887,7 +886,7 @@ private:
         
         SpeculatedType prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(bytecodeIndex);
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Dynamic [@%u, bc#%u] prediction: %s\n", nodeIndex, bytecodeIndex, speculationToString(prediction));
+        dataLog("Dynamic [@", nodeIndex, ", bc#", bytecodeIndex, "] prediction: ", SpeculationDump(prediction), "\n");
 #endif
         
         return prediction;
index bedefab002ec2ac440bfea813cb5ffe815db764c..270f53b87a67e1ff7b9e365dd4c3c85efad14fbb 100644 (file)
@@ -27,7 +27,7 @@
 #include "DFGGraph.h"
 
 #include "CodeBlock.h"
-#include <wtf/BoundsCheckedPointer.h>
+#include "DFGVariableAccessDataDump.h"
 
 #if ENABLE(DFG_JIT)
 
@@ -57,44 +57,6 @@ const char *Graph::opName(NodeType op)
     return dfgOpNames[op];
 }
 
-const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData)
-{
-    // Variables are already numbered. For readability of IR dumps, this returns
-    // an alphabetic name for the variable access data, so that you don't have to
-    // reason about two numbers (variable number and live range number), but instead
-    // a number and a letter.
-    
-    unsigned index = std::numeric_limits<unsigned>::max();
-    for (unsigned i = 0; i < m_variableAccessData.size(); ++i) {
-        if (&m_variableAccessData[i] == variableAccessData) {
-            index = i;
-            break;
-        }
-    }
-    
-    ASSERT(index != std::numeric_limits<unsigned>::max());
-    
-    if (!index)
-        return "A";
-
-    static char buf[100];
-    BoundsCheckedPointer<char> ptr(buf, sizeof(buf));
-    
-    while (index) {
-        *ptr++ = 'A' + (index % 26);
-        index /= 26;
-    }
-    
-    if (variableAccessData->isCaptured())
-        *ptr++ = '*';
-    
-    ptr.strcat(speculationToAbbreviatedString(variableAccessData->prediction()));
-    
-    *ptr++ = 0;
-    
-    return buf;
-}
-
 static void printWhiteSpace(PrintStream& out, unsigned amount)
 {
     while (amount-- > 0)
@@ -152,8 +114,7 @@ void Graph::dump(PrintStream& out, Edge edge)
     out.print(
         useKindToString(edge.useKind()),
         "@", edge.index(),
-        speculationToAbbreviatedString(
-            at(edge).prediction()));
+        AbbreviatedSpeculationDump(at(edge).prediction()));
 }
 
 void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex)
@@ -264,7 +225,7 @@ void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex)
     if (node.hasStorageAccessData()) {
         StorageAccessData& storageAccessData = m_storageAccessData[node.storageAccessDataIndex()];
         out.print(hasPrinted ? ", " : "", "id", storageAccessData.identifierNumber, "{", m_codeBlock->identifier(storageAccessData.identifierNumber).string(), "}");
-        out.print(", ", storageAccessData.offset);
+        out.print(", ", static_cast<ptrdiff_t>(storageAccessData.offset));
         hasPrinted = true;
     }
     ASSERT(node.hasVariableAccessData() == node.hasLocal());
@@ -272,9 +233,9 @@ void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex)
         VariableAccessData* variableAccessData = node.variableAccessData();
         int operand = variableAccessData->operand();
         if (operandIsArgument(operand))
-            out.print(hasPrinted ? ", " : "", "arg", operandToArgument(operand), "(", nameOfVariableAccessData(variableAccessData), ")");
+            out.print(hasPrinted ? ", " : "", "arg", operandToArgument(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")");
         else
-            out.print(hasPrinted ? ", " : "", "r", operand, "(", nameOfVariableAccessData(variableAccessData), ")");
+            out.print(hasPrinted ? ", " : "", "r", operand, "(", VariableAccessDataDump(*this, variableAccessData), ")");
         hasPrinted = true;
     }
     if (node.hasConstantBuffer()) {
@@ -321,9 +282,9 @@ void Graph::dump(PrintStream& out, const char* prefix, NodeIndex nodeIndex)
 
     if (!skipped) {
         if (node.hasVariableAccessData())
-            out.print("  predicting ", speculationToString(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
+            out.print("  predicting ", SpeculationDump(node.variableAccessData()->prediction()), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
         else if (node.hasHeapPrediction())
-            out.print("  predicting ", speculationToString(node.getHeapPrediction()));
+            out.print("  predicting ", SpeculationDump(node.getHeapPrediction()));
     }
     
     out.print("\n");
@@ -459,7 +420,9 @@ void Graph::predictArgumentTypes()
         at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction());
         
 #if DFG_ENABLE(DEBUG_VERBOSE)
-        dataLogF("Argument [%zu] prediction: %s\n", arg, speculationToString(at(m_arguments[arg]).variableAccessData()->prediction()));
+        dataLog(
+            "Argument [", arg, "] prediction: ",
+            SpeculationDump(at(m_arguments[arg]).variableAccessData()->prediction()), "\n");
 #endif
     }
 }
index 767e2a66ce5984e5c5b0933edeeafb3be66f8c24..d91d3739456910a40ed3d5e534b7cc2fde737836 100644 (file)
@@ -327,9 +327,6 @@ public:
 
     static const char *opName(NodeType);
     
-    // This is O(n), and should only be used for verbose dumps.
-    const char* nameOfVariableAccessData(VariableAccessData*);
-
     void predictArgumentTypes();
     
     StructureSet* addStructureSet(const StructureSet& structureSet)
index aeb02d83eecb96f25cf7fe7a845a3cbf91925b6d..626a11f0b6c90fecef22f6b7915dc9a5874fa26e 100644 (file)
@@ -320,15 +320,6 @@ private:
 
 } } // namespace JSC::DFG
 
-namespace WTF {
-
-inline void printInternal(PrintStream& out, const JSC::DFG::StructureAbstractValue& value)
-{
-    value.dump(out);
-}
-
-} // namespace WTF
-
 #endif // ENABLE(DFG_JIT)
 
 #endif // DFGStructureAbstractValue_h
diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.cpp
new file mode 100644 (file)
index 0000000..920858c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 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
+ * 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. 
+ */
+
+#include "config.h"
+#include "DFGVariableAccessDataDump.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGVariableAccessData.h"
+
+namespace JSC { namespace DFG {
+
+VariableAccessDataDump::VariableAccessDataDump(Graph& graph, VariableAccessData* data)
+    : m_graph(graph)
+    , m_data(data)
+{
+}
+
+void VariableAccessDataDump::dump(PrintStream& out) const
+{
+    unsigned index = std::numeric_limits<unsigned>::max();
+    for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
+        if (&m_graph.m_variableAccessData[i] == m_data) {
+            index = i;
+            break;
+        }
+    }
+    
+    ASSERT(index != std::numeric_limits<unsigned>::max());
+    
+    if (!index) {
+        out.print("a");
+        return;
+    }
+
+    while (index) {
+        out.print(CharacterDump('A' + (index % 26)));
+        index /= 26;
+    }
+    
+    if (m_data->isCaptured())
+        out.print("*");
+
+    out.print(AbbreviatedSpeculationDump(m_data->prediction()));
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+
diff --git a/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h b/Source/JavaScriptCore/dfg/DFGVariableAccessDataDump.h
new file mode 100644 (file)
index 0000000..1422d7f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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
+ * 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 DFGVariableAccessDataDump_h
+#define DFGVariableAccessDataDump_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include <wtf/PrintStream.h>
+
+namespace JSC { namespace DFG {
+
+class Graph;
+class VariableAccessData;
+
+class VariableAccessDataDump {
+public:
+    VariableAccessDataDump(Graph&, VariableAccessData*);
+    
+    void dump(PrintStream&) const;
+
+private:
+    Graph& m_graph;
+    VariableAccessData* m_data;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGVariableAccessDataDump_h
+
index d738e9925b0b0017d0d12338bb40da3297a65cfc..380ee628b8d7a24b3e75d57df234f6c580d4a67b 100644 (file)
@@ -1,3 +1,32 @@
+2012-11-28  Filip Pizlo  <fpizlo@apple.com>
+
+        SpeculatedType dumping should not use the static char buffer[thingy] idiom
+        https://bugs.webkit.org/show_bug.cgi?id=103584
+
+        Reviewed by Michael Saboff.
+
+        Added a StringPrintStream, and made it easy to create dumpers for typedefs to primitives.
+
+        * GNUmakefile.list.am:
+        * WTF.gypi:
+        * WTF.pro:
+        * WTF.vcproj/WTF.vcproj:
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/PrintStream.cpp:
+        (WTF::dumpCharacter):
+        * wtf/PrintStream.h:
+        (WTF::printInternal):
+        * wtf/StringPrintStream.cpp: Added.
+        (WTF::StringPrintStream::StringPrintStream):
+        (WTF::StringPrintStream::~StringPrintStream):
+        (WTF::StringPrintStream::vprintf):
+        (WTF::StringPrintStream::toCString):
+        (WTF::StringPrintStream::increaseSize):
+        * wtf/StringPrintStream.h: Added.
+        (StringPrintStream):
+        (WTF::toCString):
+
 2012-11-28  Michael Saboff  <msaboff@apple.com>
 
         Update String Stats for recent dataLog changes and add summary
index aa78cd177f478c52c60269c7f5a337ab73200545..88cce1398f4dd825ac796a865ea27c951177eae6 100644 (file)
@@ -159,6 +159,8 @@ wtf_sources += \
     Source/WTF/wtf/StdLibExtras.h \
     Source/WTF/wtf/StreamBuffer.h \
     Source/WTF/wtf/StringExtras.h \
+    Source/WTF/wtf/StringPrintStream.cpp \
+    Source/WTF/wtf/StringPrintStream.h \
     Source/WTF/wtf/StringHasher.h \
     Source/WTF/wtf/TCPackedCache.h \
     Source/WTF/wtf/TCPageMap.h \
index 9dcb56e55ba39c4354ef8f899dc47bf22675c542..df80c063cd57c2e910bb099011679320eeca9425 100644 (file)
@@ -99,6 +99,7 @@
             'wtf/StdLibExtras.h',
             'wtf/StringExtras.h',
             'wtf/StringHasher.h',
+            'wtf/StringPrintStream.h',
             'wtf/TemporaryChange.h',
             'wtf/ThreadRestrictionVerifier.h',
             'wtf/ThreadSafeRefCounted.h',
             'wtf/SizeLimits.cpp',
             'wtf/StackBounds.cpp',
             'wtf/StringExtras.cpp',
+            'wtf/StringPrintStream.cpp',
             'wtf/TCPackedCache.h',
             'wtf/TCPageMap.h',
             'wtf/TCSpinLock.h',
index 78e351c4de97aad1dd902132b141b57b2c9e3d11..366194bbd32b98f4d7dbd2a184989047dcece366 100644 (file)
@@ -146,6 +146,7 @@ HEADERS += \
     StdLibExtras.h \
     StringExtras.h \
     StringHasher.h \
+    StringPrintStream.h \
     TCPackedCache.h \
     TCSpinLock.h \
     TCSystemAlloc.h \
@@ -235,6 +236,7 @@ SOURCES += \
     RefCountedLeakCounter.cpp \
     SHA1.cpp \
     StackBounds.cpp \
+    StringPrintStream.cpp \
     TCSystemAlloc.cpp \
     Threading.cpp \
     TypeTraits.cpp \
index 365ec274d7e621e6bffa71f971f6ed82ebad83e3..ebc8194ad0a56f5b582646001c8bb53336954f38 100644 (file)
                        RelativePath="..\wtf\StringHasher.h"
                        >
                </File>
+               <File
+                       RelativePath="..\wtf\StringPrintStream.cpp"
+                       >
+               </File>
+               <File
+                       RelativePath="..\wtf\StringPrintStream.h"
+                       >
+               </File>
                <File
                        RelativePath="..\wtf\TCPackedCache.h"
                        >
index f9fcaca11ac745989a959497c56950d38b4acb3c..c210b5c6d0dc0a065954354d87bc226390fa874b 100644 (file)
@@ -27,6 +27,8 @@
                0F9D3362165DBA73005AD387 /* PrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D335D165DBA73005AD387 /* PrintStream.cpp */; };
                0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F9D335E165DBA73005AD387 /* PrintStream.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 */; };
                143F611F1565F0F900DB514A /* RAMSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 143F611D1565F0F900DB514A /* RAMSize.cpp */; };
                143F61201565F0F900DB514A /* RAMSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 143F611E1565F0F900DB514A /* RAMSize.h */; settings = {ATTRIBUTES = (); }; };
                14F3B0F715E45E4600210069 /* SaturatedArithmetic.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F3B0F615E45E4600210069 /* SaturatedArithmetic.h */; settings = {ATTRIBUTES = (); }; };
                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>"; };
                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>"; };
                143F611D1565F0F900DB514A /* RAMSize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RAMSize.cpp; sourceTree = "<group>"; };
                143F611E1565F0F900DB514A /* RAMSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RAMSize.h; sourceTree = "<group>"; };
                14F3B0F615E45E4600210069 /* SaturatedArithmetic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SaturatedArithmetic.h; sourceTree = "<group>"; };
                                A8A47312151A825B004123FF /* StringExtras.cpp */,
                                A8A47313151A825B004123FF /* StringExtras.h */,
                                A8A47314151A825B004123FF /* StringHasher.h */,
+                               0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */,
+                               0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */,
                                A8A47315151A825B004123FF /* TCPackedCache.h */,
                                A8A47316151A825B004123FF /* TCPageMap.h */,
                                A8A47317151A825B004123FF /* TCSpinLock.h */,
                                0F9D3361165DBA73005AD387 /* FilePrintStream.h in Headers */,
                                0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */,
                                0F87105A16643F190090B0AD /* RawPointer.h in Headers */,
+                               0FDDBFA81666DFA300C55FEF /* StringPrintStream.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                A8A47486151A825B004123FF /* WTFThreadData.cpp in Sources */,
                                0F9D3360165DBA73005AD387 /* FilePrintStream.cpp in Sources */,
                                0F9D3362165DBA73005AD387 /* PrintStream.cpp in Sources */,
+                               0FDDBFA71666DFA300C55FEF /* StringPrintStream.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 660d137b64f1880cde4b3034b960cb8cbefe0aa6..9ba49504ba4db6acc366ec0b3bdb18e4505a32df 100644 (file)
@@ -105,6 +105,7 @@ SET(WTF_HEADERS
     StdLibExtras.h
     StringExtras.h
     StringHasher.h
+    StringPrintStream.h
     TCPackedCache.h
     TCPageMap.h
     TCSpinLock.h
@@ -184,6 +185,7 @@ SET(WTF_SOURCES
     SHA1.cpp
     StackBounds.cpp
     StringExtras.cpp
+    StringPrintStream.cpp
     Threading.cpp
     TypeTraits.cpp
     WTFThreadData.cpp
index 3d4405a34bab880cc30d9a3a2ee85fbe8fe515e1..c6123e1714e8c4500e1e412fc58cb4b57d878889 100644 (file)
@@ -115,5 +115,10 @@ void printInternal(PrintStream& out, RawPointer value)
     out.printf("%p", value.value());
 }
 
+void dumpCharacter(PrintStream& out, char value)
+{
+    out.printf("%c", value);
+}
+
 } // namespace WTF
 
index 8cb0d927df9833d06f2b7f00ec8d76272f367cc7..88329fd97d7cb1f0717fad68ad52c2b2aa544f96 100644 (file)
@@ -160,6 +160,9 @@ public:
 void printInternal(PrintStream&, const char*);
 void printInternal(PrintStream&, const CString&);
 void printInternal(PrintStream&, const String&);
+inline void printInternal(PrintStream& out, char* value) { printInternal(out, static_cast<const char*>(value)); }
+inline void printInternal(PrintStream& out, CString& value) { printInternal(out, static_cast<const CString&>(value)); }
+inline void printInternal(PrintStream& out, String& value) { printInternal(out, static_cast<const String&>(value)); }
 void printInternal(PrintStream&, bool);
 void printInternal(PrintStream&, int);
 void printInternal(PrintStream&, unsigned);
@@ -171,8 +174,51 @@ void printInternal(PrintStream&, float);
 void printInternal(PrintStream&, double);
 void printInternal(PrintStream&, RawPointer);
 
+template<typename T>
+void printInternal(PrintStream& out, const T& value)
+{
+    value.dump(out);
+}
+
+#define MAKE_PRINT_ADAPTOR(Name, Type, function) \
+    class Name {                                 \
+    public:                                      \
+        Name(const Type& value)                  \
+            : m_value(value)                     \
+        {                                        \
+        }                                        \
+        void dump(PrintStream& out) const        \
+        {                                        \
+            function(out, m_value);              \
+        }                                        \
+    private:                                     \
+        Type m_value;                            \
+    }
+
+#define MAKE_PRINT_METHOD_ADAPTOR(Name, Type, method) \
+    class Name {                                 \
+    public:                                      \
+        Name(const Type& value)                  \
+            : m_value(value)                     \
+        {                                        \
+        }                                        \
+        void dump(PrintStream& out) const        \
+        {                                        \
+            m_value.method(out);                 \
+        }                                        \
+    private:                                     \
+        Type m_value;                            \
+    }
+
+// Use an adaptor-based dumper for characters to avoid situations where
+// you've "compressed" an integer to a character and it ends up printing
+// as ASCII when you wanted it to print as a number.
+void dumpCharacter(PrintStream&, char);
+MAKE_PRINT_ADAPTOR(CharacterDump, char, dumpCharacter);
+
 } // namespace WTF
 
+using WTF::CharacterDump;
 using WTF::PrintStream;
 
 #endif // PrintStream_h
diff --git a/Source/WTF/wtf/StringPrintStream.cpp b/Source/WTF/wtf/StringPrintStream.cpp
new file mode 100644 (file)
index 0000000..41e1f83
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 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
+ * 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. 
+ */
+
+#include "config.h"
+#include "StringPrintStream.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <wtf/FastMalloc.h>
+
+namespace WTF {
+
+StringPrintStream::StringPrintStream()
+    : m_buffer(m_inlineBuffer)
+    , m_next(0)
+    , m_size(sizeof(m_inlineBuffer))
+{
+    m_buffer[0] = 0; // Make sure that we always have a null terminator.
+}
+
+StringPrintStream::~StringPrintStream()
+{
+    if (m_buffer == m_inlineBuffer)
+        return;
+    fastFree(m_buffer);
+}
+
+void StringPrintStream::vprintf(const char* format, va_list argList)
+{
+    ASSERT(m_next < m_size);
+    ASSERT(!m_buffer[m_next]);
+    
+    va_list firstPassArgList;
+#if OS(WINDOWS)
+    firstPassArgList = argList;
+#else
+    va_copy(firstPassArgList, argList);
+#endif
+    
+    int numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten =
+        vsnprintf(m_buffer + m_next, m_size - m_next, format, firstPassArgList);
+    
+    int numberOfBytesThatWouldHaveBeenWritten =
+        numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten + 1;
+    
+    if (m_next + numberOfBytesThatWouldHaveBeenWritten <= m_size) {
+        m_next += numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten;
+        return; // This means that vsnprintf() succeeded.
+    }
+    
+    increaseSize(m_next + numberOfBytesThatWouldHaveBeenWritten);
+    
+    int numberOfBytesNotIncludingTerminatorThatWereWritten =
+        vsnprintf(m_buffer + m_next, m_size - m_next, format, argList);
+    
+    int numberOfBytesThatWereWritten = numberOfBytesNotIncludingTerminatorThatWereWritten + 1;
+    
+    ASSERT_UNUSED(numberOfBytesThatWereWritten, m_next + numberOfBytesThatWereWritten <= m_size);
+    
+    m_next += numberOfBytesNotIncludingTerminatorThatWereWritten;
+    
+    ASSERT(m_next < m_size);
+    ASSERT(!m_buffer[m_next]);
+}
+
+CString StringPrintStream::toCString()
+{
+    ASSERT(m_next == strlen(m_buffer));
+    return CString(m_buffer, m_next);
+}
+
+void StringPrintStream::increaseSize(size_t newSize)
+{
+    ASSERT(newSize > m_size);
+    ASSERT(newSize > sizeof(m_inlineBuffer));
+    
+    // Use exponential resizing to reduce thrashing.
+    m_size = newSize << 1;
+    
+    // Use fastMalloc instead of fastRealloc because we know that for the sizes we're using,
+    // fastRealloc will just do malloc+free anyway. Also, this simplifies the code since
+    // we can't realloc the inline buffer.
+    char* newBuffer = static_cast<char*>(fastMalloc(m_size));
+    memcpy(newBuffer, m_buffer, m_next + 1);
+    if (m_buffer != m_inlineBuffer)
+        fastFree(m_buffer);
+    m_buffer = newBuffer;
+}
+
+} // namespace WTF
+
diff --git a/Source/WTF/wtf/StringPrintStream.h b/Source/WTF/wtf/StringPrintStream.h
new file mode 100644 (file)
index 0000000..9290f08
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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
+ * 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 StringPrintStream_h
+#define StringPrintStream_h
+
+#include <wtf/PrintStream.h>
+#include <wtf/text/CString.h>
+
+namespace WTF {
+
+class StringPrintStream : public PrintStream {
+public:
+    StringPrintStream();
+    ~StringPrintStream();
+    
+    virtual void vprintf(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(2, 0);
+    
+    CString toCString();
+    
+private:
+    void increaseSize(size_t);
+    
+    char* m_buffer;
+    size_t m_next;
+    size_t m_size;
+    char m_inlineBuffer[128];
+};
+
+// Stringify any type T that has a WTF::printInternal(PrintStream&, const T&)
+template<typename T>
+CString toCString(const T& value)
+{
+    StringPrintStream stream;
+    stream.print(value);
+    return stream.toCString();
+}
+
+} // namespace WTF
+
+using WTF::StringPrintStream;
+using WTF::toCString;
+
+#endif // StringPrintStream_h
+