<!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>[201039] trunk</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/201039">201039</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-05-17 13:38:36 -0700 (Tue, 17 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add test262 harness support code
https://bugs.webkit.org/show_bug.cgi?id=157797

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This patch adds some new tooling needed to run Test262 with the jsc
CLI. There were three options that needed to be added for Test262:

1) &quot;--test262-async&quot; This option overrides the print function in the test runner to look for
'Test262:AsyncTestComplete' instead of printing the passed text. If test262-async mode is on
and that string is not passed then the test is marked as failing.

2) &quot;--strict-file=&lt;file&gt;&quot; This option appends `&quot;use strict&quot;;\n` to the beginning of the
passed file before passing the source code to the VM. This option can, in theory, be passed
multiple times.

3) &quot;--exception=&lt;name&gt;&quot; This option asserts that at the end of the last script file passed
the VM has an uncaught exception with its name property equal to the passed name.

* jsc.cpp:
(Script::Script):
(fillBufferWithContentsOfFile):
(functionPrint):
(checkUncaughtException):
(runWithScripts):
(printUsageStatement):
(CommandLine::parseArguments):
(runJSC):

Tools:

The import-test262-tests script is used to generate the yaml file used to run test262. It
takes a path to the local copy of the Test262 repository as well as an optional path to file
containing a list of failures. This script currently just creates the yaml file used to run
the script. It does not relocate the test files into our tests directory. In the future I
plan to add that feature but it didn't seem essential for the first iteration. Since many
test262 tests need to be run in both strict and non-strict mode, import-test262-tests
creates two separate runs for those tests. This enables us to distinguish between failures
in only one of the two modes.

This patch also updates the run-jsc-stress-tests Script to run tests from Test262. In order
to do so two new run commands were needed runTest262 and prepareTest262Fixture. runTest262
takes an actual test file along with the metadata associated with it. prepareTest262Fixture
takes a fixture file (used by module tests for importing) and makes sure that file is
properly relocated to the test runner directory.

The proccess I used to import the tests was to first run import-test262-tests to create a
yaml for all the tests (import-test262-tests assumes all tests pass if to failures file is
passed). Then I ran the generated yaml file with &quot;run-jsc-stress-tests -v -c 1&quot; piping the
output to a file and collected all the lines with &quot;FAIL&quot; in it. Finally, I reran
import-test262-tests with the new failure file to create the final yaml.

