Any function that can log things should be able to easily log them to a memory buffer as well
https://bugs.webkit.org/show_bug.cgi?id=103000

Reviewed by Sam Weinig.

Source/JavaScriptCore: 

Change all users of WTF::dataFile() to expect a PrintStream& rather than a FILE*.

* bytecode/Operands.h:
(JSC::OperandValueTraits::dump):
(JSC::dumpOperands):
(JSC):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::dump):
* dfg/DFGAbstractState.h:
(AbstractState):
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::dump):
* dfg/DFGCommon.h:
(JSC::DFG::NodeIndexTraits::dump):
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::dump):
* dfg/DFGVariableEvent.cpp:
(JSC::DFG::VariableEvent::dump):
(JSC::DFG::VariableEvent::dumpFillInfo):
(JSC::DFG::VariableEvent::dumpSpillInfo):
* dfg/DFGVariableEvent.h:
(VariableEvent):
* disassembler/Disassembler.h:
(JSC):
(JSC::tryToDisassemble):
* disassembler/UDis86Disassembler.cpp:
(JSC::tryToDisassemble):

Source/WTF: 

We have a number of places where we pass around a FILE* as a target to which to print
some logging information. But the purpose of passing FILE* instead of always assuming
that we should dump to stderr is that it may be sometimes useful to send the logging
information elsewhere. Unfortunately, FILE* isn't quite powerful enough: it's combersome
to use it to send logging to a string, for example.
        
We could get around this by using <iostream> and <sstream>, but so far this aspect of
C++ has not been part of the WebKit coding conventions. Personally I find <iostream>
awkward due to its abuse of operator overloading.
        
So this patch introduces the PrintStream abstract class, which offers printf-like
functionality while completely abstracting the destination and mechanism of the printing
output. It would be trivial to implement a StringPrintStream, for example. This will feed
into work on https://bugs.webkit.org/show_bug.cgi?id=102999.
        
This also sets us up for creating templatized print() and println() methods that will
allow us to say things like out.print("count = ", count, "\n"), but that is the topic
of https://bugs.webkit.org/show_bug.cgi?id=103009.
        
This patch also changes dataLog() to use FilePrintStream internally, and WTF::dataFile()
now returns a FilePrintStream&. Any previous users of WTF::dataFile() have been changed
to expect a PrintStream&.

* GNUmakefile.list.am:
* WTF.pro:
* WTF.vcproj/WTF.vcproj:
* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/DataLog.cpp:
(WTF):
(WTF::initializeLogFileOnce):
(WTF::initializeLogFile):
(WTF::dataFile):
(WTF::dataLogV):
(WTF::dataLogString):
* wtf/DataLog.h:
(WTF):
* wtf/FilePrintStream.cpp: Added.
(WTF):
(WTF::FilePrintStream::FilePrintStream):
(WTF::FilePrintStream::~FilePrintStream):
(WTF::FilePrintStream::vprintf):
(WTF::FilePrintStream::flush):
* wtf/FilePrintStream.h: Added.
(WTF):
(FilePrintStream):
(WTF::FilePrintStream::file):
* wtf/PrintStream.cpp: Added.
(WTF):
(WTF::PrintStream::PrintStream):
(WTF::PrintStream::~PrintStream):
(WTF::PrintStream::printf):
(WTF::PrintStream::print):
(WTF::PrintStream::println):
(WTF::PrintStream::flush):
(WTF::print):
* wtf/PrintStream.h: Added.
(WTF):
(PrintStream):
(WTF::print):
(WTF::println):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@135640 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 1a270e4..ba2979b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,38 @@
+2012-11-21  Filip Pizlo  <fpizlo@apple.com>
+
+        Any function that can log things should be able to easily log them to a memory buffer as well
+        https://bugs.webkit.org/show_bug.cgi?id=103000
+
+        Reviewed by Sam Weinig.
+
+        Change all users of WTF::dataFile() to expect a PrintStream& rather than a FILE*.
+
+        * bytecode/Operands.h:
+        (JSC::OperandValueTraits::dump):
+        (JSC::dumpOperands):
+        (JSC):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::dump):
+        * dfg/DFGAbstractState.h:
+        (AbstractState):
+        * dfg/DFGAbstractValue.h:
+        (JSC::DFG::AbstractValue::dump):
+        * dfg/DFGCommon.h:
+        (JSC::DFG::NodeIndexTraits::dump):
+        * dfg/DFGStructureAbstractValue.h:
+        (JSC::DFG::StructureAbstractValue::dump):
+        * dfg/DFGVariableEvent.cpp:
+        (JSC::DFG::VariableEvent::dump):
+        (JSC::DFG::VariableEvent::dumpFillInfo):
+        (JSC::DFG::VariableEvent::dumpSpillInfo):
+        * dfg/DFGVariableEvent.h:
+        (VariableEvent):
+        * disassembler/Disassembler.h:
+        (JSC):
+        (JSC::tryToDisassemble):
+        * disassembler/UDis86Disassembler.cpp:
+        (JSC::tryToDisassemble):
+
 2012-11-23  Alexis Menard  <alexis@webkit.org>
 
         [CSS3 Backgrounds and Borders] Implement new CSS3 background-position parsing.
