<!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>[182903] trunk/Source/JavaScriptCore</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/182903">182903</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-04-16 12:59:47 -0700 (Thu, 16 Apr 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Add JSC_functionOverrides=<overrides file> debugging tool.
https://bugs.webkit.org/show_bug.cgi?id=143717
Reviewed by Geoffrey Garen.
This tool allows us to do runtime replacement of function bodies with alternatives
for debugging purposes. For example, this is useful when we need to debug VM bugs
which manifest in scripts executing in webpages downloaded from remote servers
that we don't control. The tool allows us to augment those scripts with logging
or test code to help isolate the bugs.
This tool works by substituting the SourceCode at FunctionExecutable creation
time. It identifies which SourceCode to substitute by comparing the source
string against keys in a set of key value pairs.
The keys are function body strings defined by 'override' clauses in the overrides
file specified by in the JSC_functionOverrides option. The values are function
body strings defines by 'with' clauses in the overrides file.
See comment blob at top of FunctionOverrides.cpp on the formatting
of the overrides file.
At FunctionExecutable creation time, if the SourceCode string matches one of the
'override' keys from the overrides file, the tool will replace the SourceCode with
a new one based on the corresponding 'with' value string. The FunctionExecutable
will then be created with the new SourceCode instead.
Some design decisions:
1. We opted to require that the 'with' clause appear on a separate line than the
'override' clause because this makes it easier to read and write when the
'override' clause's function body is single lined and long.
2. The user can use any sequence of characters for the delimiter (except for '{',
'}' and white space characters) because this ensures that there can always be
some delimiter pattern that does not appear in the function body in the clause
e.g. in the body of strings in the JS code.
'{' and '}' are disallowed because they are used to mark the boundaries of the
function body string. White space characters are disallowed because they can
be error prone (the user may not be able to tell between spaces and tabs).
3. The start and end delimiter must be an identical sequence of characters.
I had considered allowing the use of complementary characters like <>, [], and
() for making delimiter pairs like:
[[[[ ... ]]]]
<[([( ... )])]>
But in the end, decided against it because:
a. These sequences of complementary characters can exists in JS code.
In contrast, a repeating delimiter like %%%% is unlikely to appear in JS
code.
b. It can be error prone for the user to have to type the exact complement
character for the end delimiter in reverse order.
In contrast, a repeating delimiter like %%%% is much easier to type and
less error prone. Even a sequence like @#$%^ is less error prone than
a complementary sequence because it can be copy-pasted, and need not be
typed in reverse order.
c. It is easier to parse for the same delimiter string for both start and end.
4. The tool does a lot of checks for syntax errors in the overrides file because
we don't want any overrides to fail silently. If a syntax error is detected,
the tool will print an error message and call exit(). This avoids the user
wasting time doing debugging only to be surprised later that their specified
overrides did not take effect because of some unnoticed typo.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::link):
* runtime/Executable.h:
* runtime/Options.h:
* tools/FunctionOverrides.cpp: Added.
(JSC::FunctionOverrides::overrides):
(JSC::FunctionOverrides::FunctionOverrides):
(JSC::initializeOverrideInfo):
(JSC::FunctionOverrides::initializeOverrideFor):
(JSC::hasDisallowedCharacters):
(JSC::parseClause):
(JSC::FunctionOverrides::parseOverridesInFile):
* tools/FunctionOverrides.h: Added.</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="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxprojfilters">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutableh">trunk/Source/JavaScriptCore/runtime/Executable.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretoolsFunctionOverridescpp">trunk/Source/JavaScriptCore/tools/FunctionOverrides.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoretoolsFunctionOverridesh">trunk/Source/JavaScriptCore/tools/FunctionOverrides.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 (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -388,6 +388,7 @@
</span><span class="cx">
</span><span class="cx"> tools/CodeProfile.cpp
</span><span class="cx"> tools/CodeProfiling.cpp
</span><ins>+ tools/FunctionOverrides.cpp
</ins><span class="cx">
</span><span class="cx"> yarr/RegularExpression.cpp
</span><span class="cx"> yarr/YarrCanonicalizeUCS2.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -1,3 +1,88 @@
</span><ins>+2015-04-14 Mark Lam <mark.lam@apple.com>
+
+ Add JSC_functionOverrides=<overrides file> debugging tool.
+ https://bugs.webkit.org/show_bug.cgi?id=143717
+
+ Reviewed by Geoffrey Garen.
+
+ This tool allows us to do runtime replacement of function bodies with alternatives
+ for debugging purposes. For example, this is useful when we need to debug VM bugs
+ which manifest in scripts executing in webpages downloaded from remote servers
+ that we don't control. The tool allows us to augment those scripts with logging
+ or test code to help isolate the bugs.
+
+ This tool works by substituting the SourceCode at FunctionExecutable creation
+ time. It identifies which SourceCode to substitute by comparing the source
+ string against keys in a set of key value pairs.
+
+ The keys are function body strings defined by 'override' clauses in the overrides
+ file specified by in the JSC_functionOverrides option. The values are function
+ body strings defines by 'with' clauses in the overrides file.
+ See comment blob at top of FunctionOverrides.cpp on the formatting
+ of the overrides file.
+
+ At FunctionExecutable creation time, if the SourceCode string matches one of the
+ 'override' keys from the overrides file, the tool will replace the SourceCode with
+ a new one based on the corresponding 'with' value string. The FunctionExecutable
+ will then be created with the new SourceCode instead.
+
+ Some design decisions:
+ 1. We opted to require that the 'with' clause appear on a separate line than the
+ 'override' clause because this makes it easier to read and write when the
+ 'override' clause's function body is single lined and long.
+
+ 2. The user can use any sequence of characters for the delimiter (except for '{',
+ '}' and white space characters) because this ensures that there can always be
+ some delimiter pattern that does not appear in the function body in the clause
+ e.g. in the body of strings in the JS code.
+
+ '{' and '}' are disallowed because they are used to mark the boundaries of the
+ function body string. White space characters are disallowed because they can
+ be error prone (the user may not be able to tell between spaces and tabs).
+
+ 3. The start and end delimiter must be an identical sequence of characters.
+
+ I had considered allowing the use of complementary characters like <>, [], and
+ () for making delimiter pairs like:
+ [[[[ ... ]]]]
+ <[([( ... )])]>
+
+ But in the end, decided against it because:
+ a. These sequences of complementary characters can exists in JS code.
+ In contrast, a repeating delimiter like %%%% is unlikely to appear in JS
+ code.
+ b. It can be error prone for the user to have to type the exact complement
+ character for the end delimiter in reverse order.
+ In contrast, a repeating delimiter like %%%% is much easier to type and
+ less error prone. Even a sequence like @#$%^ is less error prone than
+ a complementary sequence because it can be copy-pasted, and need not be
+ typed in reverse order.
+ c. It is easier to parse for the same delimiter string for both start and end.
+
+ 4. The tool does a lot of checks for syntax errors in the overrides file because
+ we don't want any overrides to fail silently. If a syntax error is detected,
+ the tool will print an error message and call exit(). This avoids the user
+ wasting time doing debugging only to be surprised later that their specified
+ overrides did not take effect because of some unnoticed typo.
+
+ * CMakeLists.txt:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+ * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/UnlinkedCodeBlock.cpp:
+ (JSC::UnlinkedFunctionExecutable::link):
+ * runtime/Executable.h:
+ * runtime/Options.h:
+ * tools/FunctionOverrides.cpp: Added.
+ (JSC::FunctionOverrides::overrides):
+ (JSC::FunctionOverrides::FunctionOverrides):
+ (JSC::initializeOverrideInfo):
+ (JSC::FunctionOverrides::initializeOverrideFor):
+ (JSC::hasDisallowedCharacters):
+ (JSC::parseClause):
+ (JSC::FunctionOverrides::parseOverridesInFile):
+ * tools/FunctionOverrides.h: Added.
+
</ins><span class="cx"> 2015-04-16 Basile Clement <basile_clement@apple.com>
</span><span class="cx">
</span><span class="cx"> Extract the allocation profile from JSFunction into a rare object
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -854,6 +854,7 @@
</span><span class="cx"> <ClCompile Include="..\runtime\WeakMapPrototype.cpp" />
</span><span class="cx"> <ClCompile Include="..\tools\CodeProfile.cpp" />
</span><span class="cx"> <ClCompile Include="..\tools\CodeProfiling.cpp" />
</span><ins>+ <ClCompile Include="..\tools\FunctionOverrides.cpp" />
</ins><span class="cx"> <ClCompile Include="..\yarr\RegularExpression.cpp" />
</span><span class="cx"> <ClCompile Include="..\yarr\YarrCanonicalizeUCS2.cpp" />
</span><span class="cx"> <ClCompile Include="..\yarr\YarrInterpreter.cpp" />
</span><span class="lines">@@ -1700,6 +1701,7 @@
</span><span class="cx"> <ClInclude Include="..\runtime\WriteBarrierInlines.h" />
</span><span class="cx"> <ClInclude Include="..\tools\CodeProfile.h" />
</span><span class="cx"> <ClInclude Include="..\tools\CodeProfiling.h" />
</span><ins>+ <ClInclude Include="..\tools\FunctionOverrides.h" />
</ins><span class="cx"> <ClInclude Include="..\tools\ProfileTreeNode.h" />
</span><span class="cx"> <ClInclude Include="..\tools\TieredMMapArray.h" />
</span><span class="cx"> <ClInclude Include="..\yarr\RegularExpression.h" />
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxprojfilters"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -897,6 +897,9 @@
</span><span class="cx"> <ClCompile Include="..\tools\CodeProfiling.cpp">
</span><span class="cx"> <Filter>tools</Filter>
</span><span class="cx"> </ClCompile>
</span><ins>+ <ClCompile Include="..\tools\FunctionOverrides.cpp">
+ <Filter>tools</Filter>
+ </ClCompile>
</ins><span class="cx"> <ClCompile Include="..\yarr\RegularExpression.cpp">
</span><span class="cx"> <Filter>yarr</Filter>
</span><span class="cx"> </ClCompile>
</span><span class="lines">@@ -2975,6 +2978,9 @@
</span><span class="cx"> <ClInclude Include="..\tools\CodeProfiling.h">
</span><span class="cx"> <Filter>tools</Filter>
</span><span class="cx"> </ClInclude>
</span><ins>+ <ClInclude Include="..\tools\FunctionOverrides.h">
+ <Filter>tools</Filter>
+ </ClInclude>
</ins><span class="cx"> <ClInclude Include="..\tools\ProfileTreeNode.h">
</span><span class="cx"> <Filter>tools</Filter>
</span><span class="cx"> </ClInclude>
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -1648,6 +1648,8 @@
</span><span class="cx">                 FE0D4A091ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE0D4A071ABA2437002F54BF /* GlobalContextWithFinalizerTest.cpp */; };
</span><span class="cx">                 FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; };
</span><span class="cx">                 FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */; };
+                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */; };
</ins><span class="cx">                 FE5932A7183C5A2600A1ECCC /* VMEntryScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */; };
</span><span class="cx">                 FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */; };
</span><span class="lines">@@ -3428,6 +3430,8 @@
</span><span class="cx">                 FE0D4A081ABA2437002F54BF /* GlobalContextWithFinalizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GlobalContextWithFinalizerTest.h; path = API/tests/GlobalContextWithFinalizerTest.h; sourceTree = "<group>"; };
</span><span class="cx">                 FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
</span><ins>+                FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionOverrides.cpp; sourceTree = "<group>"; };
+                FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionOverrides.h; sourceTree = "<group>"; };
</ins><span class="cx">                 FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMEntryScope.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; };
</span><span class="cx">                 FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapVerifier.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -4758,6 +4762,8 @@
</span><span class="cx">                                 86B5822F14D2373B00A9C306 /* CodeProfile.h */,
</span><span class="cx">                                 8603CEF214C7546400AE59E3 /* CodeProfiling.cpp */,
</span><span class="cx">                                 8603CEF314C7546400AE59E3 /* CodeProfiling.h */,
</span><ins>+                                FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */,
+                                FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */,
</ins><span class="cx">                                 86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */,
</span><span class="cx">                                 86B5826A14D35D5100A9C306 /* TieredMMapArray.h */,
</span><span class="cx">                         );
</span><span class="lines">@@ -6217,6 +6223,7 @@
</span><span class="cx">                                 A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */,
</span><span class="cx">                                 0A6441519420A6C61AD1882E /* MapDataInlines.h in Headers */,
</span><span class="cx">                                 A74DEF92182D991400522C22 /* MapIteratorConstructor.h in Headers */,
</span><ins>+                                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */,
</ins><span class="cx">                                 A74DEF94182D991400522C22 /* MapIteratorPrototype.h in Headers */,
</span><span class="cx">                                 A700873E17CBE8D300C3E643 /* MapPrototype.h in Headers */,
</span><span class="cx">                                 C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */,
</span><span class="lines">@@ -7255,6 +7262,7 @@
</span><span class="cx">                                 A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */,
</span><span class="cx">                                 0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */,
</span><span class="cx">                                 0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */,
</span><ins>+                                FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */,
</ins><span class="cx">                                 14A23D750F4E1ABB0023CDAD /* JITStubs.cpp in Sources */,
</span><span class="cx">                                 0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */,
</span><span class="cx">                                 0FC712E217CD8791008CC93C /* JITToDFGDeferredCompilationCallback.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeUnlinkedCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include "ClassInfo.h"
</span><span class="cx"> #include "CodeCache.h"
</span><span class="cx"> #include "Executable.h"
</span><ins>+#include "FunctionOverrides.h"
</ins><span class="cx"> #include "JSString.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><span class="cx"> #include "Parser.h"
</span><span class="lines">@@ -137,17 +138,40 @@
</span><span class="cx"> SourceCode source = m_sourceOverride ? SourceCode(m_sourceOverride) : ownerSource;
</span><span class="cx"> unsigned firstLine = source.firstLine() + m_firstLineOffset;
</span><span class="cx"> unsigned startOffset = source.startOffset() + m_startOffset;
</span><ins>+ unsigned lineCount = m_lineCount;
</ins><span class="cx">
</span><span class="cx"> // Adjust to one-based indexing.
</span><span class="cx"> bool startColumnIsOnFirstSourceLine = !m_firstLineOffset;
</span><span class="cx"> unsigned startColumn = m_unlinkedBodyStartColumn + (startColumnIsOnFirstSourceLine ? source.startColumn() : 1);
</span><del>- bool endColumnIsOnStartLine = !m_lineCount;
</del><ins>+ bool endColumnIsOnStartLine = !lineCount;
</ins><span class="cx"> unsigned endColumn = m_unlinkedBodyEndColumn + (endColumnIsOnStartLine ? startColumn : 1);
</span><span class="cx">
</span><span class="cx"> SourceCode code(source.provider(), startOffset, startOffset + m_sourceLength, firstLine, startColumn);
</span><del>- FunctionExecutable* result = FunctionExecutable::create(vm, code, this, firstLine, firstLine + m_lineCount, startColumn, endColumn);
</del><ins>+ FunctionOverrides::OverrideInfo overrideInfo;
+ bool hasFunctionOverride = false;
+
+ if (UNLIKELY(Options::functionOverrides())) {
+ hasFunctionOverride = FunctionOverrides::initializeOverrideFor(code, overrideInfo);
+ if (hasFunctionOverride) {
+ firstLine = overrideInfo.firstLine;
+ lineCount = overrideInfo.lineCount;
+ startColumn = overrideInfo.startColumn;
+ endColumn = overrideInfo.endColumn;
+ code = overrideInfo.sourceCode;
+ }
+ }
+
+ FunctionExecutable* result = FunctionExecutable::create(vm, code, this, firstLine, firstLine + lineCount, startColumn, endColumn);
</ins><span class="cx"> if (overrideLineNumber != -1)
</span><span class="cx"> result->setOverrideLineNumber(overrideLineNumber);
</span><ins>+
+ if (UNLIKELY(hasFunctionOverride)) {
+ result->overrideParameterAndTypeProfilingStartEndOffsets(
+ overrideInfo.parametersStartOffset,
+ overrideInfo.typeProfilingStartOffset,
+ overrideInfo.typeProfilingEndOffset);
+ }
+
</ins><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Executable.h (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Executable.h        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/runtime/Executable.h        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -647,6 +647,13 @@
</span><span class="cx">
</span><span class="cx"> unsigned parametersStartOffset() const { return m_parametersStartOffset; }
</span><span class="cx">
</span><ins>+ void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
+ {
+ m_parametersStartOffset = parametersStartOffset;
+ m_typeProfilingStartOffset = typeProfilingStartOffset;
+ m_typeProfilingEndOffset = typeProfilingEndOffset;
+ }
+
</ins><span class="cx"> DECLARE_INFO;
</span><span class="cx">
</span><span class="cx"> void unlinkCalls();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (182902 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2015-04-16 19:47:41 UTC (rev 182902)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -304,7 +304,9 @@
</span><span class="cx"> v(bool, enableExecutableAllocationFuzz, false, nullptr) \
</span><span class="cx"> v(unsigned, fireExecutableAllocationFuzzAt, 0, nullptr) \
</span><span class="cx"> v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, nullptr) \
</span><del>- v(bool, verboseExecutableAllocationFuzz, false, nullptr)
</del><ins>+ v(bool, verboseExecutableAllocationFuzz, false, nullptr) \
+ \
+ v(optionString, functionOverrides, nullptr, "file with debugging overrides for function bodies") \
</ins><span class="cx">
</span><span class="cx"> class Options {
</span><span class="cx"> public:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretoolsFunctionOverridescpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tools/FunctionOverrides.cpp (0 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tools/FunctionOverrides.cpp         (rev 0)
+++ trunk/Source/JavaScriptCore/tools/FunctionOverrides.cpp        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -0,0 +1,250 @@
</span><ins>+/*
+ * Copyright (C) 2015 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 "FunctionOverrides.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <wtf/DataLog.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringHash.h>
+
+namespace JSC {
+
+/*
+ The overrides file defines function bodies that we will want to override with
+ a replacement for debugging purposes. The overrides file may contain
+ 'override' and 'with' clauses like these:
+
+ // Example 1: function foo1(a)
+ override !@#$%{ print("In foo1"); }!@#$%
+ with abc{
+ print("I am overridden");
+ }abc
+
+ // Example 2: function foo2(a)
+ override %%%{
+ print("foo2's body has a string with }%% in it.");
+ // Because }%% appears in the function body here, we cannot use
+ // %% or % as the delimiter. %%% is ok though.
+ }%%%
+ with %%%{
+ print("Overridden foo2");
+ }%%%
+
+ 1. Comments are lines starting with //. All comments will be ignored.
+
+ 2. An 'override' clause is used to specify the original function body we
+ want to override. The with clause is used to specify the overriding
+ function body.
+
+ An 'override' clause must be followed immediately by a 'with' clause.
+
+ 3. An 'override' clause must be of the form:
+ override <delimiter>{...function body...}<delimiter>
+
+ The override keyword must be at the start of the line.
+
+ <delimiter> may be any string of any ASCII characters (except for '{',
+ '}', and whitespace characters) as long as the pattern of "}<delimiter>"
+ does not appear in the function body e.g. the override clause of Example 2
+ above illustrates this.
+
+ The start and end <delimiter> must be identical.
+
+ The space between the override keyword and the start <delimiter> is
+ required.
+
+ All characters between the pair of delimiters will be considered to
+ be part of the function body string. This allows us to also work
+ with script source that are multi-lined i.e. newlines are allowed.
+
+ 4. A 'with' clause is identical in form to an 'override' clause except that
+ it uses the 'with' keyword instead of the 'override' keyword.
+ */
+
+FunctionOverrides& FunctionOverrides::overrides()
+{
+ static LazyNeverDestroyed<FunctionOverrides> overrides;
+ static std::once_flag initializeListFlag;
+ std::call_once(initializeListFlag, [] {
+ const char* overridesFileName = Options::functionOverrides();
+ overrides.construct(overridesFileName);
+ });
+ return overrides;
+}
+
+FunctionOverrides::FunctionOverrides(const char* overridesFileName)
+{
+ parseOverridesInFile(overridesFileName);
+}
+
+static void initializeOverrideInfo(const SourceCode& origCode, String newBody, FunctionOverrides::OverrideInfo& info)
+{
+ String origProviderStr = origCode.provider()->source();
+ unsigned origBraceStart = origCode.startOffset();
+ unsigned origFunctionStart = origProviderStr.reverseFind("function", origBraceStart);
+ unsigned headerLength = origBraceStart - origFunctionStart;
+ String origHeader = origProviderStr.substring(origFunctionStart, headerLength);
+
+ String newProviderStr;
+ newProviderStr.append(origHeader);
+ newProviderStr.append(newBody);
+
+ RefPtr<SourceProvider> newProvider = StringSourceProvider::create(newProviderStr, "<overridden>");
+
+ info.firstLine = 1;
+ info.lineCount = 1; // Faking it. This doesn't really matter for now.
+ info.startColumn = 1;
+ info.endColumn = 1; // Faking it. This doesn't really matter for now.
+ info.parametersStartOffset = newProviderStr.find("(");
+ info.typeProfilingStartOffset = newProviderStr.find("{");
+ info.typeProfilingEndOffset = newProviderStr.length() - 1;
+
+ info.sourceCode =
+ SourceCode(newProvider, info.typeProfilingStartOffset, info.typeProfilingEndOffset + 1, 1, 1);
+}
+
+bool FunctionOverrides::initializeOverrideFor(const SourceCode& origCode, FunctionOverrides::OverrideInfo& result)
+{
+ ASSERT(Options::functionOverrides());
+ FunctionOverrides& overrides = FunctionOverrides::overrides();
+
+ auto it = overrides.m_entries.find(origCode.toString());
+ if (it == overrides.m_entries.end())
+ return false;
+
+ initializeOverrideInfo(origCode, it->value, result);
+ return true;
+}
+
+#define SYNTAX_ERROR "SYNTAX ERROR"
+#define IO_ERROR "IO ERROR"
+#define FAIL_WITH_ERROR(error, errorMessageInBrackets) \
+ do { \
+ dataLog("functionOverrides ", error, ": "); \
+ dataLog errorMessageInBrackets; \
+ exit(EXIT_FAILURE); \
+ } while (false)
+
+static bool hasDisallowedCharacters(const char* str, size_t length)
+{
+ while (length--) {
+ char c = *str++;
+ // '{' is also disallowed, but we don't need to check for it because
+ // parseClause() searches for '{' as the end of the start delimiter.
+ // As a result, the parsed delimiter string will never include '{'.
+ if (c == '}' || isASCIISpace(c))
+ return true;
+ }
+ return false;
+}
+
+static String parseClause(const char* keyword, size_t keywordLength, FILE* file, const char* line, char* buffer, size_t bufferSize)
+{
+ const char* keywordPos = strstr(line, keyword);
+ if (!keywordPos)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Expecting '", keyword, "' clause:\n", line, "\n"));
+ if (keywordPos != line)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Cannot have any characters before '", keyword, "':\n", line, "\n"));
+ if (line[keywordLength] != ' ')
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' must be followed by a ' ':\n", line, "\n"));
+
+ const char* delimiterStart = &line[keywordLength + 1];
+ const char* delimiterEnd = strstr(delimiterStart, "{");
+ if (!delimiterEnd)
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Missing { after '", keyword, "' clause start delimiter:\n", line, "\n"));
+
+ size_t delimiterLength = delimiterEnd - delimiterStart;
+ String delimiter(delimiterStart, delimiterLength);
+
+ if (hasDisallowedCharacters(delimiterStart, delimiterLength))
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Delimiter '", delimiter, "' cannot have '{', '}', or whitespace:\n", line, "\n"));
+
+ String terminatorString;
+ terminatorString.append("}");
+ terminatorString.append(delimiter);
+
+ const char* terminator = terminatorString.ascii().data();
+ line = delimiterEnd; // Start from the {.
+
+ StringBuilder builder;
+ do {
+ const char* p = strstr(line, terminator);
+ if (p) {
+ if (p[strlen(terminator)] != '\n')
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("Unexpected characters after '", keyword, "' clause end delimiter '", delimiter, "':\n", line, "\n"));
+
+ builder.append(line, p - line + 1);
+ return builder.toString();
+ }
+ builder.append(line);
+
+ } while ((line = fgets(buffer, bufferSize, file)));
+
+ FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' clause end delimiter '", delimiter, "' not found:\n", builder.toString(), "\n", "Are you missing a '}' before the delimiter?\n"));
+}
+
+void FunctionOverrides::parseOverridesInFile(const char* fileName)
+{
+ if (!fileName)
+ return;
+
+ FILE* file = fopen(fileName, "r");
+ if (!file)
+ FAIL_WITH_ERROR(IO_ERROR, ("Failed to open file ", fileName, ". Did you add the file-read-data entitlement to WebProcess.sb?\n"));
+
+ char* line;
+ char buffer[BUFSIZ];
+ while ((line = fgets(buffer, sizeof(buffer), file))) {
+ if (strstr(line, "//") == line)
+ continue;
+
+ if (line[0] == '\n' || line[0] == '\0')
+ continue;
+
+ size_t keywordLength;
+
+ keywordLength = sizeof("override") - 1;
+ String keyStr = parseClause("override", keywordLength, file, line, buffer, sizeof(buffer));
+
+ line = fgets(buffer, sizeof(buffer), file);
+
+ keywordLength = sizeof("with") - 1;
+ String valueStr = parseClause("with", keywordLength, file, line, buffer, sizeof(buffer));
+
+ m_entries.add(keyStr, valueStr);
+ }
+
+ int result = fclose(file);
+ if (result)
+ dataLogF("Failed to close file %s: %s\n", fileName, strerror(errno));
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretoolsFunctionOverridesh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tools/FunctionOverrides.h (0 => 182903)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tools/FunctionOverrides.h         (rev 0)
+++ trunk/Source/JavaScriptCore/tools/FunctionOverrides.h        2015-04-16 19:59:47 UTC (rev 182903)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+/*
+ * Copyright (C) 2015 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 FunctionOverrides_h
+#define FunctionOverrides_h
+
+#include "Options.h"
+#include "SourceCode.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class ScriptExecutable;
+
+class FunctionOverrides {
+public:
+ struct OverrideInfo {
+ SourceCode sourceCode;
+ unsigned firstLine;
+ unsigned lineCount;
+ unsigned startColumn;
+ unsigned endColumn;
+ unsigned parametersStartOffset;
+ unsigned typeProfilingStartOffset;
+ unsigned typeProfilingEndOffset;
+ };
+
+ static FunctionOverrides& overrides();
+ FunctionOverrides(const char* functionOverridesFileName);
+
+ static bool initializeOverrideFor(const SourceCode& origCode, OverrideInfo& result);
+
+private:
+ void parseOverridesInFile(const char* fileName);
+
+ HashMap<String, String> m_entries;
+};
+
+} // namespace JSC
+
+#endif // FunctionOverrides_h
</ins></span></pre>
</div>
</div>
</body>
</html>