* Scripts/import-test262-tests: Added.
* Scripts/run-jsc-stress-tests:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptsrunjscstresstests">trunk/Tools/Scripts/run-jsc-stress-tests</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsScriptsimporttest262tests">trunk/Tools/Scripts/import-test262-tests</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (201038 => 201039)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-05-17 19:38:51 UTC (rev 201038)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-05-17 20:38:36 UTC (rev 201039)
</span><span class="lines">@@ -1,3 +1,34 @@
</span><ins>+2016-05-17  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        Add test262 harness support code
+        https://bugs.webkit.org/show_bug.cgi?id=157797
+
+        Reviewed by Filip Pizlo.
+
+        This patch adds some new tooling needed to run Test262 with the jsc
+        CLI. There were three options that needed to be added for Test262:
+
+        1) &quot;--test262-async&quot; This option overrides the print function in the test runner to look for
+        'Test262:AsyncTestComplete' instead of printing the passed text. If test262-async mode is on
+        and that string is not passed then the test is marked as failing.
+
+        2) &quot;--strict-file=&lt;file&gt;&quot; This option appends `&quot;use strict&quot;;\n` to the beginning of the
+        passed file before passing the source code to the VM. This option can, in theory, be passed
+        multiple times.
+
+        3) &quot;--exception=&lt;name&gt;&quot; This option asserts that at the end of the last script file passed
+        the VM has an uncaught exception with its name property equal to the passed name.
+
+        * jsc.cpp:
+        (Script::Script):
+        (fillBufferWithContentsOfFile):
+        (functionPrint):
+        (checkUncaughtException):
+        (runWithScripts):
+        (printUsageStatement):
+        (CommandLine::parseArguments):
+        (runJSC):
+
</ins><span class="cx"> 2016-05-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WTF should know about Language
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (201038 => 201039)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2016-05-17 19:38:51 UTC (rev 201038)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2016-05-17 20:38:36 UTC (rev 201039)
</span><span class="lines">@@ -530,6 +530,8 @@
</span><span class="cx"> const ClassInfo CustomGetter::s_info = { &quot;CustomGetter&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
</span><span class="cx"> const ClassInfo RuntimeArray::s_info = { &quot;RuntimeArray&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
</span><span class="cx"> const ClassInfo SimpleObject::s_info = { &quot;SimpleObject&quot;, &amp;Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
</span><ins>+static bool test262AsyncPassed { false };
+static bool test262AsyncTest { false };
</ins><span class="cx"> 
</span><span class="cx"> ElementHandleOwner* Element::handleOwner()
</span><span class="cx"> {
</span><span class="lines">@@ -637,13 +639,17 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState*);
</span><span class="cx"> 
</span><span class="cx"> struct Script {
</span><ins>+    bool parseAsStrict;
</ins><span class="cx">     bool isFile;
</span><span class="cx">     char* argument;
</span><span class="cx"> 
</span><del>-    Script(bool isFile, char *argument)
-        : isFile(isFile)
</del><ins>+    Script(bool parseAsStrict, bool isFile, char *argument)
+        : parseAsStrict(parseAsStrict)
+        , isFile(isFile)
</ins><span class="cx">         , argument(argument)
</span><span class="cx">     {
</span><ins>+        if (parseAsStrict)
+            ASSERT(isFile);
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -662,6 +668,7 @@
</span><span class="cx">     Vector&lt;String&gt; m_arguments;
</span><span class="cx">     bool m_profile { false };
</span><span class="cx">     String m_profilerOutput;
</span><ins>+    String m_uncaughtExceptionName;
</ins><span class="cx">     bool m_dumpSamplingProfilerData { false };
</span><span class="cx"> 
</span><span class="cx">     void parseArguments(int, char**);
</span><span class="lines">@@ -1038,12 +1045,14 @@
</span><span class="cx"> 
</span><span class="cx"> static bool fillBufferWithContentsOfFile(FILE* file, Vector&lt;char&gt;&amp; buffer)
</span><span class="cx"> {
</span><ins>+    // We might have injected &quot;use strict&quot;; at the top.
+    size_t initialSize = buffer.size();
</ins><span class="cx">     fseek(file, 0, SEEK_END);
</span><span class="cx">     size_t bufferCapacity = ftell(file);
</span><span class="cx">     fseek(file, 0, SEEK_SET);
</span><del>-    buffer.resize(bufferCapacity);
-    size_t readSize = fread(buffer.data(), 1, buffer.size(), file);
-    return readSize == buffer.size();
</del><ins>+    buffer.resize(bufferCapacity + initialSize);
+    size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
+    return readSize == buffer.size() - initialSize;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static bool fillBufferWithContentsOfFile(const String&amp; fileName, Vector&lt;char&gt;&amp; buffer)
</span><span class="lines">@@ -1115,6 +1124,13 @@
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
</span><span class="cx"> {
</span><ins>+    if (test262AsyncTest) {
+        JSValue value = exec-&gt;argument(0);
+        if (value.isString() &amp;&amp; WTF::equal(asString(value)-&gt;value(exec).impl(), &quot;Test262:AsyncTestComplete&quot;))
+            test262AsyncPassed = true;
+        return JSValue::encode(jsUndefined());
+    }
+
</ins><span class="cx">     for (unsigned i = 0; i &lt; exec-&gt;argumentCount(); ++i) {
</span><span class="cx">         if (i)
</span><span class="cx">             putchar(' ');
</span><span class="lines">@@ -1973,8 +1989,31 @@
</span><span class="cx">         dumpException(globalObject, evaluationException-&gt;value());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool runWithScripts(GlobalObject* globalObject, const Vector&lt;Script&gt;&amp; scripts, bool dump, bool module)
</del><ins>+static bool checkUncaughtException(VM&amp; vm, GlobalObject* globalObject, NakedPtr&lt;Exception&gt; evaluationException, const String&amp; expectedExceptionName)
</ins><span class="cx"> {
</span><ins>+    if (!evaluationException) {
+        printf(&quot;Expected uncaught exception with name '%s' but none was thrown\n&quot;, expectedExceptionName.utf8().data());
+        return false;
+    }
+
+    JSValue exception = evaluationException-&gt;value();
+    JSValue exceptionName = exception.get(globalObject-&gt;globalExec(), vm.propertyNames-&gt;name);
+
+    if (JSString* exceptionNameStr = jsDynamicCast&lt;JSString*&gt;(exceptionName)) {
+        const String&amp; name = exceptionNameStr-&gt;value(globalObject-&gt;globalExec());
+        if (name == expectedExceptionName)
+            return true;
+        printf(&quot;Expected uncaught exception with name '%s' but got one with name '%s'\n&quot;, expectedExceptionName.utf8().data(), name.utf8().data());
+        dumpException(globalObject, exception);
+        return false;
+    }
+    printf(&quot;Expected uncaught exception with name '%s' but exception value did not have a name property\n&quot;, expectedExceptionName.utf8().data());
+    dumpException(globalObject, exception);
+    return false;
+}
+
+static bool runWithScripts(GlobalObject* globalObject, const Vector&lt;Script&gt;&amp; scripts, const String&amp; uncaughtExceptionName, bool dump, bool module)
+{
</ins><span class="cx">     String fileName;
</span><span class="cx">     Vector&lt;char&gt; scriptBuffer;
</span><span class="cx"> 
</span><span class="lines">@@ -1998,6 +2037,9 @@
</span><span class="cx">         JSInternalPromise* promise = nullptr;
</span><span class="cx">         if (scripts[i].isFile) {
</span><span class="cx">             fileName = scripts[i].argument;
</span><ins>+            if (scripts[i].parseAsStrict)
+                scriptBuffer.append(&quot;\&quot;use strict\&quot;;\n&quot;, strlen(&quot;\&quot;use strict\&quot;;\n&quot;));
+
</ins><span class="cx">             if (module)
</span><span class="cx">                 promise = loadAndEvaluateModule(globalObject-&gt;globalExec(), fileName);
</span><span class="cx">             else {
</span><span class="lines">@@ -2014,19 +2056,24 @@
</span><span class="cx">         if (module) {
</span><span class="cx">             if (!promise)
</span><span class="cx">                 promise = loadAndEvaluateModule(globalObject-&gt;globalExec(), jscSource(scriptBuffer, fileName));
</span><del>-            globalObject-&gt;globalExec()-&gt;clearException();
</del><ins>+            vm.clearException();
</ins><span class="cx">             promise-&gt;then(globalObject-&gt;globalExec(), nullptr, errorHandler);
</span><del>-            globalObject-&gt;vm().drainMicrotasks();
</del><ins>+            vm.drainMicrotasks();
</ins><span class="cx">         } else {
</span><span class="cx">             NakedPtr&lt;Exception&gt; evaluationException;
</span><span class="cx">             JSValue returnValue = evaluate(globalObject-&gt;globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
</span><del>-            success = success &amp;&amp; !evaluationException;
-            if (dump &amp;&amp; !evaluationException)
-                printf(&quot;End: %s\n&quot;, returnValue.toString(globalObject-&gt;globalExec())-&gt;value(globalObject-&gt;globalExec()).utf8().data());
-            dumpException(globalObject, evaluationException);
</del><ins>+            if (!uncaughtExceptionName || i != scripts.size() - 1) {
+                success = success &amp;&amp; !evaluationException;
+                if (dump &amp;&amp; !evaluationException)
+                    printf(&quot;End: %s\n&quot;, returnValue.toString(globalObject-&gt;globalExec())-&gt;value(globalObject-&gt;globalExec()).utf8().data());
+                dumpException(globalObject, evaluationException);
+            } else
+                success = success &amp;&amp; checkUncaughtException(vm, globalObject, evaluationException, uncaughtExceptionName);
+
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        globalObject-&gt;globalExec()-&gt;clearException();
</del><ins>+        scriptBuffer.clear();
+        vm.clearException();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(REGEXP_TRACING)
</span><span class="lines">@@ -2111,6 +2158,9 @@
</span><span class="cx">     fprintf(stderr, &quot;  -x         Output exit code before terminating\n&quot;);
</span><span class="cx">     fprintf(stderr, &quot;\n&quot;);
</span><span class="cx">     fprintf(stderr, &quot;  --sample                   Collects and outputs sampling profiler data\n&quot;);
</span><ins>+    fprintf(stderr, &quot;  --test262-async            Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n&quot;);
+    fprintf(stderr, &quot;  --strict-file=&lt;file&gt;       Parse the given file as if it were in strict mode (this option may be passed more than once)\n&quot;);
+    fprintf(stderr, &quot;  --exception=&lt;name&gt;         Check the last script exits with an uncaught exception with the specified name\n&quot;);
</ins><span class="cx">     fprintf(stderr, &quot;  --options                  Dumps all JSC VM options and exits\n&quot;);
</span><span class="cx">     fprintf(stderr, &quot;  --dumpOptions              Dumps all non-default JSC VM options before continuing\n&quot;);
</span><span class="cx">     fprintf(stderr, &quot;  --&lt;jsc VM option&gt;=&lt;value&gt;  Sets the specified JSC VM option\n&quot;);
</span><span class="lines">@@ -2133,13 +2183,13 @@
</span><span class="cx">         if (!strcmp(arg, &quot;-f&quot;)) {
</span><span class="cx">             if (++i == argc)
</span><span class="cx">                 printUsageStatement();
</span><del>-            m_scripts.append(Script(true, argv[i]));
</del><ins>+            m_scripts.append(Script(false, true, argv[i]));
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         if (!strcmp(arg, &quot;-e&quot;)) {
</span><span class="cx">             if (++i == argc)
</span><span class="cx">                 printUsageStatement();
</span><del>-            m_scripts.append(Script(false, argv[i]));
</del><ins>+            m_scripts.append(Script(false, false, argv[i]));
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         if (!strcmp(arg, &quot;-i&quot;)) {
</span><span class="lines">@@ -2197,6 +2247,23 @@
</span><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        if (!strcmp(arg, &quot;--test262-async&quot;)) {
+            test262AsyncTest = true;
+            continue;
+        }
+
+        static const unsigned strictFileStrLength = strlen(&quot;--strict-file=&quot;);
+        if (!strncmp(arg, &quot;--strict-file=&quot;, strictFileStrLength)) {
+            m_scripts.append(Script(true, true, argv[i] + strictFileStrLength));
+            continue;
+        }
+
+        static const unsigned exceptionStrLength = strlen(&quot;--exception=&quot;);
+        if (!strncmp(arg, &quot;--exception=&quot;, exceptionStrLength)) {
+            m_uncaughtExceptionName = String(arg + exceptionStrLength);
+            continue;
+        }
+
</ins><span class="cx">         // See if the -- option is a JSC VM option.
</span><span class="cx">         if (strstr(arg, &quot;--&quot;) == arg) {
</span><span class="cx">             if (!JSC::Options::setOption(&amp;arg[2])) {
</span><span class="lines">@@ -2208,7 +2275,7 @@
</span><span class="cx"> 
</span><span class="cx">         // This arg is not recognized by the VM nor by jsc. Pass it on to the
</span><span class="cx">         // script.
</span><del>-        m_scripts.append(Script(true, argv[i]));
</del><ins>+        m_scripts.append(Script(false, true, argv[i]));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (hasBadJSCOptions &amp;&amp; JSC::Options::validateOptions())
</span><span class="lines">@@ -2241,11 +2308,12 @@
</span><span class="cx">         vm-&gt;m_perBytecodeProfiler = std::make_unique&lt;Profiler::Database&gt;(*vm);
</span><span class="cx"> 
</span><span class="cx">     GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
</span><del>-    bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump, options.m_module);
</del><ins>+    bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_dump, options.m_module);
</ins><span class="cx">     if (options.m_interactive &amp;&amp; success)
</span><span class="cx">         runInteractive(globalObject);
</span><span class="cx"> 
</span><del>-    result = success ? 0 : 3;
</del><ins>+    vm-&gt;drainMicrotasks();
+    result = success &amp;&amp; (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
</ins><span class="cx"> 
</span><span class="cx">     if (options.m_exitCode)
</span><span class="cx">         printf(&quot;jsc exiting %d\n&quot;, result);
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (201038 => 201039)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-05-17 19:38:51 UTC (rev 201038)
+++ trunk/Tools/ChangeLog        2016-05-17 20:38:36 UTC (rev 201039)
</span><span class="lines">@@ -1,3 +1,34 @@
</span><ins>+2016-05-17  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        Add test262 harness support code
+        https://bugs.webkit.org/show_bug.cgi?id=157797
+
+        Reviewed by Filip Pizlo.
+
+        The import-test262-tests script is used to generate the yaml file used to run test262. It
+        takes a path to the local copy of the Test262 repository as well as an optional path to file
+        containing a list of failures. This script currently just creates the yaml file used to run
+        the script. It does not relocate the test files into our tests directory. In the future I
+        plan to add that feature but it didn't seem essential for the first iteration. Since many
+        test262 tests need to be run in both strict and non-strict mode, import-test262-tests
+        creates two separate runs for those tests. This enables us to distinguish between failures
+        in only one of the two modes.
+
+        This patch also updates the run-jsc-stress-tests Script to run tests from Test262. In order
+        to do so two new run commands were needed runTest262 and prepareTest262Fixture. runTest262
+        takes an actual test file along with the metadata associated with it. prepareTest262Fixture
+        takes a fixture file (used by module tests for importing) and makes sure that file is
+        properly relocated to the test runner directory.
+
+        The proccess I used to import the tests was to first run import-test262-tests to create a
+        yaml for all the tests (import-test262-tests assumes all tests pass if to failures file is
+        passed). Then I ran the generated yaml file with &quot;run-jsc-stress-tests -v -c 1&quot; piping the
+        output to a file and collected all the lines with &quot;FAIL&quot; in it. Finally, I reran
+        import-test262-tests with the new failure file to create the final yaml.
+
+        * Scripts/import-test262-tests: Added.
+        * Scripts/run-jsc-stress-tests:
+
</ins><span class="cx"> 2016-05-16  Enrica Casucci  &lt;enrica@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         build fix after r200968 and r200969
</span></span></pre></div>
<a id="trunkToolsScriptsimporttest262tests"></a>
<div class="addfile"><h4>Added: trunk/Tools/Scripts/import-test262-tests (0 => 201039)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/import-test262-tests                                (rev 0)
+++ trunk/Tools/Scripts/import-test262-tests        2016-05-17 20:38:36 UTC (rev 201039)
</span><span class="lines">@@ -0,0 +1,256 @@
</span><ins>+#!/usr/bin/env ruby
+
+# Copyright (C) 2016 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 AND ITS CONTRIBUTORS &quot;AS IS&quot; 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 OR ITS 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.
+
+
+require 'fileutils'
+require 'getoptlong'
+require 'pathname'
+require 'yaml'
+require 'find'
+
+THIS_SCRIPT_PATH = Pathname.new(__FILE__).realpath
+SCRIPTS_PATH = THIS_SCRIPT_PATH.dirname
+WEBKIT_PATH = SCRIPTS_PATH.dirname.dirname
+TEST262_YAML_PATH = WEBKIT_PATH + &quot;Source/JavaScriptCore/tests/test262.yaml&quot;
+
+raise unless SCRIPTS_PATH.basename.to_s == &quot;Scripts&quot;
+raise unless SCRIPTS_PATH.dirname.basename.to_s == &quot;Tools&quot;
+
+def mysys(*cmd)
+    printCommandArray(*cmd) if $verbosity &gt;= 1
+    raise &quot;Command failed: #{$?.inspect}&quot; unless system(*cmd)
+end
+
+
+def usage
+    puts &quot;import-test262-tests [options] &lt;path-to-test262-repository&gt;&quot;
+    puts
+    puts &quot;-h, --help                   print this help message.&quot;
+    puts &quot;-f, --failures FAILURES      Supplied file will be used to determine which tests fail.&quot;
+    puts &quot;                             If a failures file is not provided all tests are assumed to pass.&quot;
+
+    exit 1
+end
+
+$failures = nil
+JS_TEST_REGEXP = /.*\.js/
+JS_FIXTURE_REGEXP = /.*(_FIXTURE\.js|_\.js)/
+GET_YAML_REGEXP = /\/\*---(?&lt;yaml&gt;.*?)---\*\//m
+
+GetoptLong.new([&quot;--help&quot;, &quot;-h&quot;, GetoptLong::NO_ARGUMENT],
+               [&quot;--failures&quot;, &quot;-f&quot;, GetoptLong::REQUIRED_ARGUMENT]).each {
+    | opt, arg |
+    case opt
+    when &quot;--help&quot;
+        usage
+    when &quot;--failures&quot;
+        $failures = File.open(Pathname.new(arg)).readlines
+    end
+}
+
+def didPassForMode(path, strict)
+    if $failures
+        if strict == :strict
+            return $failures.grep(/.*#{path}\.default-strict$/).length == 0
+        else
+            return $failures.grep(/.*#{path}\.default$/).length == 0
+        end
+    else
+        return true
+    end
+end
+
+class Test
+    attr_writer :failsWithException, :isModule, :isAsync
+    attr_accessor :includeFiles, :needsStrict, :needsNonStrict
+    attr_reader :path
+
+    def initialize(path)
+        @path = path
+        @failsWithException = nil
+        @includeFiles = []
+        @needsStrict = true
+        @needsNonStrict = true
+        @isModule = false
+        @isAsync = false
+    end
+
+    def check
+        # Throw an exception here since I'm not sure if the test infrastructure works in these cases.
+        raise if !@needsStrict and !@needsNonStrict
+        raise if @isModule and !@needsNonStrict
+    end
+
+    def formatFlags(strict)
+        flags = []
+        flags &lt;&lt; strict if strict == :strict
+        flags &lt;&lt; :module if @isModule
+        flags &lt;&lt; :async if @isAsync
+
+        return flags.to_s
+    end
+
+    def formatCmdArguments(strict)
+        raise if strict == :strict ? !@needsStrict : !@needsNonStrict
+        passed = didPassForMode(@path, strict)
+        cmd = &quot;runTest262&quot;
+        cmd += passed ? &quot; :normal, &quot; : &quot; :fail, &quot;
+        cmd += @failsWithException ? @failsWithException.inspect : &quot;\&quot;NoException\&quot;&quot;
+        cmd += &quot;, #{@includeFiles.inspect}&quot;
+        cmd += &quot;, #{formatFlags(strict)}&quot;
+    end
+
+    def finalizeIncludes
+        if @isAsync
+            @includeFiles &lt;&lt; &quot;donePrintHandle.js&quot;
+        end
+
+        dir = Pathname.new(&quot;.&quot;)
+        @path.dirname.each_filename {
+            | part |
+            dir += &quot;..&quot;
+        }
+        dir += &quot;harness&quot;
+
+        @includeFiles.map! { | file | (dir + file).to_s }
+    end
+
+end
+
+def processTestFile(path)
+    /\/\*---(?&lt;yaml&gt;.*?)---\*\//m =~ File::read(path)
+
+    test = Test.new(path)
+    # These should be included by all the tests
+    test.includeFiles = [&quot;assert.js&quot;, &quot;sta.js&quot;]
+
+    begin
+        yamlElements = YAML::load(yaml)
+    rescue Exception =&gt; e
+        puts &quot;Failed to parse YAML for #{path}, threw exception:&quot;
+        puts e.inspect
+    end
+    yamlElements.each {
+        | option |
+        case option[0]
+        when &quot;negative&quot;
+            test.failsWithException = option[1].to_s
+        when &quot;includes&quot;
+            test.includeFiles += option[1]
+        when &quot;flags&quot;
+            option[1].each {
+                | flag |
+                case flag
+                when &quot;raw&quot;, &quot;noStrict&quot;
+                    test.needsStrict = false
+                when &quot;onlyStrict&quot;
+                    test.needsNonStrict = false
+                when &quot;module&quot;
+                    test.isModule = true
+                    test.needsStrict = false
+                when &quot;async&quot;
+                    test.isAsync = true
+                when &quot;generated&quot;
+                else
+                    raise &quot;Invalid Metadata flag option, #{flag}, when parsing #{$benchmarkDirectory + $benchmark}&quot;
+                end
+            }
+        end
+    }
+
+    test.finalizeIncludes
+    test.check
+
+    return test
+end
+
+class Fixture
+    attr_reader :path, :needsNonStrict, :needsStrict
+
+    def initialize(path)
+        @path = path
+        @needsNonStrict = true
+        @needsStrict = false
+    end
+
+    def formatCmdArguments(strict)
+        return &quot;prepareTest262Fixture&quot;
+    end
+
+end
+
+def processFixtureFile(path)
+    Fixture.new(path)
+end
+
+def processFilesRecursively(path)
+    # We only run the run the built-ins, language, and annexB tests.
+    # At some point we should add intl402
+    tests = []
+
+    Dir.chdir(path) {
+        paths = [Pathname.new(&quot;test/annexB&quot;), Pathname.new(&quot;test/built-ins&quot;), Pathname.new(&quot;test/language&quot;)]
+
+        paths.each {
+            | testPath |
+            Find.find(testPath) {
+                | file |
+                if File.file?(file) and JS_TEST_REGEXP =~ file.to_s
+                    path = Pathname.new(file)
+                    if JS_FIXTURE_REGEXP =~ file.to_s
+                        tests &lt;&lt; processFixtureFile(path)
+                    else
+                        tests &lt;&lt; processTestFile(path)
+                    end
+                end
+            }
+        }
+
+    }
+
+    return tests
+end
+
+def printYAML(tests)
+    File.open(TEST262_YAML_PATH, &quot;w+&quot;) {
+        | outp |
+        outp.puts &quot;---&quot;
+        tests.each {
+            | test |
+            if test.needsNonStrict
+                outp.puts &quot;- path: test262/&quot; + test.path.to_s
+                outp.puts &quot;  cmd: &quot; + test.formatCmdArguments(:nonStrict)
+            end
+            if test.needsStrict
+                outp.puts &quot;- path: test262/&quot; + test.path.to_s
+                outp.puts &quot;  cmd: &quot; + test.formatCmdArguments(:strict)
+            end
+        }
+
+    }
+end
+
+tests = processFilesRecursively(Pathname.new(ARGV[0]))
+printYAML(tests)
</ins><span class="cx">Property changes on: trunk/Tools/Scripts/import-test262-tests
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkToolsScriptsrunjscstresstests"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/run-jsc-stress-tests (201038 => 201039)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/run-jsc-stress-tests        2016-05-17 19:38:51 UTC (rev 201038)
+++ trunk/Tools/Scripts/run-jsc-stress-tests        2016-05-17 20:38:36 UTC (rev 201039)
</span><span class="lines">@@ -1011,6 +1011,61 @@
</span><span class="cx">     end
</span><span class="cx"> end
</span><span class="cx"> 
</span><ins>+def runTest262(mode, exception, includeFiles, flags)
+    failsWithException = exception != &quot;NoException&quot;
+    isStrict = false
+    isModule = false
+    isAsync = false
+
+    flags.each {
+        | flag |
+        case flag
+        when :strict
+            isStrict = true
+        when :module
+            isModule = true
+        when :async
+            isAsync = true
+        else
+            raise &quot;Invalid flag for runTest262, #{flag}&quot;
+        end
+    }
+
+    prepareExtraRelativeFiles(includeFiles.map { |f| &quot;../&quot; + f }, $collection)
+
+    args = [pathToVM.to_s] + BASE_OPTIONS
+    args &lt;&lt; &quot;-m&quot; if isModule
+    args &lt;&lt; &quot;--exception=&quot; + exception if failsWithException
+    args &lt;&lt; &quot;--test262-async&quot; if isAsync
+    args += includeFiles
+
+    case mode
+    when :normal
+        errorHandler = simpleErrorHandler
+        outputHandler = silentOutputHandler
+    when :fail
+        errorHandler = expectedFailErrorHandler
+        outputHandler = noisyOutputHandler
+    else
+        raise &quot;Invalid mode: #{mode}&quot;
+    end
+
+    if isStrict
+        kind = &quot;default-strict&quot;
+        args &lt;&lt; &quot;--strict-file=#{$benchmark}&quot;
+    else
+        kind = &quot;default&quot;
+        args &lt;&lt; $benchmark.to_s
+    end
+
+    addRunCommand(kind, args, outputHandler, errorHandler)
+end
+
+def prepareTest262Fixture
+    # This function is used to add the files used by Test262 modules tests.
+    prepareExtraRelativeFiles([&quot;&quot;], $collection)
+end
+
</ins><span class="cx"> def runES6(mode)
</span><span class="cx">     args = [pathToVM.to_s] + BASE_OPTIONS + [$benchmark.to_s]
</span><span class="cx">     case mode
</span><span class="lines">@@ -1149,7 +1204,9 @@
</span><span class="cx">     Dir.chdir($outputDir) {
</span><span class="cx">         extraFiles.each {
</span><span class="cx">             | file |
</span><del>-            FileUtils.cp $extraFilesBaseDir + file, destination + file
</del><ins>+            dest = destination + file
+            FileUtils.mkdir_p(dest.dirname)
+            FileUtils.cp $extraFilesBaseDir + file, dest
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> end
</span></span></pre>
</div>
</div>

</body>
</html>