diff --git a/Source/JavaScriptCore/bytecode/Operands.h b/Source/JavaScriptCore/bytecode/Operands.h
index 0cea096..20f79ff 100644
--- a/Source/JavaScriptCore/bytecode/Operands.h
+++ b/Source/JavaScriptCore/bytecode/Operands.h
@@ -28,7 +28,7 @@
 
 #include "CallFrame.h"
 #include "JSObject.h"
-
+#include <wtf/PrintStream.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
@@ -43,7 +43,7 @@
 template<typename T>
 struct OperandValueTraits {
     static T defaultValue() { return T(); }
-    static void dump(const T& value, FILE* out) { value.dump(out); }
+    static void dump(const T& value, PrintStream& out) { value.dump(out); }
 };
 
 template<typename T, typename Traits = OperandValueTraits<T> >
@@ -190,17 +190,17 @@
 };
 
 template<typename T, typename Traits>
-void dumpOperands(const Operands<T, Traits>& operands, FILE* out)
+void dumpOperands(const Operands<T, Traits>& operands, PrintStream& out)
 {
     for (size_t argument = 0; argument < operands.numberOfArguments(); ++argument) {
         if (argument)
-            fprintf(out, " ");
+            out.printf(" ");
         Traits::dump(operands.argument(argument), out);
     }
-    fprintf(out, " : ");
+    out.printf(" : ");
     for (size_t local = 0; local < operands.numberOfLocals(); ++local) {
         if (local)
-            fprintf(out, " ");
+            out.printf(" ");
         Traits::dump(operands.local(local), out);
     }
 }
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 23b84ce..89b2a97 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -1942,7 +1942,7 @@
     return destination.merge(source);
 }
 
-void AbstractState::dump(FILE* out)
+void AbstractState::dump(PrintStream& out)
 {
     bool first = true;
     for (size_t i = 0; i < m_block->size(); ++i) {
@@ -1953,8 +1953,8 @@
         if (first)
             first = false;
         else
-            fprintf(out, " ");
-        fprintf(out, "@%lu:", static_cast<unsigned long>(index));
+            out.printf(" ");
+        out.printf("@%lu:", static_cast<unsigned long>(index));
         value.dump(out);
     }
 }
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 230cd83..40dc502 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -180,7 +180,7 @@
     // MergeToSuccessors.
     bool mergeToSuccessors(Graph&, BasicBlock*);
     
-    void dump(FILE* out);
+    void dump(PrintStream& out);
     
 private:
     void clobberWorld(const CodeOrigin&, unsigned indexInBlock);
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractValue.h b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
index c60b792..fd32204 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractValue.h
@@ -371,15 +371,15 @@
         // complexity of the code.
     }
     
-    void dump(FILE* out) const
+    void dump(PrintStream& out) const
     {
-        fprintf(out, "(%s, %s, ", speculationToString(m_type), arrayModesToString(m_arrayModes));
+        out.printf("(%s, %s, ", speculationToString(m_type), arrayModesToString(m_arrayModes));
         m_currentKnownStructure.dump(out);
-        dataLogF(", ");
+        out.printf(", ");
         m_futurePossibleStructure.dump(out);
         if (!!m_value)
-            fprintf(out, ", %s", m_value.description());
-        fprintf(out, ")");
+            out.printf(", %s", m_value.description());
+        out.printf(")");
     }
     
     // A great way to think about the difference between m_currentKnownStructure and
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 2c0556d..14c47ce 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -92,12 +92,12 @@
 
 struct NodeIndexTraits {
     static NodeIndex defaultValue() { return NoNode; }
-    static void dump(NodeIndex value, FILE* out)
+    static void dump(NodeIndex value, PrintStream& out)
     {
         if (value == NoNode)
-            fprintf(out, "-");
+            out.printf("-");
         else
-            fprintf(out, "@%u", value);
+            out.printf("@%u", value);
     }
 };
 
