Modified: trunk/Source/_javascript_Core/jsc.cpp (201038 => 201039)
--- trunk/Source/_javascript_Core/jsc.cpp 2016-05-17 19:38:51 UTC (rev 201038)
+++ trunk/Source/_javascript_Core/jsc.cpp 2016-05-17 20:38:36 UTC (rev 201039)
@@ -530,6 +530,8 @@
const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
+static bool test262AsyncPassed { false };
+static bool test262AsyncTest { false };
ElementHandleOwner* Element::handleOwner()
{
@@ -637,13 +639,17 @@
static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState*);
struct Script {
+ bool parseAsStrict;
bool isFile;
char* argument;
- Script(bool isFile, char *argument)
- : isFile(isFile)
+ Script(bool parseAsStrict, bool isFile, char *argument)
+ : parseAsStrict(parseAsStrict)
+ , isFile(isFile)
, argument(argument)
{
+ if (parseAsStrict)
+ ASSERT(isFile);
}
};
@@ -662,6 +668,7 @@
Vector<String> m_arguments;
bool m_profile { false };
String m_profilerOutput;
+ String m_uncaughtExceptionName;
bool m_dumpSamplingProfilerData { false };
void parseArguments(int, char**);
@@ -1038,12 +1045,14 @@
static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
{
+ // We might have injected "use strict"; at the top.
+ size_t initialSize = buffer.size();
fseek(file, 0, SEEK_END);
size_t bufferCapacity = ftell(file);
fseek(file, 0, SEEK_SET);
- buffer.resize(bufferCapacity);
- size_t readSize = fread(buffer.data(), 1, buffer.size(), file);
- return readSize == buffer.size();
+ buffer.resize(bufferCapacity + initialSize);
+ size_t readSize = fread(buffer.data() + initialSize, 1, buffer.size(), file);
+ return readSize == buffer.size() - initialSize;
}
static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer)
@@ -1115,6 +1124,13 @@
EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
{
+ if (test262AsyncTest) {
+ JSValue value = exec->argument(0);
+ if (value.isString() && WTF::equal(asString(value)->value(exec).impl(), "Test262:AsyncTestComplete"))
+ test262AsyncPassed = true;
+ return JSValue::encode(jsUndefined());
+ }
+
for (unsigned i = 0; i < exec->argumentCount(); ++i) {
if (i)
putchar(' ');
@@ -1973,8 +1989,31 @@
dumpException(globalObject, evaluationException->value());
}
-static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, bool dump, bool module)
+static bool checkUncaughtException(VM& vm, GlobalObject* globalObject, NakedPtr<Exception> evaluationException, const String& expectedExceptionName)
{
+ if (!evaluationException) {
+ printf("Expected uncaught exception with name '%s' but none was thrown\n", expectedExceptionName.utf8().data());
+ return false;
+ }
+
+ JSValue exception = evaluationException->value();
+ JSValue exceptionName = exception.get(globalObject->globalExec(), vm.propertyNames->name);
+
+ if (JSString* exceptionNameStr = jsDynamicCast<JSString*>(exceptionName)) {
+ const String& name = exceptionNameStr->value(globalObject->globalExec());
+ if (name == expectedExceptionName)
+ return true;
+ printf("Expected uncaught exception with name '%s' but got one with name '%s'\n", expectedExceptionName.utf8().data(), name.utf8().data());
+ dumpException(globalObject, exception);
+ return false;
+ }
+ printf("Expected uncaught exception with name '%s' but exception value did not have a name property\n", expectedExceptionName.utf8().data());
+ dumpException(globalObject, exception);
+ return false;
+}
+
+static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scripts, const String& uncaughtExceptionName, bool dump, bool module)
+{
String fileName;
Vector<char> scriptBuffer;
@@ -1998,6 +2037,9 @@
JSInternalPromise* promise = nullptr;
if (scripts[i].isFile) {
fileName = scripts[i].argument;
+ if (scripts[i].parseAsStrict)
+ scriptBuffer.append("\"use strict\";\n", strlen("\"use strict\";\n"));
+
if (module)
promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
else {
@@ -2014,19 +2056,24 @@
if (module) {
if (!promise)
promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
- globalObject->globalExec()->clearException();
+ vm.clearException();
promise->then(globalObject->globalExec(), nullptr, errorHandler);
- globalObject->vm().drainMicrotasks();
+ vm.drainMicrotasks();
} else {
NakedPtr<Exception> evaluationException;
JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
- success = success && !evaluationException;
- if (dump && !evaluationException)
- printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
- dumpException(globalObject, evaluationException);
+ if (!uncaughtExceptionName || i != scripts.size() - 1) {
+ success = success && !evaluationException;
+ if (dump && !evaluationException)
+ printf("End: %s\n", returnValue.toString(globalObject->globalExec())->value(globalObject->globalExec()).utf8().data());
+ dumpException(globalObject, evaluationException);
+ } else
+ success = success && checkUncaughtException(vm, globalObject, evaluationException, uncaughtExceptionName);
+
}
- globalObject->globalExec()->clearException();
+ scriptBuffer.clear();
+ vm.clearException();
}
#if ENABLE(REGEXP_TRACING)
@@ -2111,6 +2158,9 @@
fprintf(stderr, " -x Output exit code before terminating\n");
fprintf(stderr, "\n");
fprintf(stderr, " --sample Collects and outputs sampling profiler data\n");
+ fprintf(stderr, " --test262-async Check that some script calls the print function with the string 'Test262:AsyncTestComplete'\n");
+ fprintf(stderr, " --strict-file=<file> Parse the given file as if it were in strict mode (this option may be passed more than once)\n");
+ fprintf(stderr, " --exception=<name> Check the last script exits with an uncaught exception with the specified name\n");
fprintf(stderr, " --options Dumps all JSC VM options and exits\n");
fprintf(stderr, " --dumpOptions Dumps all non-default JSC VM options before continuing\n");
fprintf(stderr, " --<jsc VM option>=<value> Sets the specified JSC VM option\n");
@@ -2133,13 +2183,13 @@
if (!strcmp(arg, "-f")) {
if (++i == argc)
printUsageStatement();
- m_scripts.append(Script(true, argv[i]));
+ m_scripts.append(Script(false, true, argv[i]));
continue;
}
if (!strcmp(arg, "-e")) {
if (++i == argc)
printUsageStatement();
- m_scripts.append(Script(false, argv[i]));
+ m_scripts.append(Script(false, false, argv[i]));
continue;
}
if (!strcmp(arg, "-i")) {
@@ -2197,6 +2247,23 @@
continue;
}
+ if (!strcmp(arg, "--test262-async")) {
+ test262AsyncTest = true;
+ continue;
+ }
+
+ static const unsigned strictFileStrLength = strlen("--strict-file=");
+ if (!strncmp(arg, "--strict-file=", strictFileStrLength)) {
+ m_scripts.append(Script(true, true, argv[i] + strictFileStrLength));
+ continue;
+ }
+
+ static const unsigned exceptionStrLength = strlen("--exception=");
+ if (!strncmp(arg, "--exception=", exceptionStrLength)) {
+ m_uncaughtExceptionName = String(arg + exceptionStrLength);
+ continue;
+ }
+
// See if the -- option is a JSC VM option.
if (strstr(arg, "--") == arg) {
if (!JSC::Options::setOption(&arg[2])) {
@@ -2208,7 +2275,7 @@
// This arg is not recognized by the VM nor by jsc. Pass it on to the
// script.
- m_scripts.append(Script(true, argv[i]));
+ m_scripts.append(Script(false, true, argv[i]));
}
if (hasBadJSCOptions && JSC::Options::validateOptions())
@@ -2241,11 +2308,12 @@
vm->m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*vm);
GlobalObject* globalObject = GlobalObject::create(*vm, GlobalObject::createStructure(*vm, jsNull()), options.m_arguments);
- bool success = runWithScripts(globalObject, options.m_scripts, options.m_dump, options.m_module);
+ bool success = runWithScripts(globalObject, options.m_scripts, options.m_uncaughtExceptionName, options.m_dump, options.m_module);
if (options.m_interactive && success)
runInteractive(globalObject);
- result = success ? 0 : 3;
+ vm->drainMicrotasks();
+ result = success && (test262AsyncTest == test262AsyncPassed) ? 0 : 3;
if (options.m_exitCode)
printf("jsc exiting %d\n", result);
Added: trunk/Tools/Scripts/import-test262-tests (0 => 201039)
--- trunk/Tools/Scripts/import-test262-tests (rev 0)
+++ trunk/Tools/Scripts/import-test262-tests 2016-05-17 20:38:36 UTC (rev 201039)
@@ -0,0 +1,256 @@
+#!/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 "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 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 + "Source/_javascript_Core/tests/test262.yaml"
+
+raise unless SCRIPTS_PATH.basename.to_s == "Scripts"
+raise unless SCRIPTS_PATH.dirname.basename.to_s == "Tools"
+
+def mysys(*cmd)
+ printCommandArray(*cmd) if $verbosity >= 1
+ raise "Command failed: #{$?.inspect}" unless system(*cmd)
+end
+
+
+def usage
+ puts "import-test262-tests [options] <path-to-test262-repository>"
+ puts
+ puts "-h, --help print this help message."
+ puts "-f, --failures FAILURES Supplied file will be used to determine which tests fail."
+ puts " If a failures file is not provided all tests are assumed to pass."
+
+ exit 1
+end
+
+$failures = nil
+JS_TEST_REGEXP = /.*\.js/
+JS_FIXTURE_REGEXP = /.*(_FIXTURE\.js|_\.js)/
+GET_YAML_REGEXP = /\/\*---(?<yaml>.*?)---\*\//m
+
+GetoptLong.new(["--help", "-h", GetoptLong::NO_ARGUMENT],
+ ["--failures", "-f", GetoptLong::REQUIRED_ARGUMENT]).each {
+ | opt, arg |
+ case opt
+ when "--help"
+ usage
+ when "--failures"
+ $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 << strict if strict == :strict
+ flags << :module if @isModule
+ flags << :async if @isAsync
+
+ return flags.to_s
+ end
+
+ def formatCmdArguments(strict)
+ raise if strict == :strict ? !@needsStrict : !@needsNonStrict
+ passed = didPassForMode(@path, strict)
+ cmd = "runTest262"
+ cmd += passed ? " :normal, " : " :fail, "
+ cmd += @failsWithException ? @failsWithException.inspect : "\"NoException\""
+ cmd += ", #{@includeFiles.inspect}"
+ cmd += ", #{formatFlags(strict)}"
+ end
+
+ def finalizeIncludes
+ if @isAsync
+ @includeFiles << "donePrintHandle.js"
+ end
+
+ dir = Pathname.new(".")
+ @path.dirname.each_filename {
+ | part |
+ dir += ".."
+ }
+ dir += "harness"
+
+ @includeFiles.map! { | file | (dir + file).to_s }
+ end
+
+end
+
+def processTestFile(path)
+ /\/\*---(?<yaml>.*?)---\*\//m =~ File::read(path)
+
+ test = Test.new(path)
+ # These should be included by all the tests
+ test.includeFiles = ["assert.js", "sta.js"]
+
+ begin
+ yamlElements = YAML::load(yaml)
+ rescue Exception => e
+ puts "Failed to parse YAML for #{path}, threw exception:"
+ puts e.inspect
+ end
+ yamlElements.each {
+ | option |
+ case option[0]
+ when "negative"
+ test.failsWithException = option[1].to_s
+ when "includes"
+ test.includeFiles += option[1]
+ when "flags"
+ option[1].each {
+ | flag |
+ case flag
+ when "raw", "noStrict"
+ test.needsStrict = false
+ when "onlyStrict"
+ test.needsNonStrict = false
+ when "module"
+ test.isModule = true
+ test.needsStrict = false
+ when "async"
+ test.isAsync = true
+ when "generated"
+ else
+ raise "Invalid Metadata flag option, #{flag}, when parsing #{$benchmarkDirectory + $benchmark}"
+ 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 "prepareTest262Fixture"
+ 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("test/annexB"), Pathname.new("test/built-ins"), Pathname.new("test/language")]
+
+ 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 << processFixtureFile(path)
+ else
+ tests << processTestFile(path)
+ end
+ end
+ }
+ }
+
+ }
+
+ return tests
+end
+
+def printYAML(tests)
+ File.open(TEST262_YAML_PATH, "w+") {
+ | outp |
+ outp.puts "---"
+ tests.each {
+ | test |
+ if test.needsNonStrict
+ outp.puts "- path: test262/" + test.path.to_s
+ outp.puts " cmd: " + test.formatCmdArguments(:nonStrict)
+ end
+ if test.needsStrict
+ outp.puts "- path: test262/" + test.path.to_s
+ outp.puts " cmd: " + test.formatCmdArguments(:strict)
+ end
+ }
+
+ }
+end
+
+tests = processFilesRecursively(Pathname.new(ARGV[0]))
+printYAML(tests)
Property changes on: trunk/Tools/Scripts/import-test262-tests
___________________________________________________________________