<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[213151] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/213151">213151</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2017-02-28 10:50:00 -0800 (Tue, 28 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add ability to configure JSC options from a file
https://bugs.webkit.org/show_bug.cgi?id=168914

Reviewed by Filip Pizlo.

Added the ability to set options and DataLog file location via a configuration file.
Source/JavaScriptCore:

The configuration file is specified with the --configFile option to JSC or the
JSC_configFile environment variable.

The file format allows for options conditionally dependent on various attributes.
Currently those attributes are the process name, parent process name and build
type (Release or Debug).  In this patch, the parent process type is not set.
That will be set up in WebKit code with a follow up patch.

Here is an example config file:

    logFile = &quot;/tmp/jscLog.%pid.txt&quot;

    jscOptions {
        dumpOptions = 2
    }

    build == &quot;Debug&quot; {
        jscOptions {
            useConcurrentJIT = false
            dumpDisassembly = true
        }
    }

    build == &quot;Release&quot; &amp;&amp; processName == &quot;jsc&quot; {
        jscOptions {
            asyncDisassembly = true
        }
    }

Eliminated the prior options file code.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* jsc.cpp:
(jscmain):
* runtime/ConfigFile.cpp: Added.
(JSC::ConfigFileScanner::ConfigFileScanner):
(JSC::ConfigFileScanner::start):
(JSC::ConfigFileScanner::lineNumber):
(JSC::ConfigFileScanner::currentBuffer):
(JSC::ConfigFileScanner::atFileEnd):
(JSC::ConfigFileScanner::tryConsume):
(JSC::ConfigFileScanner::tryConsumeString):
(JSC::ConfigFileScanner::tryConsumeUpto):
(JSC::ConfigFileScanner::fillBufferIfNeeded):
(JSC::ConfigFileScanner::fillBuffer):
(JSC::ConfigFile::ConfigFile):
(JSC::ConfigFile::setProcessName):
(JSC::ConfigFile::setParentProcessName):
(JSC::ConfigFile::parse):
* runtime/ConfigFile.h: Added.
* runtime/Options.cpp:
(JSC::Options::initialize):
(JSC::Options::setOptions):
* runtime/Options.h:

Source/WTF:

The pathname can include the printf style &quot;%pid&quot;, which will be replaced with the
current process id.