diff --git a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
index b3082de..25606b9 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
+++ b/Source/JavaScriptCore/dfg/DFGStructureAbstractValue.h
@@ -298,17 +298,17 @@
         return m_structure == other.m_structure;
     }
     
-    void dump(FILE* out) const
+    void dump(PrintStream& out) const
     {
         if (isTop()) {
-            fprintf(out, "TOP");
+            out.printf("TOP");
             return;
         }
         
-        fprintf(out, "[");
+        out.printf("[");
         if (m_structure)
-            fprintf(out, "%p", m_structure);
-        fprintf(out, "]");
+            out.printf("%p", m_structure);
+        out.printf("]");
     }
 
 private:
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp
index 3e84a6b..8ea568b 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp
+++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.cpp
@@ -33,11 +33,11 @@
 
 namespace JSC { namespace DFG {
 
-void VariableEvent::dump(FILE* out) const
+void VariableEvent::dump(PrintStream& out) const
 {
     switch (kind()) {
     case Reset:
-        fprintf(out, "Reset");
+        out.printf("Reset");
         break;
     case BirthToFill:
         dumpFillInfo("BirthToFill", out);
@@ -52,13 +52,13 @@
         dumpSpillInfo("Spill", out);
         break;
     case Death:
-        fprintf(out, "Death(@%u)", nodeIndex());
+        out.printf("Death(@%u)", nodeIndex());
         break;
     case MovHint:
-        fprintf(out, "MovHint(@%u, r%d)", nodeIndex(), operand());
+        out.printf("MovHint(@%u, r%d)", nodeIndex(), operand());
         break;
     case SetLocalEvent:
-        fprintf(out, "SetLocal(r%d, %s)", operand(), dataFormatToString(dataFormat()));
+        out.printf("SetLocal(r%d, %s)", operand(), dataFormatToString(dataFormat()));
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -66,23 +66,23 @@
     }
 }
 
-void VariableEvent::dumpFillInfo(const char* name, FILE* out) const
+void VariableEvent::dumpFillInfo(const char* name, PrintStream& out) const
 {
-    fprintf(out, "%s(@%u, ", name, nodeIndex());
+    out.printf("%s(@%u, ", name, nodeIndex());
     if (dataFormat() == DataFormatDouble)
-        fprintf(out, "%s", FPRInfo::debugName(fpr()));
+        out.printf("%s", FPRInfo::debugName(fpr()));
 #if USE(JSVALUE32_64)
     else if (dataFormat() & DataFormatJS)
-        fprintf(out, "%s:%s", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR()));
+        out.printf("%s:%s", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR()));
 #endif
     else
-        fprintf(out, "%s", GPRInfo::debugName(gpr()));
-    fprintf(out, ", %s)", dataFormatToString(dataFormat()));
+        out.printf("%s", GPRInfo::debugName(gpr()));
+    out.printf(", %s)", dataFormatToString(dataFormat()));
 }
 
-void VariableEvent::dumpSpillInfo(const char* name, FILE* out) const
+void VariableEvent::dumpSpillInfo(const char* name, PrintStream& out) const
 {
-    fprintf(out, "%s(@%u, r%d, %s)", name, nodeIndex(), virtualRegister(), dataFormatToString(dataFormat()));
+    out.printf("%s(@%u, r%d, %s)", name, nodeIndex(), virtualRegister(), dataFormatToString(dataFormat()));
 }
 
 } } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGVariableEvent.h b/Source/JavaScriptCore/dfg/DFGVariableEvent.h
index a491a3e..0d1fe0a 100644
--- a/Source/JavaScriptCore/dfg/DFGVariableEvent.h
+++ b/Source/JavaScriptCore/dfg/DFGVariableEvent.h
@@ -240,11 +240,11 @@
     
     const VariableRepresentation& variableRepresentation() const { return u; }
     
-    void dump(FILE*) const;
+    void dump(PrintStream&) const;
     
 private:
-    void dumpFillInfo(const char* name, FILE*) const;
-    void dumpSpillInfo(const char* name, FILE*) const;
+    void dumpFillInfo(const char* name, PrintStream&) const;
+    void dumpSpillInfo(const char* name, PrintStream&) const;
     
     NodeIndex m_index;
     
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.cpp b/Source/JavaScriptCore/disassembler/Disassembler.cpp
index 84bf2ec..3fed2cd 100644
--- a/Source/JavaScriptCore/disassembler/Disassembler.cpp
+++ b/Source/JavaScriptCore/disassembler/Disassembler.cpp
@@ -31,12 +31,12 @@
 
 namespace JSC {
 
-void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, FILE* out)
+void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
 {
     if (tryToDisassemble(codePtr, size, prefix, out))
         return;
     
-    fprintf(out, "%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size);
+    out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size);
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.h b/Source/JavaScriptCore/disassembler/Disassembler.h
index b87f3d3..a087a65 100644
--- a/Source/JavaScriptCore/disassembler/Disassembler.h
+++ b/Source/JavaScriptCore/disassembler/Disassembler.h
@@ -26,18 +26,17 @@
 #ifndef Disassembler_h
 #define Disassembler_h
 
-#include <stdio.h>
 #include <wtf/Platform.h>
-#include <wtf/StdLibExtras.h>
+#include <wtf/PrintStream.h>
 
 namespace JSC {
 
 class MacroAssemblerCodePtr;
 
 #if ENABLE(DISASSEMBLER)
-bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, FILE* out);
+bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, PrintStream&);
 #else
-inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*, FILE*)
+inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*, PrintStream&)
 {
     return false;
 }
@@ -45,7 +44,7 @@
 
 // Prints either the disassembly, or a line of text indicating that disassembly failed and
 // the range of machine code addresses.
-void disassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, FILE* out);
+void disassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, PrintStream& out);
 
 } // namespace JSC
 