* wtf/DataLog.cpp:
(WTF::initializeLogFileOnce):
(WTF::setDataFile):
* wtf/DataLog.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionscpp">trunk/Source/JavaScriptCore/runtime/Options.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfDataLogcpp">trunk/Source/WTF/wtf/DataLog.cpp</a></li>
<li><a href="#trunkSourceWTFwtfDataLogh">trunk/Source/WTF/wtf/DataLog.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreruntimeConfigFilecpp">trunk/Source/JavaScriptCore/runtime/ConfigFile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeConfigFileh">trunk/Source/JavaScriptCore/runtime/ConfigFile.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -690,6 +690,7 @@
</span><span class="cx">     runtime/CommonSlowPathsExceptions.cpp
</span><span class="cx">     runtime/CompilationResult.cpp
</span><span class="cx">     runtime/Completion.cpp
</span><ins>+    runtime/ConfigFile.cpp
</ins><span class="cx">     runtime/ConsoleClient.cpp
</span><span class="cx">     runtime/ConsoleObject.cpp
</span><span class="cx">     runtime/ConstantMode.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -1,3 +1,67 @@
</span><ins>+2017-02-28  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        Add ability to configure JSC options from a file
+        https://bugs.webkit.org/show_bug.cgi?id=168914
+
+        Reviewed by Filip Pizlo.
+
+        Added the ability to set options and DataLog file location via a configuration file.
+        The configuration file is specified with the --configFile option to JSC or the
+        JSC_configFile environment variable.
+
+        The file format allows for options conditionally dependent on various attributes.
+        Currently those attributes are the process name, parent process name and build
+        type (Release or Debug).  In this patch, the parent process type is not set.
+        That will be set up in WebKit code with a follow up patch.
+
+        Here is an example config file:
+
+            logFile = &quot;/tmp/jscLog.%pid.txt&quot;
+
+            jscOptions {
+                dumpOptions = 2
+            }
+
+            build == &quot;Debug&quot; {
+                jscOptions {
+                    useConcurrentJIT = false
+                    dumpDisassembly = true
+                }
+            }
+
+            build == &quot;Release&quot; &amp;&amp; processName == &quot;jsc&quot; {
+                jscOptions {
+                    asyncDisassembly = true
+                }
+            }
+
+        Eliminated the prior options file code.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * jsc.cpp:
+        (jscmain):
+        * runtime/ConfigFile.cpp: Added.
+        (JSC::ConfigFileScanner::ConfigFileScanner):
+        (JSC::ConfigFileScanner::start):
+        (JSC::ConfigFileScanner::lineNumber):
+        (JSC::ConfigFileScanner::currentBuffer):
+        (JSC::ConfigFileScanner::atFileEnd):
+        (JSC::ConfigFileScanner::tryConsume):
+        (JSC::ConfigFileScanner::tryConsumeString):
+        (JSC::ConfigFileScanner::tryConsumeUpto):
+        (JSC::ConfigFileScanner::fillBufferIfNeeded):
+        (JSC::ConfigFileScanner::fillBuffer):
+        (JSC::ConfigFile::ConfigFile):
+        (JSC::ConfigFile::setProcessName):
+        (JSC::ConfigFile::setParentProcessName):
+        (JSC::ConfigFile::parse):
+        * runtime/ConfigFile.h: Added.
+        * runtime/Options.cpp:
+        (JSC::Options::initialize):
+        (JSC::Options::setOptions):
+        * runtime/Options.h:
+
</ins><span class="cx"> 2017-02-27  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Begin enabling WebRTC on 64-bit
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -1386,6 +1386,8 @@
</span><span class="cx">                 655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 655EB29A10CE2581001A990E /* NodesCodegen.cpp */; };
</span><span class="cx">                 657CF45819BF6662004ACBF2 /* JSCallee.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 657CF45619BF6662004ACBF2 /* JSCallee.cpp */; };
</span><span class="cx">                 657CF45919BF6662004ACBF2 /* JSCallee.h in Headers */ = {isa = PBXBuildFile; fileRef = 657CF45719BF6662004ACBF2 /* JSCallee.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                658824AF1E5CFDB000FB7359 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 658824AE1E5CFDB000FB7359 /* ConfigFile.h */; };
+                658824B11E5CFDF400FB7359 /* ConfigFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 658824B01E5CFDF400FB7359 /* ConfigFile.cpp */; };
</ins><span class="cx">                 658D3A5619638268003C45D6 /* VMEntryRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 658D3A5519638268003C45D6 /* VMEntryRecord.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 65B8392E1BACAD360044E824 /* CachedRecovery.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B8392C1BACA92A0044E824 /* CachedRecovery.h */; };
</span><span class="cx">                 65B8392F1BACAD6A0044E824 /* CachedRecovery.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65B8392D1BACA9D30044E824 /* CachedRecovery.cpp */; };
</span><span class="lines">@@ -3870,6 +3872,8 @@
</span><span class="cx">                 657CF45619BF6662004ACBF2 /* JSCallee.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCallee.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 657CF45719BF6662004ACBF2 /* JSCallee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallee.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 65860177185A8F5E00030EEE /* MaxFrameExtentForSlowPathCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MaxFrameExtentForSlowPathCall.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                658824AE1E5CFDB000FB7359 /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigFile.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                658824B01E5CFDF400FB7359 /* ConfigFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConfigFile.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 658D3A5519638268003C45D6 /* VMEntryRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VMEntryRecord.h; sourceTree = &quot;&lt;group&gt;&quot;; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
</span><span class="cx">                 65987F2C167FE84B003C2F8D /* DFGOSRExitCompilationInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompilationInfo.h; path = dfg/DFGOSRExitCompilationInfo.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 65987F2F16828A7E003C2F8D /* UnusedPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnusedPointer.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -6354,6 +6358,8 @@
</span><span class="cx">                                 A7E5A3A61797432D00E893C0 /* CompilationResult.h */,
</span><span class="cx">                                 969A09220ED1E09C00F1F681 /* Completion.cpp */,
</span><span class="cx">                                 F5BB2BC5030F772101FCFE1D /* Completion.h */,
</span><ins>+                                658824B01E5CFDF400FB7359 /* ConfigFile.cpp */,
+                                658824AE1E5CFDB000FB7359 /* ConfigFile.h */,
</ins><span class="cx">                                 0FDB2CE9174896C7007B3C1B /* ConcurrentJSLock.h */,
</span><span class="cx">                                 A5B6A74C18C6DBA600F11E91 /* ConsoleClient.cpp */,
</span><span class="cx">                                 A53CE08918BC21C300BEDF76 /* ConsoleClient.h */,
</span><span class="lines">@@ -8364,6 +8370,7 @@
</span><span class="cx">                                 A7D89CFE17A0B8CC00773AD8 /* DFGOSRAvailabilityAnalysisPhase.h in Headers */,
</span><span class="cx">                                 0FD82E57141DAF1000179C94 /* DFGOSREntry.h in Headers */,
</span><span class="cx">                                 0FD8A32617D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.h in Headers */,
</span><ins>+                                658824AF1E5CFDB000FB7359 /* ConfigFile.h in Headers */,
</ins><span class="cx">                                 0FC0976A1468A6F700CF2442 /* DFGOSRExit.h in Headers */,
</span><span class="cx">                                 0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */,
</span><span class="cx">                                 0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
</span><span class="lines">@@ -10377,6 +10384,7 @@
</span><span class="cx">                                 140B7D1D0DC69AF7009C42B8 /* JSLexicalEnvironment.cpp in Sources */,
</span><span class="cx">                                 14280875107EC13E0013E7B2 /* JSLock.cpp in Sources */,
</span><span class="cx">                                 C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */,
</span><ins>+                                658824B11E5CFDF400FB7359 /* ConfigFile.cpp in Sources */,
</ins><span class="cx">                                 A700874117CBE8EB00C3E643 /* JSMap.cpp in Sources */,
</span><span class="cx">                                 A74DEF95182D991400522C22 /* JSMapIterator.cpp in Sources */,
</span><span class="cx">                                 E3D239C81B829C1C00BBEF67 /* JSModuleEnvironment.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;ButterflyInlines.h&quot;
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;Completion.h&quot;
</span><ins>+#include &quot;ConfigFile.h&quot;
</ins><span class="cx"> #include &quot;DOMJITGetterSetter.h&quot;
</span><span class="cx"> #include &quot;DOMJITPatchpoint.h&quot;
</span><span class="cx"> #include &quot;DOMJITPatchpointParams.h&quot;
</span><span class="lines">@@ -3762,6 +3763,12 @@
</span><span class="cx">     // comes first.
</span><span class="cx">     CommandLine options(argc, argv);
</span><span class="cx"> 
</span><ins>+    if (Options::configFile()) {
+        ConfigFile configFile(Options::configFile());
+        configFile.setProcessName(&quot;jsc&quot;);
+        configFile.parse();
+    }
+
</ins><span class="cx">     // Initialize JSC before getting VM.
</span><span class="cx">     WTF::initializeMainThread();
</span><span class="cx">     JSC::initializeThreading();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeConfigFilecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/runtime/ConfigFile.cpp (0 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ConfigFile.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/runtime/ConfigFile.cpp        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -0,0 +1,413 @@
</span><ins>+/*
+ * Copyright (C) 2017 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 &quot;config.h&quot;
+#include &quot;ConfigFile.h&quot;
+
+#include &quot;Options.h&quot;
+#include &lt;limits.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;wtf/ASCIICType.h&gt;
+#include &lt;wtf/DataLog.h&gt;
+#include &lt;wtf/StringExtras.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace JSC {
+
+static const size_t s_processNameMax = 128;
+#if PLATFORM(WIN)
+static const size_t s_maxPathLength = 260; // Windows value for &quot;MAX_PATH&quot;
+#else
+static const size_t s_maxPathLength = PATH_MAX;
+#endif
+char ConfigFile::s_processName[s_processNameMax + 1] = { 0 };
+char ConfigFile::s_parentProcessName[s_processNameMax + 1] = { 0 };
+
+class ConfigFileScanner {
+public:
+    ConfigFileScanner(const char* filename)
+        : m_filename(filename)
+        , m_lineNumber(0)
+    {
+        m_srcPtr = &amp;m_buffer[0];
+        m_bufferEnd = &amp;m_buffer[0];
+    }
+
+    bool start()
+    {
+        m_file = fopen(m_filename, &quot;r&quot;);
+        if (!m_file) {
+            dataLogF(&quot;Failed to open file JSC Config file '%s'.\n&quot;, m_filename);
+            return false;
+        }
+
+        return true;
+    }
+
+    unsigned lineNumber()
+    {
+        return m_lineNumber;
+    }
+
+    const char* currentBuffer()
+    {
+        if (!m_srcPtr || m_srcPtr == m_bufferEnd)
+            return &quot;&quot;;
+
+        return m_srcPtr;
+    }
+
+    bool atFileEnd()
+    {
+        if (!fillBufferIfNeeded())
+            return true;
+
+        return false;
+    }
+
+    bool tryConsume(char c)
+    {
+        if (!fillBufferIfNeeded())
+            return false;
+
+        if (c == *m_srcPtr) {
+            m_srcPtr++;
+            return true;
+        }
+
+        return false;
+    }
+
+    template &lt;size_t length&gt;
+    bool tryConsume(const char (&amp;token) [length])
+    {
+        if (!fillBufferIfNeeded())
+            return false;
+
+        size_t tokenLength = length - 1;
+        if (!strncmp(m_srcPtr, token, tokenLength)) {
+            m_srcPtr += tokenLength;
+            return true;
+        }
+
+        return false;
+    }
+
+    char* tryConsumeString()
+    {
+        if (!fillBufferIfNeeded())
+            return nullptr;
+
+        if (*m_srcPtr != '&quot;')
+            return nullptr;
+
+        char* stringStart = ++m_srcPtr;
+
+        char* stringEnd = strchr(m_srcPtr, '&quot;');
+        if (stringEnd) {
+            *stringEnd = '\0';
+            m_srcPtr = stringEnd + 1;
+            return stringStart;
+        }
+
+        return nullptr;
+    }
+
+    char* tryConsumeUpto(bool&amp; foundChar, char c)
+    {
+        if (!fillBufferIfNeeded())
+            return nullptr;
+
+        char* start = m_srcPtr;
+        foundChar = false;
+
+        char* cPosition = strchr(m_srcPtr, c);
+        if (cPosition) {
+            *cPosition = '\0';
+            m_srcPtr = cPosition + 1;
+            foundChar = true;
+        } else
+            m_srcPtr = m_bufferEnd;
+
+        return start;
+    }
+
+private:
+    bool fillBufferIfNeeded()
+    {
+        if (!m_srcPtr)
+            return false;
+
+        while (true) {
+            while (m_srcPtr != m_bufferEnd &amp;&amp; isASCIISpace(*m_srcPtr))
+                m_srcPtr++;
+
+            if (m_srcPtr != m_bufferEnd)
+                break;
+
+            if (!fillBuffer())
+                return false;
+        }
+
+        return true;
+    }
+
+    bool fillBuffer()
+    {
+        do {
+            m_srcPtr = fgets(m_buffer, sizeof(m_buffer), m_file);
+            if (!m_srcPtr) {
+                fclose(m_file);
+                return false;
+            }
+
+            m_lineNumber++;
+
+            m_bufferEnd = strchr(m_srcPtr, '#');
+
+            if (m_bufferEnd)
+                *m_bufferEnd = '\0';
+            else {
+                m_bufferEnd = m_srcPtr + strlen(m_srcPtr);
+                if (m_bufferEnd &gt; m_srcPtr &amp;&amp; m_bufferEnd[-1] == '\n') {
+                    m_bufferEnd--;
+                    *m_bufferEnd = '\0';
+                }
+            }
+        } while (m_bufferEnd == m_srcPtr);
+
+        return true;
+    }
+
+    const char* m_filename;
+    unsigned m_lineNumber;
+    FILE* m_file;
+    char m_buffer[BUFSIZ];
+    char* m_srcPtr;
+    char* m_bufferEnd;
+};
+
+ConfigFile::ConfigFile(const char* filename)
+    : m_filename(filename)
+{
+}
+
+void ConfigFile::setProcessName(const char* processName)
+{
+    strncpy(s_processName, processName, s_processNameMax);
+}
+
+void ConfigFile::setParentProcessName(const char* parentProcessName)
+{
+    strncpy(s_parentProcessName, parentProcessName, s_processNameMax);
+}
+
+void ConfigFile::parse()
+{
+    enum StatementNesting { TopLevelStatment, NestedStatement, NestedStatementFailedCriteria };
+    enum ParseResult { ParseOK, ParseError, NestedStatementDone };
+
+    ConfigFileScanner scanner(m_filename);
+
+    if (!scanner.start())
+        return;
+
+    char logPathname[s_maxPathLength + 1] = { 0 };
+
+    StringBuilder jscOptionsBuilder;
+
+    auto parseLogFile = [&amp;](StatementNesting statementNesting) {
+        char* filename = nullptr;
+        if (scanner.tryConsume('=') &amp;&amp; (filename = scanner.tryConsumeString())) {
+            if (statementNesting != NestedStatementFailedCriteria)
+                strncpy(logPathname, filename, s_maxPathLength);
+
+            return ParseOK;
+        }
+
+        return ParseError;
+    };
+
+    auto parseJSCOptions = [&amp;](StatementNesting statementNesting) {
+        if (scanner.tryConsume('{')) {
+            StringBuilder builder;
+
+            bool foundClosingBrace = false;
+            char* currentLine = nullptr;
+
+            while ((currentLine = scanner.tryConsumeUpto(foundClosingBrace, '}'))) {
+                char* p = currentLine;
+
+                do {
+                    if (foundClosingBrace &amp;&amp; !*p)
+                        break;
+
+                    char* optionNameStart = p;
+
+                    while (*p &amp;&amp; !isASCIISpace(*p) &amp;&amp; *p != '=')
+                        p++;
+
+                    builder.append(optionNameStart, p - optionNameStart);
+
+                    while (*p &amp;&amp; isASCIISpace(*p) &amp;&amp; *p != '=')
+                        p++;
+
+                    if (!*p)
+                        return ParseError;
+                    p++; // Advance past the '='
+
+                    builder.append('=');
+
+                    while (*p &amp;&amp; isASCIISpace(*p))
+                        p++;
+
+                    if (!*p)
+                        return ParseError;
+
+                    char* optionValueStart = p;
+
+                    while (*p &amp;&amp; !isASCIISpace(*p))
+                        p++;
+
+                    builder.append(optionValueStart, p - optionValueStart);
+                    builder.append('\n');
+
+                    while (*p &amp;&amp; isASCIISpace(*p))
+                        p++;
+                } while (*p);
+
+                if (foundClosingBrace)
+                    break;
+            }
+
+            if (statementNesting != NestedStatementFailedCriteria)
+                jscOptionsBuilder.append(builder);
+
+            return ParseOK;
+        }
+
+        return ParseError;
+    };
+
+    auto parseNestedStatement = [&amp;](StatementNesting statementNesting) {
+        if (scanner.tryConsume(&quot;jscOptions&quot;))
+            return parseJSCOptions(statementNesting);
+
+        if (scanner.tryConsume(&quot;logFile&quot;))
+            return parseLogFile(statementNesting);
+
+        if (scanner.tryConsume('}'))
+            return NestedStatementDone;
+
+        return ParseError;
+    };
+
+    auto parsePredicate = [&amp;](bool&amp; predicateMatches, const char* matchValue) {
+        char* predicateValue = nullptr;
+        if (scanner.tryConsume(&quot;==&quot;)
+            &amp;&amp; (predicateValue = scanner.tryConsumeString()) &amp;&amp; matchValue) {
+                predicateMatches = !strcmp(predicateValue, matchValue);
+                return true;
+        }
+
+        return false;
+    };
+
+    auto parseConditionalBlock = [&amp;](StatementNesting statementNesting) {
+        if (statementNesting == NestedStatement) {
+            StatementNesting subNesting = NestedStatement;
+
+            while (true) {
+                bool predicateMatches;
+                const char* actualValue = nullptr;
+
+                if (scanner.tryConsume(&quot;processName&quot;))
+                    actualValue = s_processName;
+                else if (scanner.tryConsume(&quot;parentProcessName&quot;))
+                    actualValue = s_parentProcessName;
+                else if (scanner.tryConsume(&quot;build&quot;))
+#ifndef NDEBUG
+                    actualValue = &quot;Debug&quot;;
+#else
+                    actualValue = &quot;Release&quot;;
+#endif
+                else
+                    return ParseError;
+
+                if (parsePredicate(predicateMatches, actualValue)) {
+                    if (!predicateMatches)
+                        subNesting = NestedStatementFailedCriteria;
+
+                    if (!scanner.tryConsume(&quot;&amp;&amp;&quot;))
+                        break;
+                }
+            }
+
+            if (!scanner.tryConsume('{'))
+                return ParseError;
+
+            ParseResult parseResult = ParseOK;
+            while (parseResult == ParseOK &amp;&amp; !scanner.atFileEnd())
+                parseResult = parseNestedStatement(subNesting);
+
+            if (parseResult == NestedStatementDone)
+                return ParseOK;
+        }
+
+        return ParseError;
+    };
+
+    auto parseStatement = [&amp;](StatementNesting statementNesting) {
+        if (scanner.tryConsume(&quot;jscOptions&quot;))
+            return parseJSCOptions(statementNesting);
+
+        if (scanner.tryConsume(&quot;logFile&quot;))
+            return parseLogFile(statementNesting);
+
+        if (statementNesting == TopLevelStatment)
+            return parseConditionalBlock(NestedStatement);
+
+        return ParseError;
+    };
+
+    ParseResult parseResult = ParseOK;
+
+    while (parseResult == ParseOK &amp;&amp; !scanner.atFileEnd())
+        parseResult = parseStatement(TopLevelStatment);
+
+    if (parseResult == ParseOK) {
+        if (strlen(logPathname))
+            WTF::setDataFile(logPathname);
+
+        if (!jscOptionsBuilder.isEmpty()) {
+            const char* optionsStr = jscOptionsBuilder.toString().utf8().data();
+            Options::setOptions(optionsStr);
+        }
+    } else
+        WTF::dataLogF(&quot;Error in JSC Config file on or near line %u, parsing '%s'\n&quot;, scanner.lineNumber(), scanner.currentBuffer());
+}
+
+} // namespace JSC
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeConfigFileh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/runtime/ConfigFile.h (0 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ConfigFile.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/runtime/ConfigFile.h        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+namespace JSC {
+
+class ConfigFile {
+public:
+    JS_EXPORT_PRIVATE ConfigFile(const char*);
+
+    JS_EXPORT_PRIVATE static void setProcessName(const char*);
+    JS_EXPORT_PRIVATE static void setParentProcessName(const char*);
+    JS_EXPORT_PRIVATE void parse();
+
+private:
+    static char s_processName[];
+    static char s_parentProcessName[];
+
+    const char* m_filename;
+};
+
+} // namespace JSC
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.cpp (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.cpp        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/runtime/Options.cpp        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -51,9 +51,6 @@
</span><span class="cx"> #include &quot;MacroAssemblerX86.h&quot;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#define USE_OPTIONS_FILE 0
-#define OPTIONS_FILENAME &quot;/tmp/jsc.options&quot;
-
</del><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="cx"> namespace {
</span><span class="lines">@@ -496,31 +493,6 @@
</span><span class="cx">                 ; // Deconfuse editors that do auto indentation
</span><span class="cx"> #endif
</span><span class="cx">     
</span><del>-#if USE(OPTIONS_FILE)
-            {
-                const char* filename = OPTIONS_FILENAME;
-                FILE* optionsFile = fopen(filename, &quot;r&quot;);
-                if (!optionsFile) {
-                    dataLogF(&quot;Failed to open file %s. Did you add the file-read-data entitlement to WebProcess.sb?\n&quot;, filename);
-                    return;
-                }
-                
-                StringBuilder builder;
-                char* line;
-                char buffer[BUFSIZ];
-                while ((line = fgets(buffer, sizeof(buffer), optionsFile)))
-                    builder.append(buffer);
-                
-                const char* optionsStr = builder.toString().utf8().data();
-                dataLogF(&quot;Setting options: %s\n&quot;, optionsStr);
-                setOptions(optionsStr);
-                
-                int result = fclose(optionsFile);
-                if (result)
-                    dataLogF(&quot;Failed to close file %s: %s\n&quot;, filename, strerror(errno));
-            }
-#endif
-
</del><span class="cx">             recomputeDependentOptions();
</span><span class="cx"> 
</span><span class="cx">             // Do range checks where needed and make corrections to the options:
</span><span class="lines">@@ -628,7 +600,12 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    recomputeDependentOptions();
+
</ins><span class="cx">     dumpOptionsIfNeeded();
</span><ins>+
+    ensureOptionsAreCoherent();
+
</ins><span class="cx">     return success;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -103,6 +103,7 @@
</span><span class="cx"> #define JSC_OPTIONS(v) \
</span><span class="cx">     v(bool, validateOptions, false, Normal, &quot;crashes if mis-typed JSC options were passed to the VM&quot;) \
</span><span class="cx">     v(unsigned, dumpOptions, 0, Normal, &quot;dumps JSC options (0 = None, 1 = Overridden only, 2 = All, 3 = Verbose)&quot;) \
</span><ins>+    v(optionString, configFile, nullptr, Normal, &quot;file to configure JSC options and logging location&quot;) \
</ins><span class="cx">     \
</span><span class="cx">     v(bool, useLLInt,  true, Normal, &quot;allows the LLINT to be used if true&quot;) \
</span><span class="cx">     v(bool, useJIT,    true, Normal, &quot;allows the baseline JIT to be used if true&quot;) \
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/WTF/ChangeLog        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2017-02-28  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        Add ability to configure JSC options from a file
+        https://bugs.webkit.org/show_bug.cgi?id=168914
+
+        Reviewed by Filip Pizlo.
+
+        Added the ability to set options and DataLog file location via a configuration file.
+        The pathname can include the printf style &quot;%pid&quot;, which will be replaced with the
+        current process id.
+
+        * wtf/DataLog.cpp:
+        (WTF::initializeLogFileOnce):
+        (WTF::setDataFile):
+        * wtf/DataLog.h:
+
</ins><span class="cx"> 2017-02-27  Andy Estes  &lt;aestes@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS] Enable file replacement
</span></span></pre></div>
<a id="trunkSourceWTFwtfDataLogcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/DataLog.cpp (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/DataLog.cpp        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/WTF/wtf/DataLog.cpp        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -50,30 +50,22 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+static const size_t maxPathLength = 1024;
+
</ins><span class="cx"> static PrintStream* s_file;
</span><del>-
</del><span class="cx"> static uint64_t s_fileData[(sizeof(FilePrintStream) + 7) / 8];
</span><span class="cx"> static uint64_t s_lockedFileData[(sizeof(LockedPrintStream) + 7) / 8];
</span><span class="cx"> 
</span><span class="cx"> static void initializeLogFileOnce()
</span><span class="cx"> {
</span><del>-    FilePrintStream* file = nullptr;
-    
-#if DATA_LOG_TO_FILE
-    const long maxPathLength = 1024;
</del><ins>+    const char* filename = nullptr;
</ins><span class="cx"> 
</span><del>-    char filenameSuffix[maxPathLength + 1];
</del><ins>+    if (s_file)
+        return;
</ins><span class="cx"> 
</span><del>-#if PLATFORM(WIN)
-    _snprintf(filenameSuffix, sizeof(filenameSuffix), &quot;.%d.txt&quot;, GetCurrentProcessId());
-#else
-    snprintf(filenameSuffix, sizeof(filenameSuffix), &quot;.%d.txt&quot;, getpid());
-#endif
-
</del><ins>+#if DATA_LOG_TO_FILE
</ins><span class="cx"> #if DATA_LOG_TO_DARWIN_TEMP_DIR
</span><span class="cx">     char filenameBuffer[maxPathLength + 1];
</span><del>-    unsigned suffixLength = strlen(filenameSuffix);
-
</del><span class="cx"> #if defined(DATA_LOG_FILENAME)
</span><span class="cx">     char* logBasename = strrchr(DATA_LOG_FILENAME, '/');
</span><span class="cx">     if (!logBasename)
</span><span class="lines">@@ -82,13 +74,11 @@
</span><span class="cx">     const char* logBasename = &quot;WTFLog&quot;;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    const char* filename = nullptr;
-
</del><span class="cx">     bool success = confstr(_CS_DARWIN_USER_TEMP_DIR, filenameBuffer, sizeof(filenameBuffer));
</span><span class="cx">     if (success) {
</span><span class="cx">         // FIXME: Assert that the path ends with a slash instead of adding a slash if it does not exist
</span><span class="cx">         // once &lt;rdar://problem/23579077&gt; is fixed in all iOS Simulator versions that we use.
</span><del>-        size_t lastComponentLength = strlen(logBasename) + suffixLength;
</del><ins>+        size_t lastComponentLength = strlen(logBasename) + 20; // More than enough for &quot;.&lt;pid&gt;.txt&quot;
</ins><span class="cx">         size_t dirnameLength = strlen(filenameBuffer);
</span><span class="cx">         bool shouldAddPathSeparator = filenameBuffer[dirnameLength - 1] != '/' &amp;&amp; logBasename[0] != '/';
</span><span class="cx">         if (lastComponentLength + shouldAddPathSeparator &lt;= sizeof(filenameBuffer) - dirnameLength - 1) {
</span><span class="lines">@@ -99,36 +89,23 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> #elif defined(DATA_LOG_FILENAME)
</span><del>-    const char* filename = DATA_LOG_FILENAME;
</del><ins>+    filename = DATA_LOG_FILENAME;
</ins><span class="cx"> #else
</span><del>-    const char* filename = getenv(&quot;WTF_DATA_LOG_FILENAME&quot;);
</del><ins>+    filename = getenv(&quot;WTF_DATA_LOG_FILENAME&quot;);
</ins><span class="cx"> #endif
</span><span class="cx">     char actualFilename[maxPathLength + 1];
</span><span class="cx"> 
</span><del>-    if (filename) {
</del><ins>+    if (filename &amp;&amp; !strstr(filename, &quot;%pid&quot;)) {
</ins><span class="cx"> #if PLATFORM(WIN)
</span><del>-        _snprintf(actualFilename, sizeof(actualFilename), &quot;%s%s&quot;, filename, filenameSuffix);
</del><ins>+        _snprintf(actualFilename, sizeof(actualFilename), &quot;%s.%%pid.txt&quot;, filename);
</ins><span class="cx"> #else
</span><del>-        snprintf(actualFilename, sizeof(actualFilename), &quot;%s%s&quot;, filename, filenameSuffix);
</del><ins>+        snprintf(actualFilename, sizeof(actualFilename), &quot;%s.%%pid.txt&quot;, filename);
</ins><span class="cx"> #endif
</span><del>-        
-        file = FilePrintStream::open(actualFilename, &quot;w&quot;).release();
-        if (file)
-            WTFLogAlways(&quot;*** DataLog output to \&quot;%s\&quot; ***\n&quot;, actualFilename);
-        else
-            WTFLogAlways(&quot;Warning: Could not open DataLog file %s for writing.\n&quot;, actualFilename);
</del><ins>+        filename = actualFilename;
</ins><span class="cx">     }
</span><span class="cx"> #endif // DATA_LOG_TO_FILE
</span><del>-    
-    if (!file) {
-        // Use placement new; this makes it easier to use dataLog() to debug
-        // fastMalloc.
-        file = new (s_fileData) FilePrintStream(stderr, FilePrintStream::Borrow);
-    }
-    
-    setvbuf(file-&gt;file(), 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
-    
-    s_file = new (s_lockedFileData) LockedPrintStream(std::unique_ptr&lt;FilePrintStream&gt;(file));
</del><ins>+
+    setDataFile(filename);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void initializeLogFile()
</span><span class="lines">@@ -141,6 +118,60 @@
</span><span class="cx">         });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void setDataFile(const char* path)
+{
+    FilePrintStream* file = nullptr;
+    char formattedPath[maxPathLength + 1];
+    const char* pathToOpen = path;
+
+    if (path) {
+        const char* pidFormat = strstr(path, &quot;%pid&quot;);
+        if (pidFormat) {
+            size_t leadingPathLength = pidFormat - path;
+            size_t pathCharactersAvailable = std::min(maxPathLength, leadingPathLength);
+            strncpy(formattedPath, path, pathCharactersAvailable);
+            char* nextDest = formattedPath + pathCharactersAvailable;
+            pathCharactersAvailable = maxPathLength - pathCharactersAvailable;
+            if (pathCharactersAvailable) {
+                int pidTextLength;
+#if PLATFORM(WIN)
+                pidTextLength = _snprintf(nextDest, pathCharactersAvailable, &quot;%d&quot;, GetCurrentProcessId());
+#else
+                pidTextLength = snprintf(nextDest, pathCharactersAvailable, &quot;%d&quot;, getpid());
+#endif
+                if (pidTextLength &lt; 0 || static_cast&lt;size_t&gt;(pidTextLength) &gt;= pathCharactersAvailable)
+                    pathCharactersAvailable = 0;
+                else {
+                    pathCharactersAvailable -= static_cast&lt;size_t&gt;(pidTextLength);
+                    nextDest += pidTextLength;
+                    strncpy(nextDest, pidFormat + 4, pathCharactersAvailable);
+                }
+            }
+            formattedPath[maxPathLength] = '\0';
+            pathToOpen = formattedPath;
+        }
+
+        file = FilePrintStream::open(pathToOpen, &quot;w&quot;).release();
+        if (file)
+            WTFLogAlways(&quot;*** DataLog output to \&quot;%s\&quot; ***\n&quot;, pathToOpen);
+        else
+            WTFLogAlways(&quot;Warning: Could not open DataLog file %s for writing.\n&quot;, pathToOpen);
+    }
+
+    if (!file) {
+        // Use placement new; this makes it easier to use dataLog() to debug
+        // fastMalloc.
+        file = new (s_fileData) FilePrintStream(stderr, FilePrintStream::Borrow);
+    }
+
+    setvbuf(file-&gt;file(), 0, _IONBF, 0); // Prefer unbuffered output, so that we get a full log upon crash or deadlock.
+
+    if (s_file)
+        s_file-&gt;flush();
+
+    s_file = new (s_lockedFileData) LockedPrintStream(std::unique_ptr&lt;FilePrintStream&gt;(file));
+}
+
</ins><span class="cx"> PrintStream&amp; dataFile()
</span><span class="cx"> {
</span><span class="cx">     initializeLogFile();
</span></span></pre></div>
<a id="trunkSourceWTFwtfDataLogh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/DataLog.h (213150 => 213151)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/DataLog.h        2017-02-28 16:43:27 UTC (rev 213150)
+++ trunk/Source/WTF/wtf/DataLog.h        2017-02-28 18:50:00 UTC (rev 213151)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><span class="cx"> WTF_EXPORT_PRIVATE PrintStream&amp; dataFile();
</span><ins>+WTF_EXPORT_PRIVATE void setDataFile(const char* path);
</ins><span class="cx"> 
</span><span class="cx"> WTF_EXPORT_PRIVATE void dataLogFV(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(1, 0);
</span><span class="cx"> WTF_EXPORT_PRIVATE void dataLogF(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
</span></span></pre>
</div>
</div>

</body>
</html>