diff --git a/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
index b6baed4..63c235b 100644
--- a/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
+++ b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
@@ -33,7 +33,7 @@
 
 namespace JSC {
 
-bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, FILE* out)
+bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
 {
     ud_t disassembler;
     ud_init(&disassembler);
@@ -50,7 +50,7 @@
     while (ud_disassemble(&disassembler)) {
         char pcString[20];
         snprintf(pcString, sizeof(pcString), "0x%lx", static_cast<unsigned long>(currentPC));
-        fprintf(out, "%s%16s: %s\n", prefix, pcString, ud_insn_asm(&disassembler));
+        out.printf("%s%16s: %s\n", prefix, pcString, ud_insn_asm(&disassembler));
         currentPC = disassembler.pc;
     }
     
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index 5908fe2..4e9ea8e 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,72 @@
+2012-11-21  Filip Pizlo  <fpizlo@apple.com>
+
+        Any function that can log things should be able to easily log them to a memory buffer as well
+        https://bugs.webkit.org/show_bug.cgi?id=103000
+
+        Reviewed by Sam Weinig.
+
+        We have a number of places where we pass around a FILE* as a target to which to print
+        some logging information. But the purpose of passing FILE* instead of always assuming
+        that we should dump to stderr is that it may be sometimes useful to send the logging
+        information elsewhere. Unfortunately, FILE* isn't quite powerful enough: it's combersome
+        to use it to send logging to a string, for example.
+        
+        We could get around this by using <iostream> and <sstream>, but so far this aspect of
+        C++ has not been part of the WebKit coding conventions. Personally I find <iostream>
+        awkward due to its abuse of operator overloading.
+        
+        So this patch introduces the PrintStream abstract class, which offers printf-like
+        functionality while completely abstracting the destination and mechanism of the printing
+        output. It would be trivial to implement a StringPrintStream, for example. This will feed
+        into work on https://bugs.webkit.org/show_bug.cgi?id=102999.
+        
+        This also sets us up for creating templatized print() and println() methods that will
+        allow us to say things like out.print("count = ", count, "\n"), but that is the topic
+        of https://bugs.webkit.org/show_bug.cgi?id=103009.
+        
+        This patch also changes dataLog() to use FilePrintStream internally, and WTF::dataFile()
+        now returns a FilePrintStream&. Any previous users of WTF::dataFile() have been changed
+        to expect a PrintStream&.
+
+        * GNUmakefile.list.am:
+        * WTF.pro:
+        * WTF.vcproj/WTF.vcproj:
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/DataLog.cpp:
+        (WTF):
+        (WTF::initializeLogFileOnce):
+        (WTF::initializeLogFile):
+        (WTF::dataFile):
+        (WTF::dataLogV):
+        (WTF::dataLogString):
+        * wtf/DataLog.h:
+        (WTF):
+        * wtf/FilePrintStream.cpp: Added.
+        (WTF):
+        (WTF::FilePrintStream::FilePrintStream):
+        (WTF::FilePrintStream::~FilePrintStream):
+        (WTF::FilePrintStream::vprintf):
+        (WTF::FilePrintStream::flush):
+        * wtf/FilePrintStream.h: Added.
+        (WTF):
+        (FilePrintStream):
+        (WTF::FilePrintStream::file):
+        * wtf/PrintStream.cpp: Added.
+        (WTF):
+        (WTF::PrintStream::PrintStream):
+        (WTF::PrintStream::~PrintStream):
+        (WTF::PrintStream::printf):
+        (WTF::PrintStream::print):
+        (WTF::PrintStream::println):
+        (WTF::PrintStream::flush):
+        (WTF::print):
+        * wtf/PrintStream.h: Added.
+        (WTF):
+        (PrintStream):
+        (WTF::print):
+        (WTF::println):
+
 2012-11-23  Robert Kroeger  <rjkroege@chromium.org>
 
         Remove unused ScrollByPixelVelocity
diff --git a/Source/WTF/GNUmakefile.list.am b/Source/WTF/GNUmakefile.list.am
index f9db8c0..a9337b7 100644
--- a/Source/WTF/GNUmakefile.list.am
+++ b/Source/WTF/GNUmakefile.list.am
@@ -47,6 +47,8 @@
     Source/WTF/wtf/FastBitVector.h \
     Source/WTF/wtf/FastMalloc.cpp \
     Source/WTF/wtf/FastMalloc.h \
+    Source/WTF/wtf/FilePrintStream.cpp \
+    Source/WTF/wtf/FilePrintStream.h \
     Source/WTF/wtf/FixedArray.h \
     Source/WTF/wtf/Float32Array.h \
     Source/WTF/wtf/Float64Array.h \
@@ -128,6 +130,8 @@
     Source/WTF/wtf/PassTraits.h \
     Source/WTF/wtf/Platform.h \
     Source/WTF/wtf/PossiblyNull.h \
+    Source/WTF/wtf/PrintStream.cpp \
+    Source/WTF/wtf/PrintStream.h \
     Source/WTF/wtf/RandomNumber.cpp \
     Source/WTF/wtf/RandomNumber.h \
     Source/WTF/wtf/RandomNumberSeed.h \
diff --git a/Source/WTF/WTF.gypi b/Source/WTF/WTF.gypi
index 28eb576..34b7f4b 100644
--- a/Source/WTF/WTF.gypi
+++ b/Source/WTF/WTF.gypi
@@ -31,6 +31,7 @@
             'wtf/Encoder.h',
             'wtf/FastAllocBase.h',
             'wtf/FastMalloc.h',
+            'wtf/FilePrintStream.h',
             'wtf/FixedArray.h',
             'wtf/Forward.h',
             'wtf/Functional.h',
@@ -82,6 +83,7 @@
             'wtf/Platform.h',
             'wtf/Platform.h',
             'wtf/PossiblyNull.h',
+            'wtf/PrintStream.h',
             'wtf/RandomNumber.h',
             'wtf/RefCounted.h',
             'wtf/RefCountedLeakCounter.h',
@@ -157,6 +159,7 @@
             'wtf/DynamicAnnotations.cpp',
             'wtf/DynamicAnnotations.h',
             'wtf/FastMalloc.cpp',
+            'wtf/FilePrintStream.cpp',
             'wtf/Float32Array.h',
             'wtf/Float64Array.h',
             'wtf/GregorianDateTime.cpp',
@@ -186,6 +189,7 @@
             'wtf/ParallelJobsGeneric.h',
             'wtf/ParallelJobsLibdispatch.h',
             'wtf/ParallelJobsOpenMP.h',
+            'wtf/PrintStream.cpp',
             'wtf/RandomNumber.cpp',
             'wtf/RandomNumberSeed.h',
             'wtf/RefCountedLeakCounter.cpp',
diff --git a/Source/WTF/WTF.pro b/Source/WTF/WTF.pro
index 80cff2a..90286c2 100644
--- a/Source/WTF/WTF.pro
+++ b/Source/WTF/WTF.pro
@@ -61,6 +61,7 @@
     ExportMacros.h \
     FastAllocBase.h \
     FastMalloc.h \
+    FilePrintStream.h \
     FixedArray.h \
     Float32Array.h \
     Float64Array.h \
@@ -127,6 +128,7 @@
     PassTraits.h \
     Platform.h \
     PossiblyNull.h \
+    PrintStream.h \
     RandomNumber.h \
     RandomNumberSeed.h \
     RedBlackTree.h \
@@ -208,6 +210,7 @@
     dtoa/fixed-dtoa.cc \
     dtoa/strtod.cc \
     FastMalloc.cpp \
+    FilePrintStream.cpp \
     GregorianDateTime.cpp \
     gobject/GOwnPtr.cpp \
     gobject/GRefPtr.cpp \
@@ -226,6 +229,7 @@
     PageAllocationAligned.cpp \
     PageBlock.cpp \
     ParallelJobsGeneric.cpp \
+    PrintStream.cpp \
     RandomNumber.cpp \
     RefCountedLeakCounter.cpp \
     SHA1.cpp \
diff --git a/Source/WTF/WTF.vcproj/WTF.vcproj b/Source/WTF/WTF.vcproj/WTF.vcproj
index 68633af..f847eb0 100644
--- a/Source/WTF/WTF.vcproj/WTF.vcproj
+++ b/Source/WTF/WTF.vcproj/WTF.vcproj
@@ -781,6 +781,14 @@
 			>
 		</File>
 		<File
+			RelativePath="..\wtf\FilePrintStream.cpp"
+			>
+		</File>
+		<File
+			RelativePath="..\wtf\FilePrintStream.h"
+			>
+		</File>
+		<File
 			RelativePath="..\wtf\FixedArray.h"
 			>
 		</File>
@@ -1097,6 +1105,14 @@
 			>
 		</File>
 		<File
+			RelativePath="..\wtf\PrintStream.cpp"
+			>
+		</File>
+		<File
+			RelativePath="..\wtf\PrintStream.h"
+			>
+		</File>
+		<File
 			RelativePath="..\wtf\RandomNumber.cpp"
 			>
 		</File>
diff --git a/Source/WTF/WTF.xcodeproj/project.pbxproj b/Source/WTF/WTF.xcodeproj/project.pbxproj
index b27631d..58cda16 100644
--- a/Source/WTF/WTF.xcodeproj/project.pbxproj
+++ b/Source/WTF/WTF.xcodeproj/project.pbxproj
@@ -21,6 +21,10 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+		0F9D3360165DBA73005AD387 /* FilePrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */; };
+		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 */; };
 		0FD81AC5154FB22E00983E72 /* FastBitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD81AC4154FB22E00983E72 /* FastBitVector.h */; settings = {ATTRIBUTES = (); }; };
 		143F611F1565F0F900DB514A /* RAMSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 143F611D1565F0F900DB514A /* RAMSize.cpp */; };
 		143F61201565F0F900DB514A /* RAMSize.h in Headers */ = {isa = PBXBuildFile; fileRef = 143F611E1565F0F900DB514A /* RAMSize.h */; settings = {ATTRIBUTES = (); }; };
@@ -314,6 +318,10 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FilePrintStream.cpp; sourceTree = "<group>"; };
+		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>"; };
 		0FD81AC4154FB22E00983E72 /* FastBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastBitVector.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>"; };
@@ -711,6 +719,8 @@
 				0FD81AC4154FB22E00983E72 /* FastBitVector.h */,
 				A8A472A1151A825A004123FF /* FastMalloc.cpp */,
 				A8A472A2151A825A004123FF /* FastMalloc.h */,
+				0F9D335B165DBA73005AD387 /* FilePrintStream.cpp */,
+				0F9D335C165DBA73005AD387 /* FilePrintStream.h */,
 				A8A472A3151A825A004123FF /* FixedArray.h */,
 				A8A472A4151A825A004123FF /* Float32Array.h */,
 				A8A472A5151A825A004123FF /* Float64Array.h */,
@@ -789,8 +799,9 @@
 				A8A472ED151A825B004123FF /* PassRefPtr.h */,
 				A8A472EE151A825B004123FF /* PassTraits.h */,
 				A8A472EF151A825B004123FF /* Platform.h */,
-				A876DBD7151816E500DADB95 /* Platform.h */,
 				A8A472F3151A825B004123FF /* PossiblyNull.h */,
+				0F9D335D165DBA73005AD387 /* PrintStream.cpp */,
+				0F9D335E165DBA73005AD387 /* PrintStream.h */,
 				143F611D1565F0F900DB514A /* RAMSize.cpp */,
 				143F611E1565F0F900DB514A /* RAMSize.h */,
 				A8A472FB151A825B004123FF /* RandomNumber.cpp */,
@@ -854,6 +865,7 @@
 				A8A47372151A825B004123FF /* VMTags.h */,
 				A8A4737A151A825B004123FF /* WTFThreadData.cpp */,
 				A8A4737B151A825B004123FF /* WTFThreadData.h */,
+				A876DBD7151816E500DADB95 /* Platform.h */,
 			);
 			path = wtf;
 			sourceTree = "<group>";
@@ -1223,6 +1235,8 @@
 				A8A47480151A825B004123FF /* VMTags.h in Headers */,
 				A8A47446151A825B004123FF /* WTFString.h in Headers */,
 				A8A47487151A825B004123FF /* WTFThreadData.h in Headers */,
+				0F9D3361165DBA73005AD387 /* FilePrintStream.h in Headers */,
+				0F9D3363165DBA73005AD387 /* PrintStream.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1391,6 +1405,8 @@
 				A8A47469151A825B004123FF /* UTF8.cpp in Sources */,
 				A8A47445151A825B004123FF /* WTFString.cpp in Sources */,
 				A8A47486151A825B004123FF /* WTFThreadData.cpp in Sources */,
+				0F9D3360165DBA73005AD387 /* FilePrintStream.cpp in Sources */,
+				0F9D3362165DBA73005AD387 /* PrintStream.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Source/WTF/wtf/CMakeLists.txt b/Source/WTF/wtf/CMakeLists.txt
index cafe104..4f822a54 100644
--- a/Source/WTF/wtf/CMakeLists.txt
+++ b/Source/WTF/wtf/CMakeLists.txt
@@ -26,6 +26,7 @@
     Encoder.h
     FastAllocBase.h
     FastMalloc.h
+    FilePrintStream.h
     FixedArray.h
     Forward.h
     GetPtr.h
@@ -86,6 +87,7 @@
     ParallelJobsOpenMP.h
     Platform.h
     PossiblyNull.h
+    PrintStream.h
     RandomNumber.h
     RandomNumberSeed.h
     RedBlackTree.h
@@ -161,6 +163,7 @@
     DecimalNumber.cpp
     DynamicAnnotations.cpp
     FastMalloc.cpp
+    FilePrintStream.cpp
     GregorianDateTime.cpp
     HashTable.cpp
     MD5.cpp
@@ -174,6 +177,7 @@
     PageAllocationAligned.cpp
     PageBlock.cpp
     ParallelJobsGeneric.cpp
+    PrintStream.cpp
     RandomNumber.cpp
     RefCountedLeakCounter.cpp
     SHA1.cpp
diff --git a/Source/WTF/wtf/DataLog.cpp b/Source/WTF/wtf/DataLog.cpp
index 523567c..97e0e97 100644
--- a/Source/WTF/wtf/DataLog.cpp
+++ b/Source/WTF/wtf/DataLog.cpp
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "DataLog.h"
 #include <stdarg.h>
+#include <wtf/FilePrintStream.h>
 #include <wtf/Threading.h>
 
 #define DATA_LOG_TO_FILE 0
@@ -35,34 +36,37 @@
 
 namespace WTF {
 
-#if DATA_LOG_TO_FILE
-static FILE* file;
+#if USE(PTHREADS)
+static pthread_once_t initializeLogFileOnceKey = PTHREAD_ONCE_INIT;
+#endif
+
+static FilePrintStream* file;
 
 static void initializeLogFileOnce()
 {
+#if DATA_LOG_TO_FILE
 #ifdef DATA_LOG_FILENAME
     const char* filename = DATA_LOG_FILENAME;
 #else
     const char* filename = getenv("WTF_DATA_LOG_FILENAME");
 #endif
     if (filename) {
-        file = fopen(filename, "w");
-        if (!file)
+        FILE* rawFile = fopen(filename, "w");
+        if (rawFile)
+            file = new FilePrintStream(rawFile);
+        else
             fprintf(stderr, "Warning: Could not open log file %s for writing.\n", filename);
     }
+#endif // DATA_LOG_TO_FILE
     if (!file)
-        file = stderr;
+        file = new FilePrintStream(stderr, FilePrintStream::Borrow);
     
-    setvbuf(file, 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
+    setvbuf(file->file(), 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
 }
 
-#if OS(DARWIN)
-static pthread_once_t initializeLogFileOnceKey = PTHREAD_ONCE_INIT;
-#endif
-
 static void initializeLogFile()
 {
-#if OS(DARWIN)
+#if USE(PTHREADS)
     pthread_once(&initializeLogFileOnceKey, initializeLogFileOnce);
 #else
     if (!file)
@@ -70,21 +74,15 @@
 #endif
 }
 
-FILE* dataFile()
+FilePrintStream& dataFile()
 {
     initializeLogFile();
-    return file;
+    return *file;
 }
-#else // DATA_LOG_TO_FILE
-FILE* dataFile()
-{
-    return stderr;
-}
-#endif // DATA_LOG_TO_FILE
 
 void dataLogFV(const char* format, va_list argList)
 {
-    vfprintf(dataFile(), format, argList);
+    dataFile().vprintf(format, argList);
 }
 
 void dataLogF(const char* format, ...)
@@ -97,7 +95,7 @@
 
 void dataLogFString(const char* str)
 {
-    fputs(str, dataFile());
+    dataFile().printf("%s", str);
 }
 
 } // namespace WTF
diff --git a/Source/WTF/wtf/DataLog.h b/Source/WTF/wtf/DataLog.h
index 12dd523..ebb7cbe 100644
--- a/Source/WTF/wtf/DataLog.h
+++ b/Source/WTF/wtf/DataLog.h
@@ -28,12 +28,13 @@
 
 #include <stdarg.h>
 #include <stdio.h>
+#include <wtf/FilePrintStream.h>
 #include <wtf/Platform.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WTF {
 
-WTF_EXPORT_PRIVATE FILE* dataFile();
+WTF_EXPORT_PRIVATE FilePrintStream& dataFile();
 
 WTF_EXPORT_PRIVATE void dataLogFV(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(1, 0);
 WTF_EXPORT_PRIVATE void dataLogF(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
diff --git a/Source/WTF/wtf/FilePrintStream.cpp b/Source/WTF/wtf/FilePrintStream.cpp
new file mode 100644
index 0000000..2deea68
--- /dev/null
+++ b/Source/WTF/wtf/FilePrintStream.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 "FilePrintStream.h"
+
+namespace WTF {
+
+FilePrintStream::FilePrintStream(FILE* file, AdoptionMode adoptionMode)
+    : m_file(file)
+    , m_adoptionMode(adoptionMode)
+{
+}
+
+FilePrintStream::~FilePrintStream()
+{
+    if (m_adoptionMode == Borrow)
+        return;
+    fclose(m_file);
+}
+
+void FilePrintStream::vprintf(const char* format, va_list argList)
+{
+    vfprintf(m_file, format, argList);
+}
+
+void FilePrintStream::flush()
+{
+    fflush(m_file);
+}
+
+} // namespace WTF
+
diff --git a/Source/WTF/wtf/FilePrintStream.h b/Source/WTF/wtf/FilePrintStream.h
new file mode 100644
index 0000000..c9af344
--- /dev/null
+++ b/Source/WTF/wtf/FilePrintStream.h
@@ -0,0 +1,59 @@
+/*
+ * 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 FilePrintStream_h
+#define FilePrintStream_h
+
+#include <stdio.h>
+#include <wtf/PrintStream.h>
+
+namespace WTF {
+
+class FilePrintStream : public PrintStream {
+public:
+    enum AdoptionMode {
+        Adopt,
+        Borrow
+    };
+    
+    FilePrintStream(FILE*, AdoptionMode = Adopt);
+    virtual ~FilePrintStream();
+    
+    FILE* file() { return m_file; }
+    
+    void vprintf(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(2, 0);
+    void flush();
+
+private:
+    FILE* m_file;
+    AdoptionMode m_adoptionMode;
+};
+
+} // namespace WTF
+
+using WTF::FilePrintStream;
+
+#endif // FilePrintStream_h
+
diff --git a/Source/WTF/wtf/PrintStream.cpp b/Source/WTF/wtf/PrintStream.cpp
new file mode 100644
index 0000000..5d77a83
--- /dev/null
+++ b/Source/WTF/wtf/PrintStream.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "PrintStream.h"
+
+#include <stdio.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTF {
+
+PrintStream::PrintStream() { }
+PrintStream::~PrintStream() { } // Force the vtable to be in this module
+
+void PrintStream::printf(const char* format, ...)
+{
+    va_list argList;
+    va_start(argList, format);
+    vprintf(format, argList);
+    va_end(argList);
+}
+
+void PrintStream::flush()
+{
+}
+
+} // namespace WTF
+
diff --git a/Source/WTF/wtf/PrintStream.h b/Source/WTF/wtf/PrintStream.h
new file mode 100644
index 0000000..3158488
--- /dev/null
+++ b/Source/WTF/wtf/PrintStream.h
@@ -0,0 +1,59 @@
+/*
+ * 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 PrintStream_h
+#define PrintStream_h
+
+#include <stdarg.h>
+#include <wtf/FastAllocBase.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+class CString;
+class String;
+
+class PrintStream {
+    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(PrintStream);
+public:
+    PrintStream();
+    virtual ~PrintStream();
+
+    void printf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+    virtual void vprintf(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(2, 0) = 0;
+
+    // Typically a no-op for many subclasses of PrintStream, this is a hint that
+    // the implementation should flush its buffers if it had not done so already.
+    virtual void flush();
+};
+
+} // namespace WTF
+
+using WTF::PrintStream;
+
+#endif // PrintStream_h
+