From 05bbf90b3af78cbb10626a5a4a8e7fa88c80e6a9 Mon Sep 17 00:00:00 2001 From: "christian.plesner.hansen" Date: Wed, 27 Aug 2008 10:11:39 +0000 Subject: [PATCH] Changed shell sample to take flags directly from the command-line. Added api call that implements this. Added better test support. Added load, quit and version functions to the shell sample so it's easier to run benchmarks and tests. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- SConstruct | 167 ++++-- public/v8.h | 8 + samples/process.cc | 50 +- samples/shell.cc | 64 ++- src/SConscript | 5 +- src/api.cc | 5 + src/assembler-arm-inl.h | 51 +- src/assembler-arm.cc | 51 +- src/assembler-arm.h | 51 +- src/bootstrapper.cc | 13 +- src/builtins.cc | 2 +- src/codegen-arm.cc | 431 +++++++++------ src/factory.cc | 5 +- src/factory.h | 4 - src/flags.cc | 12 +- src/globals.h | 3 +- src/heap-inl.h | 8 - src/heap.cc | 22 +- src/heap.h | 5 +- src/objects-debug.cc | 1 + src/objects-inl.h | 7 + src/objects.cc | 126 +++-- src/objects.h | 60 ++- src/parser.cc | 5 +- src/property.cc | 3 + src/property.h | 7 +- src/runtime.cc | 79 ++- src/v8natives.js | 3 +- test/cctest/cctest.cc | 71 ++- test/cctest/cctest.h | 6 +- test/cctest/test-debug.cc | 84 +-- test/cctest/test-flags.cc | 4 +- test/cctest/testcfg.py | 84 +++ test/mjsunit/debug-script.js | 6 +- test/mjsunit/function-source.js | 2 - test/mjsunit/mirror-object.js | 9 +- test/mjsunit/regexp-multiline-stack-trace.js | 2 +- test/mjsunit/regress/regress-1341167.js | 33 ++ test/mjsunit/testcfg.py | 35 +- test/mozilla/mozilla.status | 762 +++++++++++++++++++++++++++ test/mozilla/testcfg.py | 125 +++++ tools/test.py | 286 +++++++--- 42 files changed, 2102 insertions(+), 655 deletions(-) create mode 100644 test/cctest/testcfg.py create mode 100644 test/mjsunit/regress/regress-1341167.js create mode 100644 test/mozilla/mozilla.status create mode 100644 test/mozilla/testcfg.py diff --git a/SConstruct b/SConstruct index 13e9dce..199afc4 100644 --- a/SConstruct +++ b/SConstruct @@ -28,6 +28,7 @@ import platform import re import sys +import os from os.path import join, dirname, abspath root_dir = dirname(File('SConstruct').rfile().abspath) sys.path.append(join(root_dir, 'tools')) @@ -41,7 +42,8 @@ LIBRARY_FLAGS = { 'gcc': { 'all': { 'DIALECTFLAGS': ['-ansi'], - 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'], + 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS', + '-fno-strict-aliasing'], 'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'], 'LIBS': ['pthread'] }, @@ -52,6 +54,9 @@ LIBRARY_FLAGS = { 'mode:release': { 'CCFLAGS': ['-O2'] }, + 'wordsize:64': { + 'CCFLAGS': ['-m32'] + }, }, 'msvc': { 'all': { @@ -83,10 +88,13 @@ LIBRARY_FLAGS = { V8_EXTRA_FLAGS = { 'gcc': { 'all': { - 'CXXFLAGS': ['-fvisibility=hidden'], + 'CXXFLAGS': [], #['-fvisibility=hidden'], 'WARNINGFLAGS': ['-pedantic', '-Wall', '-Werror', '-W', '-Wno-unused-parameter'] }, + 'arch:arm': { + 'CPPDEFINES': ['ARM'] + }, }, 'msvc': { 'all': { @@ -95,6 +103,9 @@ V8_EXTRA_FLAGS = { 'library:shared': { 'CPPDEFINES': ['BUILDING_V8_SHARED'] }, + 'arch:arm': { + 'CPPDEFINES': ['ARM'] + }, } } @@ -143,6 +154,9 @@ CCTEST_EXTRA_FLAGS = { } }, 'msvc': { + 'all': { + 'CPPDEFINES': ['_HAS_EXCEPTIONS=0'] + }, 'library:shared': { 'CPPDEFINES': ['USING_V8_SHARED'] } @@ -198,17 +212,24 @@ def GuessOS(): elif id == 'Windows': return 'win32' else: - return '' + return None -def GuessProcessor(): +def GuessArchitecture(): id = platform.machine() if id.startswith('arm'): return 'arm' elif (not id) or (not re.match('(x|i[3-6])86', id) is None): return 'ia32' else: - return '' + return None + + +def GuessWordsize(): + if '64' in platform.machine(): + return '64' + else: + return '32' def GuessToolchain(os): @@ -218,21 +239,61 @@ def GuessToolchain(os): elif 'msvc' in tools: return 'msvc' else: - return '' + return None + + +OS_GUESS = GuessOS() +TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS) +ARCH_GUESS = GuessArchitecture() +WORDSIZE_GUESS = GuessWordsize() + + +SIMPLE_OPTIONS = { + 'toolchain': { + 'values': ['gcc', 'msvc'], + 'default': TOOLCHAIN_GUESS, + 'help': 'the toolchain to use' + }, + 'os': { + 'values': ['linux', 'macos', 'win32'], + 'default': OS_GUESS, + 'help': 'the os to build for' + }, + 'arch': { + 'values':['arm', 'ia32'], + 'default': ARCH_GUESS, + 'help': 'the architecture to build for' + }, + 'snapshot': { + 'values': ['on', 'off'], + 'default': 'off', + 'help': 'build using snapshots for faster start-up' + }, + 'library': { + 'values': ['static', 'shared', 'default'], + 'default': 'default', + 'help': 'the type of library to produce' + }, + 'wordsize': { + 'values': ['64', '32'], + 'default': WORDSIZE_GUESS, + 'help': 'the word size' + }, + 'simulator': { + 'values': ['arm', 'none'], + 'default': 'none', + 'help': 'build with simulator' + } +} def GetOptions(): result = Options() - os_guess = GuessOS() - toolchain_guess = GuessToolchain(os_guess) - processor_guess = GuessProcessor() result.Add('mode', 'compilation mode (debug, release)', 'release') - result.Add('toolchain', 'the toolchain to use (gcc, msvc)', toolchain_guess) - result.Add('os', 'the os to build for (linux, macos, win32)', os_guess) - result.Add('processor', 'the processor to build for (arm, ia32)', processor_guess) - result.Add('snapshot', 'build using snapshots for faster start-up (on, off)', 'off') - result.Add('library', 'which type of library to produce (static, shared, default)', 'default') result.Add('sample', 'build sample (shell, process)', '') + for (name, option) in SIMPLE_OPTIONS.items(): + help = '%s (%s)' % (name, ", ".join(option['values'])) + result.Add(name, help, option.get('default')) return result @@ -252,51 +313,46 @@ def IsLegal(env, option, values): def VerifyOptions(env): if not IsLegal(env, 'mode', ['debug', 'release']): return False - if not env['toolchain'] in ['gcc', 'msvc']: - Abort("Unknown toolchain '%s'." % env['toolchain']) - if not env['os'] in ['linux', 'macos', 'win32']: - Abort("Unknown os '%s'." % env['os']) - if not env['processor'] in ['arm', 'ia32']: - Abort("Unknown processor '%s'." % env['processor']) - if not env['snapshot'] in ['on', 'off']: - Abort("Illegal value for option snapshot: '%s'." % env['snapshot']) - if not env['library'] in ['static', 'shared', 'default']: - Abort("Illegal value for option library: '%s'." % env['library']) if not IsLegal(env, 'sample', ["shell", "process"]): return False + for (name, option) in SIMPLE_OPTIONS.items(): + if (not option.get('default')) and (name not in ARGUMENTS): + message = ("A value for option %s must be specified (%s)." % + (name, ", ".join(option['values']))) + Abort(message) + if not env[name] in option['values']: + message = ("Unknown %s value '%s'. Possible values are (%s)." % + (name, env[name], ", ".join(option['values']))) + Abort(message) class BuildContext(object): - def __init__(self, os, arch, toolchain, snapshot, library, samples, mode): + def __init__(self, options, samples): self.library_targets = [] self.cctest_targets = [] self.sample_targets = [] - self.os = os - self.arch = arch - self.toolchain = toolchain - self.snapshot = snapshot - self.library = library + self.options = options self.samples = samples - self.mode = mode - self.use_snapshot = (snapshot == 'on') + self.use_snapshot = (options['snapshot'] == 'on') self.flags = None def AddRelevantFlags(self, initial, flags): result = initial.copy() self.AppendFlags(result, flags.get('all')) - self.AppendFlags(result, flags[self.toolchain].get('all')) - self.AppendFlags(result, flags[self.toolchain].get('mode:' + self.mode)) - self.AppendFlags(result, flags[self.toolchain].get('library:' + self.library)) + toolchain = self.options['toolchain'] + self.AppendFlags(result, flags[toolchain].get('all')) + for option in sorted(self.options.keys()): + value = self.options[option] + self.AppendFlags(result, flags[toolchain].get(option + ':' + value)) return result def GetRelevantSources(self, source): result = [] result += source.get('all', []) - result += source.get('arch:' + self.arch, []) - result += source.get('os:' + self.os, []) - result += source.get('mode:' + self.mode, []) - return result + for (name, value) in self.options.items(): + result += source.get(name + ':' + value, []) + return sorted(result) def AppendFlags(self, options, added): if not added: @@ -306,28 +362,39 @@ class BuildContext(object): options[key] = value else: options[key] = options[key] + value - + def ConfigureObject(self, env, input, **kw): - if self.library == 'static': + if self.options['library'] == 'static': return env.StaticObject(input, **kw) - elif self.library == 'shared': + elif self.options['library'] == 'shared': return env.SharedObject(input, **kw) else: return env.Object(input, **kw) +def PostprocessOptions(options): + # Adjust architecture if the simulator option has been set + if (options['simulator'] != 'none') and (options['arch'] != options['simulator']): + if 'arch' in ARGUMENTS: + # Print a warning if arch has explicitly been set + print "Warning: forcing architecture to match simulator (%s)" % options['simulator'] + options['arch'] = options['simulator'] + + def BuildSpecific(env, mode): - context = BuildContext(os=env['os'], arch=env['processor'], - toolchain=env['toolchain'], snapshot=env['snapshot'], - library=env['library'], samples=SplitList(env['sample']), - mode=mode) + options = {'mode': mode} + for option in SIMPLE_OPTIONS: + options[option] = env[option] + PostprocessOptions(options) + + context = BuildContext(options, samples=SplitList(env['sample'])) - library_flags = context.AddRelevantFlags({}, LIBRARY_FLAGS) + library_flags = context.AddRelevantFlags(os.environ, LIBRARY_FLAGS) v8_flags = context.AddRelevantFlags(library_flags, V8_EXTRA_FLAGS) jscre_flags = context.AddRelevantFlags(library_flags, JSCRE_EXTRA_FLAGS) dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS) cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS) - sample_flags = context.AddRelevantFlags({}, SAMPLE_FLAGS) + sample_flags = context.AddRelevantFlags(os.environ, SAMPLE_FLAGS) context.flags = { 'v8': v8_flags, @@ -351,9 +418,9 @@ def BuildSpecific(env, mode): ) # Link the object files into a library. - if context.library == 'static': + if context.options['library'] == 'static': library = env.StaticLibrary(library_name, object_files) - elif context.library == 'shared': + elif context.options['library'] == 'shared': # There seems to be a glitch in the way scons decides where to put # PDB files when compiling using MSVC so we specify it manually. # This should not affect any other platforms. diff --git a/public/v8.h b/public/v8.h index be64d23..083f2c4 100644 --- a/public/v8.h +++ b/public/v8.h @@ -1673,6 +1673,14 @@ class EXPORT V8 { */ static void SetFlagsFromString(const char* str, int length); + /** + * Sets v8 flags from command line. + * TODO(758124): Describe flags? + */ + static void SetFlagsFromCommandLine(int* argc, + char** argv, + bool remove_flags); + /** Get the version string. */ static const char* GetVersion(); diff --git a/samples/process.cc b/samples/process.cc index d468395..8f3c032 100644 --- a/samples/process.cc +++ b/samples/process.cc @@ -62,7 +62,7 @@ class HttpRequestProcessor { // Initialize this processor. The map contains options that control // how requests should be processed. virtual bool Initialize(map* options, - map* output) = 0; + map* output) = 0; // Process a single request. virtual bool Process(HttpRequest* req) = 0; @@ -78,17 +78,17 @@ class JsHttpRequestProcessor : public HttpRequestProcessor { // Creates a new processor that processes requests by invoking the // Process function of the JavaScript script given as an argument. - JsHttpRequestProcessor(Handle script) : script_(script) { } + explicit JsHttpRequestProcessor(Handle script) : script_(script) { } virtual ~JsHttpRequestProcessor(); virtual bool Initialize(map* opts, - map* output); + map* output); virtual bool Process(HttpRequest* req); private: - // Execute the script associated with this processor and extract the - // Process function. Returns true if this succeeded, otherwise false. + // Execute the script associated with this processor and extract the + // Process function. Returns true if this succeeded, otherwise false. bool ExecuteScript(Handle script); // Wrap the options and output map in a JavaScript objects and @@ -108,8 +108,9 @@ class JsHttpRequestProcessor : public HttpRequestProcessor { // Callbacks that access maps static Handle MapGet(Local name, const AccessorInfo& info); - static Handle MapSet(Local name, Local value, - const AccessorInfo& info); + static Handle MapSet(Local name, + Local value, + const AccessorInfo& info); // Utility methods for wrapping C++ objects as JavaScript objects, // and going back again. @@ -142,7 +143,7 @@ static Handle LogCallback(const Arguments& args) { // Execute the script and fetch the Process method. bool JsHttpRequestProcessor::Initialize(map* opts, - map* output) { + map* output) { // Create a handle scope to hold the temporary references. HandleScope handle_scope; @@ -223,7 +224,7 @@ bool JsHttpRequestProcessor::ExecuteScript(Handle script) { bool JsHttpRequestProcessor::InstallMaps(map* opts, - map* output) { + map* output) { HandleScope handle_scope; // Wrap the map object in a JavaScript wrapper @@ -335,7 +336,7 @@ string ObjectToString(Local value) { Handle JsHttpRequestProcessor::MapGet(Local name, - const AccessorInfo& info) { + const AccessorInfo& info) { // Fetch the map wrapped by this object. map* obj = UnwrapMap(info.Holder()); @@ -355,7 +356,8 @@ Handle JsHttpRequestProcessor::MapGet(Local name, Handle JsHttpRequestProcessor::MapSet(Local name, - Local value_obj, const AccessorInfo& info) { + Local value_obj, + const AccessorInfo& info) { // Fetch the map wrapped by this object. map* obj = UnwrapMap(info.Holder()); @@ -433,7 +435,7 @@ HttpRequest* JsHttpRequestProcessor::UnwrapRequest(Handle obj) { Handle JsHttpRequestProcessor::GetPath(Local name, - const AccessorInfo& info) { + const AccessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. HttpRequest* request = UnwrapRequest(info.Holder()); @@ -446,7 +448,7 @@ Handle JsHttpRequestProcessor::GetPath(Local name, Handle JsHttpRequestProcessor::GetReferrer(Local name, - const AccessorInfo& info) { + const AccessorInfo& info) { HttpRequest* request = UnwrapRequest(info.Holder()); const string& path = request->Referrer(); return String::New(path.c_str(), path.length()); @@ -454,7 +456,7 @@ Handle JsHttpRequestProcessor::GetReferrer(Local name, Handle JsHttpRequestProcessor::GetHost(Local name, - const AccessorInfo& info) { + const AccessorInfo& info) { HttpRequest* request = UnwrapRequest(info.Holder()); const string& path = request->Host(); return String::New(path.c_str(), path.length()); @@ -462,7 +464,7 @@ Handle JsHttpRequestProcessor::GetHost(Local name, Handle JsHttpRequestProcessor::GetUserAgent(Local name, - const AccessorInfo& info) { + const AccessorInfo& info) { HttpRequest* request = UnwrapRequest(info.Holder()); const string& path = request->UserAgent(); return String::New(path.c_str(), path.length()); @@ -499,8 +501,10 @@ void HttpRequestProcessor::Log(const char* event) { */ class StringHttpRequest : public HttpRequest { public: - StringHttpRequest(const string& path, const string& referrer, - const string& host, const string& user_agent); + StringHttpRequest(const string& path, + const string& referrer, + const string& host, + const string& user_agent); virtual const string& Path() { return path_; } virtual const string& Referrer() { return referrer_; } virtual const string& Host() { return host_; } @@ -514,15 +518,19 @@ class StringHttpRequest : public HttpRequest { StringHttpRequest::StringHttpRequest(const string& path, - const string& referrer, const string& host, const string& user_agent) + const string& referrer, + const string& host, + const string& user_agent) : path_(path), referrer_(referrer), host_(host), user_agent_(user_agent) { } -void ParseOptions(int argc, char* argv[], map& options, - string* file) { +void ParseOptions(int argc, + char* argv[], + map& options, + string* file) { for (int i = 1; i < argc; i++) { string arg = argv[i]; int index = arg.find('=', 0); @@ -571,7 +579,7 @@ StringHttpRequest kSampleRequests[kSampleSize] = { bool ProcessEntries(HttpRequestProcessor* processor, int count, - StringHttpRequest* reqs) { + StringHttpRequest* reqs) { for (int i = 0; i < count; i++) { if (!processor->Process(&reqs[i])) return false; diff --git a/samples/shell.cc b/samples/shell.cc index 73b979a..8ab60f3 100644 --- a/samples/shell.cc +++ b/samples/shell.cc @@ -28,6 +28,7 @@ #include #include #include +#include void RunShell(v8::Handle context); @@ -35,18 +36,28 @@ bool ExecuteString(v8::Handle source, v8::Handle name, bool print_result); v8::Handle Print(const v8::Arguments& args); +v8::Handle Load(const v8::Arguments& args); +v8::Handle Quit(const v8::Arguments& args); +v8::Handle Version(const v8::Arguments& args); v8::Handle ReadFile(const char* name); void ProcessRuntimeFlags(int argc, char* argv[]); int main(int argc, char* argv[]) { - ProcessRuntimeFlags(argc, argv); + v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::HandleScope handle_scope; // Create a template for the global object. v8::Handle global = v8::ObjectTemplate::New(); // Bind the global 'print' function to the C++ Print callback. global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); - // Create a new execution environment containing the 'print' function. + // Bind the global 'load' function to the C++ Load callback. + global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); + // Bind the 'quit' function + global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); + // Bind the 'version' function + global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); + // Create a new execution environment containing the built-in + // functions v8::Handle context = v8::Context::New(NULL, global); // Enter the newly created execution environment. v8::Context::Scope context_scope(context); @@ -55,9 +66,8 @@ int main(int argc, char* argv[]) { const char* str = argv[i]; if (strcmp(str, "--shell") == 0) { run_shell = true; - } else if (strcmp(str, "--runtime-flags") == 0) { - // Skip the --runtime-flags flag since it was processed earlier. - i++; + } else if (strncmp(str, "--", 2) == 0) { + printf("Warning: unknown flag %s.\n", str); } else { // Use all other arguments as names of files to load and run. v8::HandleScope handle_scope; @@ -93,6 +103,39 @@ v8::Handle Print(const v8::Arguments& args) { } +// The callback that is invoked by v8 whenever the JavaScript 'load' +// function is called. Loads, compiles and executes its argument +// JavaScript file. +v8::Handle Load(const v8::Arguments& args) { + for (int i = 0; i < args.Length(); i++) { + v8::HandleScope handle_scope; + v8::String::AsciiValue file(args[i]); + v8::Handle source = ReadFile(*file); + if (source.IsEmpty()) { + return v8::ThrowException(v8::String::New("Error loading file")); + } + ExecuteString(source, v8::String::New(*file), false); + } + return v8::Undefined(); +} + + +// The callback that is invoked by v8 whenever the JavaScript 'quit' +// function is called. Quits. +v8::Handle Quit(const v8::Arguments& args) { + // If not arguments are given args[0] will yield undefined which + // converts to the integer value 0. + int exit_code = args[0]->Int32Value(); + exit(exit_code); + return v8::Undefined(); +} + + +v8::Handle Version(const v8::Arguments& args) { + return v8::String::New(v8::V8::GetVersion()); +} + + // Reads a file into a v8 string. v8::Handle ReadFile(const char* name) { FILE* file = fopen(name, "rb"); @@ -161,14 +204,3 @@ bool ExecuteString(v8::Handle source, } } } - - -// Set the vm flags before using the vm. -void ProcessRuntimeFlags(int argc, char* argv[]) { - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--runtime-flags") == 0 && i + 1 < argc) { - i++; - v8::V8::SetFlagsFromString(argv[i], strlen(argv[i])); - } - } -} diff --git a/src/SConscript b/src/SConscript index a5a919a..135af67 100644 --- a/src/SConscript +++ b/src/SConscript @@ -50,10 +50,11 @@ SOURCES = { ], 'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc', 'cpu-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'ic-arm.cc', - 'macro-assembler-arm.cc', 'simulator-arm.cc', 'stub-cache-arm.cc'], + 'macro-assembler-arm.cc', 'stub-cache-arm.cc'], 'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc', 'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc', - 'macro-assembler-ia32.cc', 'simulator-ia32.cc', 'stub-cache-ia32.cc'], + 'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'], + 'simulator:arm': ['simulator-arm.cc'], 'os:linux': ['platform-linux.cc'], 'os:macos': ['platform-macos.cc'], 'os:nullos': ['platform-nullos.cc'], diff --git a/src/api.cc b/src/api.cc index 2646448..a09f7d2 100644 --- a/src/api.cc +++ b/src/api.cc @@ -223,6 +223,11 @@ void V8::SetFlagsFromString(const char* str, int length) { } +void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { + i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags); +} + + v8::Handle ThrowException(v8::Handle value) { if (IsDeadCheck("v8::ThrowException()")) return v8::Handle(); i::Top::ScheduleThrow(*Utils::OpenHandle(*value)); diff --git a/src/assembler-arm-inl.h b/src/assembler-arm-inl.h index fbe8cce..6bc900a 100644 --- a/src/assembler-arm-inl.h +++ b/src/assembler-arm-inl.h @@ -1,29 +1,38 @@ -// Copyright 2007-2008 Google Inc. All Rights Reserved. +// Copyright (c) 1994-2006 Sun Microsystems 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: +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// - Redistribution 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. // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. +// - Neither the name of Sun Microsystems or the names of contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -// OWNER 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. +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER 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. + +// The original source code covered by the above license above has been modified +// significantly by Google Inc. +// Copyright 2006-2008 Google Inc. All Rights Reserved. #ifndef V8_ASSEMBLER_ARM_INL_H_ #define V8_ASSEMBLER_ARM_INL_H_ diff --git a/src/assembler-arm.cc b/src/assembler-arm.cc index 2f56efd..de029cd 100644 --- a/src/assembler-arm.cc +++ b/src/assembler-arm.cc @@ -1,29 +1,38 @@ -// Copyright 2006-2008 Google Inc. All Rights Reserved. +// Copyright (c) 1994-2006 Sun Microsystems 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: +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. +// - Redistribution 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. +// +// - Neither the name of Sun Microsystems or the names of contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -// OWNER 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. +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER 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. + +// The original source code covered by the above license above has been modified +// significantly by Google Inc. +// Copyright 2006-2008 Google Inc. All Rights Reserved. #include "v8.h" diff --git a/src/assembler-arm.h b/src/assembler-arm.h index 43bedff..f8cdb00 100644 --- a/src/assembler-arm.h +++ b/src/assembler-arm.h @@ -1,29 +1,38 @@ -// Copyright 2007-2008 Google Inc. All Rights Reserved. +// Copyright (c) 1994-2006 Sun Microsystems 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: +// modification, are permitted provided that the following conditions +// are met: +// +// - Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// - Redistribution 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. // -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. +// - Neither the name of Sun Microsystems or the names of contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -// OWNER 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. +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER 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. + +// The original source code covered by the above license above has been modified +// significantly by Google Inc. +// Copyright 2006-2008 Google Inc. All Rights Reserved. // A light-weight ARM Assembler // Generates user mode instructions for the ARM architecture up to version 5 diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 6aceafe..0cb688e 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -379,9 +379,9 @@ Handle Genesis::ComputeFunctionInstanceDescriptor( // Add prototype. PropertyAttributes attributes = static_cast( - (make_prototype_enumerable ? 0 : DONT_ENUM) - | DONT_DELETE - | (make_prototype_read_only ? READ_ONLY : 0)); + (make_prototype_enumerable ? 0 : DONT_ENUM) + | DONT_DELETE + | (make_prototype_read_only ? READ_ONLY : 0)); result = Factory::CopyAppendProxyDescriptor( result, @@ -481,8 +481,8 @@ void Genesis::CreateRoots(v8::Handle global_template, global_context()->set_initial_object_prototype(*prototype); SetPrototype(object_fun, prototype); - object_function_map->set_instance_descriptors( - DescriptorArray::cast(Heap::empty_fixed_array())); + object_function_map-> + set_instance_descriptors(Heap::empty_descriptor_array()); } // Allocate the empty function as the prototype for function ECMAScript @@ -1192,7 +1192,8 @@ void Genesis::TransferNamedProperties(Handle from, } case MAP_TRANSITION: case CONSTANT_TRANSITION: - // Ignore map transitions. + case NULL_DESCRIPTOR: + // Ignore non-properties. break; case NORMAL: // Do not occur since the from object has fast properties. diff --git a/src/builtins.cc b/src/builtins.cc index b51c39b..9f95322 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -352,7 +352,7 @@ BUILTIN_0(HandleApiCall) { HandleScope scope; // TODO(1238487): This is not nice. We need to get rid of this - // retarded behavior and start handling API calls in a more direct + // kludgy behavior and start handling API calls in a more direct // way - maybe compile specialized stubs lazily?. #ifdef USE_OLD_CALLING_CONVENTIONS Handle function = diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc index 3f72b03..30c1e4b 100644 --- a/src/codegen-arm.cc +++ b/src/codegen-arm.cc @@ -1084,6 +1084,12 @@ class GenericBinaryOpStub : public CodeStub { case Token::SUB: return "GenericBinaryOpStub_SUB"; case Token::MUL: return "GenericBinaryOpStub_MUL"; case Token::DIV: return "GenericBinaryOpStub_DIV"; + case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; + case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; + case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; + case Token::SAR: return "GenericBinaryOpStub_SAR"; + case Token::SHL: return "GenericBinaryOpStub_SHL"; + case Token::SHR: return "GenericBinaryOpStub_SHR"; default: return "GenericBinaryOpStub"; } } @@ -1175,75 +1181,104 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { __ bind(&exit); break; } - default: UNREACHABLE(); - } - __ Ret(); -} - -class SmiOpStub : public CodeStub { - public: - SmiOpStub(Token::Value op, bool reversed) - : op_(op), reversed_(reversed) {} - - private: - Token::Value op_; - bool reversed_; - - Major MajorKey() { return SmiOp; } - int MinorKey() { - return (op_ == Token::ADD ? 2 : 0) | (reversed_ ? 1 : 0); - } - void Generate(MacroAssembler* masm); - void GenerateShared(MacroAssembler* masm); + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: { + Label slow, exit; + // tag check + __ orr(r2, r1, Operand(r0)); // r2 = x | y; + ASSERT(kSmiTag == 0); // adjust code below + __ tst(r2, Operand(kSmiTagMask)); + __ b(ne, &slow); + switch (op_) { + case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; + case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; + case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; + default: UNREACHABLE(); + } + __ b(&exit); + __ bind(&slow); + __ push(r1); // restore stack + __ push(r0); + __ mov(r0, Operand(1)); // 1 argument (not counting receiver). + switch (op_) { + case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, JUMP_JS); break; + case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, JUMP_JS); break; + case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, JUMP_JS); break; + default: UNREACHABLE(); + } + __ bind(&exit); + break; + } - const char* GetName() { return "SmiOpStub"; } + case Token::SHL: + case Token::SHR: + case Token::SAR: { + Label slow, exit; + // tag check + __ orr(r2, r1, Operand(r0)); // r2 = x | y; + ASSERT(kSmiTag == 0); // adjust code below + __ tst(r2, Operand(kSmiTagMask)); + __ b(ne, &slow); + // remove tags from operands (but keep sign) + __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x + __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y + // use only the 5 least significant bits of the shift count + __ and_(r2, r2, Operand(0x1f)); + // perform operation + switch (op_) { + case Token::SAR: + __ mov(r3, Operand(r3, ASR, r2)); + // no checks of result necessary + break; -#ifdef DEBUG - void Print() { - PrintF("SmiOpStub (token %s), (reversed %s)\n", - Token::String(op_), reversed_ ? "true" : "false"); - } -#endif -}; + case Token::SHR: + __ mov(r3, Operand(r3, LSR, r2)); + // check that the *unsigned* result fits in a smi + // neither of the two high-order bits can be set: + // - 0x80000000: high bit would be lost when smi tagging + // - 0x40000000: this number would convert to negative when + // smi tagging these two cases can only happen with shifts + // by 0 or 1 when handed a valid smi + __ and_(r2, r3, Operand(0xc0000000), SetCC); + __ b(ne, &slow); + break; + case Token::SHL: + __ mov(r3, Operand(r3, LSL, r2)); + // check that the *signed* result fits in a smi + __ add(r2, r3, Operand(0x40000000), SetCC); + __ b(mi, &slow); + break; -void SmiOpStub::Generate(MacroAssembler* masm) { - switch (op_) { - case Token::ADD: { - if (!reversed_) { - __ sub(r0, r0, Operand(r1)); // revert optimistic add - __ push(r0); - __ push(r1); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin("ADD", 1, JUMP_JS); - } else { - __ sub(r0, r0, Operand(r1)); // revert optimistic add - __ push(r1); // reversed - __ push(r0); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin("ADD", 1, JUMP_JS); + default: UNREACHABLE(); } - break; - } - case Token::SUB: { - if (!reversed_) { - __ push(r0); - __ push(r1); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin("SUB", 1, JUMP_JS); - } else { - __ push(r1); - __ push(r0); - __ mov(r0, Operand(1)); // set number of arguments - __ InvokeBuiltin("SUB", 1, JUMP_JS); + // tag result and store it in r0 + ASSERT(kSmiTag == 0); // adjust code below + __ mov(r0, Operand(r3, LSL, kSmiTagSize)); + __ b(&exit); + // slow case + __ bind(&slow); + __ push(r1); // restore stack + __ push(r0); + __ mov(r0, Operand(1)); // 1 argument (not counting receiver). + switch (op_) { + case Token::SAR: __ InvokeBuiltin("SAR", 1, JUMP_JS); break; + case Token::SHR: __ InvokeBuiltin("SHR", 1, JUMP_JS); break; + case Token::SHL: __ InvokeBuiltin("SHL", 1, JUMP_JS); break; + default: UNREACHABLE(); } + __ bind(&exit); break; } + default: UNREACHABLE(); } + __ Ret(); } + void StackCheckStub::Generate(MacroAssembler* masm) { Label within_limit; __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit())); @@ -1866,7 +1901,13 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { switch (op) { case Token::ADD: // fall through. case Token::SUB: // fall through. - case Token::MUL: { + case Token::MUL: + case Token::BIT_OR: + case Token::BIT_AND: + case Token::BIT_XOR: + case Token::SHL: + case Token::SHR: + case Token::SAR: { __ pop(r0); // r0 : y __ pop(r1); // r1 : x GenericBinaryOpStub stub(op); @@ -1886,101 +1927,6 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { break; } - case Token::BIT_OR: - case Token::BIT_AND: - case Token::BIT_XOR: { - Label slow, exit; - __ pop(r0); // get y - __ pop(r1); // get x - // tag check - __ orr(r2, r1, Operand(r0)); // r2 = x | y; - ASSERT(kSmiTag == 0); // adjust code below - __ tst(r2, Operand(kSmiTagMask)); - __ b(ne, &slow); - switch (op) { - case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; - case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; - case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; - default: UNREACHABLE(); - } - __ b(&exit); - __ bind(&slow); - __ push(r1); // restore stack - __ push(r0); - __ mov(r0, Operand(1)); // 1 argument (not counting receiver). - switch (op) { - case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, CALL_JS); break; - case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, CALL_JS); break; - case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, CALL_JS); break; - default: UNREACHABLE(); - } - __ bind(&exit); - break; - } - - case Token::SHL: - case Token::SHR: - case Token::SAR: { - Label slow, exit; - __ pop(r0); // get y - __ pop(r1); // get x - // tag check - __ orr(r2, r1, Operand(r0)); // r2 = x | y; - ASSERT(kSmiTag == 0); // adjust code below - __ tst(r2, Operand(kSmiTagMask)); - __ b(ne, &slow); - // remove tags from operands (but keep sign) - __ mov(r3, Operand(r1, ASR, kSmiTagSize)); - __ mov(r2, Operand(r0, ASR, kSmiTagSize)); - // use only the 5 least significant bits of the shift count - __ and_(r2, r2, Operand(0x1f)); - // perform operation - switch (op) { - case Token::SAR: - __ mov(r3, Operand(r3, ASR, r2)); - // no checks of result necessary - break; - - case Token::SHR: - __ mov(r3, Operand(r3, LSR, r2)); - // check that the *unsigned* result fits in a smi - // neither of the two high-order bits can be set: - // - 0x80000000: high bit would be lost when smi tagging - // - 0x40000000: this number would convert to negative when - // smi tagging these two cases can only happen with shifts - // by 0 or 1 when handed a valid smi - __ and_(r2, r3, Operand(0xc0000000), SetCC); - __ b(ne, &slow); - break; - - case Token::SHL: - __ mov(r3, Operand(r3, LSL, r2)); - // check that the *signed* result fits in a smi - __ add(r2, r3, Operand(0x40000000), SetCC); - __ b(mi, &slow); - break; - - default: UNREACHABLE(); - } - // tag result and store it in r0 - ASSERT(kSmiTag == 0); // adjust code below - __ mov(r0, Operand(r3, LSL, kSmiTagSize)); - __ b(&exit); - // slow case - __ bind(&slow); - __ push(r1); // restore stack - __ push(r0); - __ mov(r0, Operand(1)); // 1 argument (not counting receiver). - switch (op) { - case Token::SAR: __ InvokeBuiltin("SAR", 1, CALL_JS); break; - case Token::SHR: __ InvokeBuiltin("SHR", 1, CALL_JS); break; - case Token::SHL: __ InvokeBuiltin("SHL", 1, CALL_JS); break; - default: UNREACHABLE(); - } - __ bind(&exit); - break; - } - case Token::COMMA: __ pop(r0); // simply discard left value @@ -1995,6 +1941,82 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { } +class DeferredInlinedSmiOperation: public DeferredCode { + public: + DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op, + int value, bool reversed) : + DeferredCode(generator), op_(op), value_(value), reversed_(reversed) { + set_comment("[ DeferredInlinedSmiOperation"); + } + + virtual void Generate() { + switch (op_) { + case Token::ADD: { + if (reversed_) { + // revert optimistic add + __ sub(r0, r0, Operand(Smi::FromInt(value_))); + __ mov(r1, Operand(Smi::FromInt(value_))); // x + } else { + // revert optimistic add + __ sub(r1, r0, Operand(Smi::FromInt(value_))); + __ mov(r0, Operand(Smi::FromInt(value_))); + } + break; + } + + case Token::SUB: { + if (reversed_) { + // revert optimistic sub + __ rsb(r0, r0, Operand(Smi::FromInt(value_))); + __ mov(r1, Operand(Smi::FromInt(value_))); + } else { + __ add(r1, r0, Operand(Smi::FromInt(value_))); + __ mov(r0, Operand(Smi::FromInt(value_))); + } + break; + } + + case Token::BIT_OR: + case Token::BIT_XOR: + case Token::BIT_AND: { + if (reversed_) { + __ mov(r1, Operand(Smi::FromInt(value_))); + } else { + __ mov(r1, Operand(r0)); + __ mov(r0, Operand(Smi::FromInt(value_))); + } + break; + } + + case Token::SHL: + case Token::SHR: + case Token::SAR: { + if (!reversed_) { + __ mov(r1, Operand(r0)); + __ mov(r0, Operand(Smi::FromInt(value_))); + } else { + UNREACHABLE(); // should have been handled in SmiOperation + } + break; + } + + default: + // other cases should have been handled before this point. + UNREACHABLE(); + break; + } + + GenericBinaryOpStub igostub(op_); + __ CallStub(&igostub); + } + + private: + Token::Value op_; + int value_; + bool reversed_; +}; + + void ArmCodeGenerator::SmiOperation(Token::Value op, Handle value, bool reversed) { @@ -2007,45 +2029,108 @@ void ArmCodeGenerator::SmiOperation(Token::Value op, // sp[0] : operand - ASSERT(value->IsSmi()); + int int_value = Smi::cast(*value)->value(); Label exit; __ pop(r0); switch (op) { case Token::ADD: { - Label slow; + DeferredCode* deferred = + new DeferredInlinedSmiOperation(this, op, int_value, reversed); - __ mov(r1, Operand(value)); - __ add(r0, r0, Operand(r1), SetCC); - __ b(vs, &slow); + __ add(r0, r0, Operand(value), SetCC); + __ b(vs, deferred->enter()); __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &exit); - __ bind(&slow); - - SmiOpStub stub(Token::ADD, reversed); - __ CallStub(&stub); + __ b(ne, deferred->enter()); + __ bind(deferred->exit()); break; } case Token::SUB: { - Label slow; + DeferredCode* deferred = + new DeferredInlinedSmiOperation(this, op, int_value, reversed); - __ mov(r1, Operand(value)); if (!reversed) { - __ sub(r2, r0, Operand(r1), SetCC); + __ sub(r0, r0, Operand(value), SetCC); } else { - __ rsb(r2, r0, Operand(r1), SetCC); + __ rsb(r0, r0, Operand(value), SetCC); } - __ b(vs, &slow); - __ tst(r2, Operand(kSmiTagMask)); - __ mov(r0, Operand(r2), LeaveCC, eq); // conditionally set r0 to result - __ b(eq, &exit); + __ b(vs, deferred->enter()); + __ tst(r0, Operand(kSmiTagMask)); + __ b(ne, deferred->enter()); + __ bind(deferred->exit()); + break; + } - __ bind(&slow); + case Token::BIT_OR: + case Token::BIT_XOR: + case Token::BIT_AND: { + DeferredCode* deferred = + new DeferredInlinedSmiOperation(this, op, int_value, reversed); + __ tst(r0, Operand(kSmiTagMask)); + __ b(ne, deferred->enter()); + switch (op) { + case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break; + case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break; + case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break; + default: UNREACHABLE(); + } + __ bind(deferred->exit()); + break; + } - SmiOpStub stub(Token::SUB, reversed); - __ CallStub(&stub); + case Token::SHL: + case Token::SHR: + case Token::SAR: { + if (reversed) { + __ mov(ip, Operand(value)); + __ push(ip); + __ push(r0); + GenericBinaryOperation(op); + + } else { + int shift_value = int_value & 0x1f; // least significant 5 bits + DeferredCode* deferred = + new DeferredInlinedSmiOperation(this, op, shift_value, false); + __ tst(r0, Operand(kSmiTagMask)); + __ b(ne, deferred->enter()); + __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags + switch (op) { + case Token::SHL: { + __ mov(r2, Operand(r2, LSL, shift_value)); + // check that the *unsigned* result fits in a smi + __ add(r3, r2, Operand(0x40000000), SetCC); + __ b(mi, deferred->enter()); + break; + } + case Token::SHR: { + // LSR by immediate 0 means shifting 32 bits. + if (shift_value != 0) { + __ mov(r2, Operand(r2, LSR, shift_value)); + } + // check that the *unsigned* result fits in a smi + // neither of the two high-order bits can be set: + // - 0x80000000: high bit would be lost when smi tagging + // - 0x40000000: this number would convert to negative when + // smi tagging these two cases can only happen with shifts + // by 0 or 1 when handed a valid smi + __ and_(r3, r2, Operand(0xc0000000), SetCC); + __ b(ne, deferred->enter()); + break; + } + case Token::SAR: { + if (shift_value != 0) { + // ASR by immediate 0 means shifting 32 bits. + __ mov(r2, Operand(r2, ASR, shift_value)); + } + break; + } + default: UNREACHABLE(); + } + __ mov(r0, Operand(r2, LSL, kSmiTagSize)); + __ bind(deferred->exit()); + } break; } diff --git a/src/factory.cc b/src/factory.cc index 3bbf53c..78c56ca 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -555,8 +555,7 @@ Handle Factory::NewJSObject(Handle constructor, Handle Factory::NewObjectLiteral(int expected_number_of_properties) { Handle map = Handle(Top::object_function()->initial_map()); map = Factory::CopyMap(map); - map->set_instance_descriptors( - DescriptorArray::cast(Heap::empty_fixed_array())); + map->set_instance_descriptors(Heap::empty_descriptor_array()); map->set_unused_property_fields(expected_number_of_properties); CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, TENURED), JSObject); @@ -704,7 +703,7 @@ Handle Factory::CreateApiFunction( if (parent->IsUndefined()) break; obj = Handle::cast(parent); } - if (array->length() > 0) { + if (!array->IsEmpty()) { map->set_instance_descriptors(*array); } diff --git a/src/factory.h b/src/factory.h index 883a9c5..432f9ca 100644 --- a/src/factory.h +++ b/src/factory.h @@ -281,10 +281,6 @@ class Factory : public AllStatic { SYMBOL_LIST(SYMBOL_ACCESSOR) #undef SYMBOL_ACCESSOR - static Handle empty_descriptor_array() { - return Handle::cast(empty_fixed_array()); - } - static Handle NewSharedFunctionInfo(Handle name); static Handle DictionaryAtNumberPut(Handle, diff --git a/src/flags.cc b/src/flags.cc index cb5e08d..2431460 100644 --- a/src/flags.cc +++ b/src/flags.cc @@ -301,8 +301,16 @@ int FlagList::SetFlagsFromCommandLine(int* argc, // lookup the flag Flag* flag = Lookup(name); if (flag == NULL) { - fprintf(stderr, "Error: unrecognized flag %s\n", arg); - return j; + if (remove_flags) { + // We don't recognize this flag but since we're removing + // the flags we recognize we assume that the remaining flags + // will be processed somewhere else so this flag might make + // sense there. + continue; + } else { + fprintf(stderr, "Error: unrecognized flag %s\n", arg); + return j; + } } // if we still need a flag value, use the next argument if available diff --git a/src/globals.h b/src/globals.h index 095288d..5f7d557 100644 --- a/src/globals.h +++ b/src/globals.h @@ -304,7 +304,8 @@ enum PropertyType { FIELD = 3, // only in fast mode CALLBACKS = 4, CONSTANT_TRANSITION = 5, // only in fast mode - INTERCEPTOR = 6 + INTERCEPTOR = 6, + NULL_DESCRIPTOR = 7 // only in fast mode }; diff --git a/src/heap-inl.h b/src/heap-inl.h index 49460cc..22ef441 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -160,14 +160,6 @@ void Heap::RecordWrite(Address address, int offset) { } -Object* Heap::AllocatePropertyStorageForMap(Map* map) { - if (map->unused_property_fields() > 0) { - return AllocateFixedArray(map->unused_property_fields()); - } - return Heap::empty_fixed_array(); -} - - AllocationSpace Heap::TargetSpace(HeapObject* object) { // Heap numbers and sequential strings are promoted to code space, all // other object types are promoted to old space. We do not use diff --git a/src/heap.cc b/src/heap.cc index a7e71a7..d81c612 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -861,7 +861,7 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) { map->set_prototype(null_value()); map->set_constructor(null_value()); map->set_instance_size(instance_size); - map->set_instance_descriptors(DescriptorArray::cast(empty_fixed_array())); + map->set_instance_descriptors(empty_descriptor_array()); map->set_code_cache(empty_fixed_array()); map->set_unused_property_fields(0); map->set_bit_field(0); @@ -894,17 +894,20 @@ bool Heap::CreateInitialMaps() { if (obj->IsFailure()) return false; null_value_ = obj; - // Fix the instance_descriptors for the existing maps. - DescriptorArray* empty_descriptors = - DescriptorArray::cast(empty_fixed_array()); + // Allocate the empty descriptor array. AllocateMap can now be used. + obj = AllocateEmptyFixedArray(); + if (obj->IsFailure()) return false; + // There is a check against empty_descriptor_array() in cast(). + empty_descriptor_array_ = reinterpret_cast(obj); - meta_map()->set_instance_descriptors(empty_descriptors); + // Fix the instance_descriptors for the existing maps. + meta_map()->set_instance_descriptors(empty_descriptor_array()); meta_map()->set_code_cache(empty_fixed_array()); - fixed_array_map()->set_instance_descriptors(empty_descriptors); + fixed_array_map()->set_instance_descriptors(empty_descriptor_array()); fixed_array_map()->set_code_cache(empty_fixed_array()); - oddball_map()->set_instance_descriptors(empty_descriptors); + oddball_map()->set_instance_descriptors(empty_descriptor_array()); oddball_map()->set_code_cache(empty_fixed_array()); // Fix prototype object for existing maps. @@ -1004,6 +1007,7 @@ bool Heap::CreateInitialMaps() { if (obj->IsFailure()) return false; shared_function_info_map_ = Map::cast(obj); + ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); return true; } @@ -1701,7 +1705,7 @@ Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { ASSERT(map->instance_type() != JS_FUNCTION_TYPE); // Allocate the backing storage for the properties. - Object* properties = AllocatePropertyStorageForMap(map); + Object* properties = AllocateFixedArray(map->unused_property_fields()); if (properties->IsFailure()) return properties; // Allocate the JSObject. @@ -1749,7 +1753,7 @@ Object* Heap::ReinitializeJSGlobalObject(JSFunction* constructor, ASSERT(map->instance_size() == object->map()->instance_size()); // Allocate the backing storage for the properties. - Object* properties = AllocatePropertyStorageForMap(map); + Object* properties = AllocateFixedArray(map->unused_property_fields()); if (properties->IsFailure()) return properties; // Reset the map for the object. diff --git a/src/heap.h b/src/heap.h index cd2fb2a..24d08f5 100644 --- a/src/heap.h +++ b/src/heap.h @@ -112,6 +112,7 @@ namespace v8 { namespace internal { V(Object, false_value) \ V(String, empty_string) \ V(FixedArray, empty_fixed_array) \ + V(DescriptorArray, empty_descriptor_array) \ V(Object, the_hole_value) \ V(Map, neander_map) \ V(JSObject, message_listeners) \ @@ -811,10 +812,6 @@ class Heap : public AllStatic { // inlined). static inline Object* AllocateRawMap(int size_in_bytes); - // Allocate storage for JSObject properties. - // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation - // failed. - static inline Object* AllocatePropertyStorageForMap(Map* map); // Initializes a JSObject based on its map. static void InitializeJSObjectFromMap(JSObject* obj, diff --git a/src/objects-debug.cc b/src/objects-debug.cc index d12b7d3..00b086e 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -133,6 +133,7 @@ void HeapObject::HeapObjectPrint() { JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(); break; case JS_VALUE_TYPE: + PrintF("Value wrapper around:"); JSValue::cast(this)->value()->Print(); break; case CODE_TYPE: diff --git a/src/objects-inl.h b/src/objects-inl.h index ed84ce4..f7978ae 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -979,6 +979,13 @@ void FixedArray::set_the_hole(int index) { } +bool DescriptorArray::IsEmpty() { + ASSERT(this == Heap::empty_descriptor_array() || + this->length() > 2); + return this == Heap::empty_descriptor_array(); +} + + void DescriptorArray::fast_swap(FixedArray* array, int first, int second) { Object* tmp = array->get(first); fast_set(array, first, array->get(second)); diff --git a/src/objects.cc b/src/objects.cc index 1704c05..a1624a5 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1030,8 +1030,7 @@ Object* JSObject::AddFastProperty(String* name, } else { ASSERT(map()->unused_property_fields() == 0); - static const int kFastNofProperties = 8; - if (properties()->length() > kFastNofProperties) { + if (properties()->length() > kMaxFastProperties) { Object* obj = NormalizeProperties(); if (obj->IsFailure()) return obj; return AddSlowProperty(name, value, attributes); @@ -1553,6 +1552,8 @@ Object* JSObject::SetProperty(LookupResult* result, // if the value is a function. // AddProperty has been extended to do this, in this case. return AddFastProperty(name, value, attributes); + case NULL_DESCRIPTOR: + UNREACHABLE(); default: UNREACHABLE(); } @@ -1612,6 +1613,8 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(String* name, case INTERCEPTOR: return SetPropertyWithInterceptor(name, value, NONE); case CONSTANT_TRANSITION: + case NULL_DESCRIPTOR: + UNREACHABLE(); break; } } @@ -1727,7 +1730,12 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver, case INTERCEPTOR: return result->holder()-> GetPropertyAttributeWithInterceptor(receiver, name, continue_search); + case MAP_TRANSITION: + case CONSTANT_TRANSITION: + case NULL_DESCRIPTOR: + return ABSENT; default: + UNREACHABLE(); break; } } @@ -1790,8 +1798,14 @@ Object* JSObject::NormalizeProperties() { dictionary = Dictionary::cast(result); break; } + case MAP_TRANSITION: + case CONSTANT_TRANSITION: + case NULL_DESCRIPTOR: + case INTERCEPTOR: + break; default: - ASSERT(details.IsTransition()); + case NORMAL: + UNREACHABLE(); break; } } @@ -1800,17 +1814,15 @@ Object* JSObject::NormalizeProperties() { int index = map()->instance_descriptors()->NextEnumerationIndex(); dictionary->SetNextEnumerationIndex(index); - // Descriptors with type MAP_TRANSITION is ignored. - // Allocate new map. obj = map()->Copy(); if (obj->IsFailure()) return obj; + // We have now sucessfully allocated all the necessary objects. + // Changes can now be made with the guarantee that all of them take effect. set_map(Map::cast(obj)); - map()-> - set_instance_descriptors(DescriptorArray::cast(Heap::empty_fixed_array())); + map()->set_instance_descriptors(Heap::empty_descriptor_array()); - // We have now allocate all the necessary object and change can be applied. map()->set_unused_property_fields(0); set_properties(dictionary); @@ -2569,20 +2581,33 @@ void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) { } +#ifdef DEBUG +bool FixedArray::IsEqualTo(FixedArray* other) { + if (length() != other->length()) return false; + for (int i = 0 ; i < length(); ++i) { + if (get(i) != other->get(i)) return false; + } + return true; +} +#endif + + Object* DescriptorArray::Allocate(int number_of_descriptors) { - // Allocate the descriptor array. + if (number_of_descriptors == 0) { + return Heap::empty_descriptor_array(); + } + // Allocate the array of keys. Object* array = Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors)); if (array->IsFailure()) return array; - DescriptorArray* result = DescriptorArray::cast(array); + // Do not use DescriptorArray::cast on incomplete object. + FixedArray* result = FixedArray::cast(array); // Allocate the content array and set it in the descriptor array. array = Heap::AllocateFixedArray(number_of_descriptors << 1); if (array->IsFailure()) return array; result->set(kContentArrayIndex, array); - - // Initialize the next enumeration index. - result->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); - + result->set(kEnumerationIndexIndex, + Smi::FromInt(PropertyDetails::kInitialIndex)); return result; } @@ -2594,7 +2619,7 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, FixedArray::cast(get(kEnumerationIndexIndex))-> set(kEnumCacheBridgeCacheIndex, new_cache); } else { - if (length() == 0) return; // Do nothing for empty descriptor array. + if (IsEmpty()) return; // Do nothing for empty descriptor array. FixedArray::cast(bridge_storage)-> set(kEnumCacheBridgeCacheIndex, new_cache); fast_set(FixedArray::cast(bridge_storage), @@ -2706,7 +2731,6 @@ Object* DescriptorArray::CopyRemove(String* name) { // Set the enumeration index in the descriptors and set the enumeration index // in the result. new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); - // Write the old content and the descriptor information DescriptorWriter w(new_descriptors); DescriptorReader r(this); @@ -2801,6 +2825,19 @@ int DescriptorArray::BinarySearch(String* name, int low, int high) { } +#ifdef DEBUG +bool DescriptorArray::IsEqualTo(DescriptorArray* other) { + if (IsEmpty()) return other->IsEmpty(); + if (other->IsEmpty()) return false; + if (length() != other->length()) return false; + for (int i = 0; i < length(); ++i) { + if (get(i) != other->get(i) && i != kContentArrayIndex) return false; + } + return GetContentArray()->IsEqualTo(other->GetContentArray()); +} +#endif + + static StaticResource string_input_buffer; @@ -3775,7 +3812,8 @@ Object* JSFunction::SetPrototype(Object* value) { map()->set_constructor(value); map()->set_non_instance_prototype(true); - construct_prototype = *Top::initial_object_prototype(); + construct_prototype = + Top::context()->global_context()->initial_object_prototype(); } else { map()->set_non_instance_prototype(false); } @@ -4210,8 +4248,8 @@ Object* JSObject::SetElementsLength(Object* len) { } int min = NewElementsCapacity(old_capacity); int new_capacity = value > min ? value : min; - if (KeepInFastCase(new_capacity) || - new_capacity <= kMaxFastElementsLength) { + if (new_capacity <= kMaxFastElementsLength || + !ShouldConvertToSlowElements(new_capacity)) { Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); if (obj->IsFailure()) return obj; if (IsJSArray()) JSArray::cast(this)->set_length(smi_length); @@ -4463,8 +4501,8 @@ Object* JSObject::SetFastElement(uint32_t index, Object* value) { if ((index - elms_length) < kMaxGap) { // Try allocating extra space. int new_capacity = NewElementsCapacity(index+1); - if (KeepInFastCase(new_capacity) || - new_capacity <= kMaxFastElementsLength) { + if (new_capacity <= kMaxFastElementsLength || + !ShouldConvertToSlowElements(new_capacity)) { ASSERT(static_cast(new_capacity) > index); Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); if (obj->IsFailure()) return obj; @@ -4519,7 +4557,7 @@ Object* JSObject::SetElement(uint32_t index, Object* value) { } // Attempt to put this object back in fast case. - if (ShouldHaveFastElements()) { + if (ShouldConvertToFastElements()) { uint32_t new_length = 0; if (IsJSArray()) { CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length)); @@ -4671,17 +4709,17 @@ bool JSObject::HasDenseElements() { } -bool JSObject::KeepInFastCase(int new_capacity) { +bool JSObject::ShouldConvertToSlowElements(int new_capacity) { ASSERT(HasFastElements()); // Keep the array in fast case if the current backing storage is // almost filled and if the new capacity is no more than twice the // old capacity. int elements_length = FixedArray::cast(elements())->length(); - return HasDenseElements() && ((new_capacity / 2) <= elements_length); + return !HasDenseElements() || ((new_capacity / 2) > elements_length); } -bool JSObject::ShouldHaveFastElements() { +bool JSObject::ShouldConvertToFastElements() { ASSERT(!HasFastElements()); Dictionary* dictionary = Dictionary::cast(elements()); // If the elements are sparse, we should not go back to fast case. @@ -4864,8 +4902,15 @@ bool JSObject::HasRealNamedProperty(String* key) { case NORMAL: // fall through. case FIELD: // fall through. case CALLBACKS: // fall through. - case CONSTANT_FUNCTION: return true; - default: return false; + case CONSTANT_FUNCTION: + return true; + case INTERCEPTOR: + case MAP_TRANSITION: + case CONSTANT_TRANSITION: + case NULL_DESCRIPTOR: + return false; + default: + UNREACHABLE(); } } @@ -5099,8 +5144,9 @@ int JSObject::GetLocalElementKeys(FixedArray* storage, } ASSERT(!storage || storage->length() >= counter); } else { - if (storage) + if (storage) { element_dictionary()->CopyKeysTo(storage, filter); + } counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); } @@ -5506,7 +5552,7 @@ Object* Dictionary::GenerateNewEnumerationIndices() { Object* Dictionary::EnsureCapacity(int n, Key* key) { - // Check whether there is enough enumeration indices for adding n elements. + // Check whether there are enough enumeration indices to add n elements. if (key->IsStringKey() && !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) { // If not, we generate new indices for the properties. @@ -5793,9 +5839,10 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, } // Allocate the instance descriptor. - Object* instance_descriptors = + Object* descriptors_unchecked = DescriptorArray::Allocate(instance_descriptor_length); - if (instance_descriptors->IsFailure()) return instance_descriptors; + if (descriptors_unchecked->IsFailure()) return descriptors_unchecked; + DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked); int number_of_allocated_fields = number_of_fields + unused_property_fields; @@ -5804,7 +5851,7 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, if (fields->IsFailure()) return fields; // Fill in the instance descriptor and the fields. - DescriptorWriter w(DescriptorArray::cast(instance_descriptors)); + DescriptorWriter w(descriptors); int current_offset = 0; for (int i = 0; i < capacity; i++) { Object* k = KeyAt(i); @@ -5841,25 +5888,20 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj, } ASSERT(current_offset == number_of_fields); - // Sort the instance descriptors. - DescriptorArray::cast(instance_descriptors)->Sort(); - + descriptors->Sort(); // Allocate new map. Object* new_map = obj->map()->Copy(); if (new_map->IsFailure()) return new_map; // Transform the object. - Map::cast(new_map)-> - set_instance_descriptors(DescriptorArray::cast(instance_descriptors)); - Map::cast(new_map)->set_unused_property_fields(unused_property_fields); obj->set_map(Map::cast(new_map)); + obj->map()->set_instance_descriptors(descriptors); + obj->map()->set_unused_property_fields(unused_property_fields); + obj->set_properties(FixedArray::cast(fields)); ASSERT(obj->IsJSObject()); - // Transfer next enumeration index from dictionary to instance descriptors. - DescriptorArray::cast(instance_descriptors)-> - SetNextEnumerationIndex(NextEnumerationIndex()); - + descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); // Check it really works. ASSERT(obj->HasFastProperties()); return obj; diff --git a/src/objects.h b/src/objects.h index 8ad0930..e61a4f9 100644 --- a/src/objects.h +++ b/src/objects.h @@ -52,6 +52,7 @@ // - Array // - ByteArray // - FixedArray +// - DescriptorArray // - HashTable // - Dictionary // - SymbolTable @@ -135,8 +136,7 @@ class PropertyDetails BASE_EMBEDDED { bool IsTransition() { PropertyType t = type(); ASSERT(t != INTERCEPTOR); - if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true; - return false; + return t == MAP_TRANSITION || t == CONSTANT_TRANSITION; } PropertyAttributes attributes() { return AttributesField::decode(value_); } @@ -1095,23 +1095,20 @@ class HeapNumber: public HeapObject { class JSObject: public HeapObject { public: // [properties]: Backing storage for properties. - DECL_ACCESSORS(properties, FixedArray) + // properties is a FixedArray in the fast case, and a Dictionary in the + // slow case. + DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties. inline void initialize_properties(); - - // [elements]: The elements in the fast case. - DECL_ACCESSORS(elements, HeapObject) - inline void initialize_elements(); - - // Accessors for properties. inline bool HasFastProperties(); + inline Dictionary* property_dictionary(); // Gets slow properties. - // Do we want to keep the elements in fast case when increasing the - // capacity? - bool KeepInFastCase(int new_capacity); - - // Accessors for slow properties - inline Dictionary* property_dictionary(); // asserts !HasFastProperties - inline Dictionary* element_dictionary(); // asserts !HasFastElements + // [elements]: The elements (properties with names that are integers). + // elements is a FixedArray in the fast case, and a Dictionary in the slow + // case. + DECL_ACCESSORS(elements, HeapObject) // Get and set fast elements. + inline void initialize_elements(); + inline bool HasFastElements(); + inline Dictionary* element_dictionary(); // Gets slow elements. Object* SetProperty(String* key, Object* value, @@ -1188,14 +1185,14 @@ class JSObject: public HeapObject { // Tests for the fast common case for property enumeration. bool IsSimpleEnum(); - // Tells whether the backing storage for elements is fast (FixedArray). - inline bool HasFastElements(); - + // Do we want to keep the elements in fast case when increasing the + // capacity? + bool ShouldConvertToSlowElements(int new_capacity); // Returns true if the backing storage for the slow-case elements of // this object takes up nearly as much space as a fast-case backing // storage would. In that case the JSObject should have fast // elements. - bool ShouldHaveFastElements(); + bool ShouldConvertToFastElements(); // Return the object's prototype (might be Heap::null_value()). inline Object* GetPrototype(); @@ -1370,6 +1367,7 @@ class JSObject: public HeapObject { static const uint32_t kMaxGap = 1024; static const int kMaxFastElementsLength = 5000; + static const int kMaxFastProperties = 8; // Layout description. static const int kPropertiesOffset = HeapObject::kSize; @@ -1477,6 +1475,8 @@ class FixedArray: public Array { #ifdef DEBUG void FixedArrayPrint(); void FixedArrayVerify(); + // Checks if two FixedArrays have identical contents. + bool IsEqualTo(FixedArray* other); #endif // Swap two elements. @@ -1505,14 +1505,15 @@ class FixedArray: public Array { // class DescriptorArray: public FixedArray { public: + // Is this the singleton empty_descriptor_array? + inline bool IsEmpty(); // Returns the number of descriptors in the array. int number_of_descriptors() { - int len = length(); - return len == 0 ? 0 : len - kFirstIndex; + return IsEmpty() ? 0 : length() - kFirstIndex; } int NextEnumerationIndex() { - if (length() == 0) return PropertyDetails::kInitialIndex; + if (IsEmpty()) return PropertyDetails::kInitialIndex; Object* obj = get(kEnumerationIndexIndex); if (obj->IsSmi()) { return Smi::cast(obj)->value(); @@ -1524,11 +1525,12 @@ class DescriptorArray: public FixedArray { // Set next enumeration index and flush any enum cache. void SetNextEnumerationIndex(int value) { - fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value)); + if (!IsEmpty()) { + fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value)); + } } - bool HasEnumCache() { - return length() > 0 && !get(kEnumerationIndexIndex)->IsSmi(); + return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi(); } Object* GetEnumCache() { @@ -1579,6 +1581,9 @@ class DescriptorArray: public FixedArray { // with low=0 and high=2. int BinarySearch(String* name, int low, int high); + + // Allocates a DescriptorArray, but returns the singleton + // empty descriptor array object if number_of_descriptors is 0. static Object* Allocate(int number_of_descriptors); // Casting. @@ -1612,6 +1617,9 @@ class DescriptorArray: public FixedArray { // Is the descriptor array sorted and without duplicates? bool IsSortedNoDuplicates(); + + // Are two DescriptorArrays equal? + bool IsEqualTo(DescriptorArray* other); #endif // The maximum number of descriptors we want in a descriptor array (should diff --git a/src/parser.cc b/src/parser.cc index b48f568..042af9f 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -2726,9 +2726,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { int literal_index = temp_scope_->NextMaterializedLiteralIndex(); if (is_pre_parsing_) return NULL; - Handle constant_properties = (number_of_constant_properties == 0) - ? Factory::empty_fixed_array() - : Factory::NewFixedArray(number_of_constant_properties*2, TENURED); + Handle constant_properties = + Factory::NewFixedArray(number_of_constant_properties * 2, TENURED); int position = 0; for (int i = 0; i < properties.length(); i++) { ObjectLiteral::Property* property = properties.at(i); diff --git a/src/property.cc b/src/property.cc index 7cbe2c5..7546195 100644 --- a/src/property.cc +++ b/src/property.cc @@ -87,6 +87,9 @@ void LookupResult::Print() { case CONSTANT_TRANSITION: PrintF(" -type = constant property transition\n"); break; + case NULL_DESCRIPTOR: + PrintF(" =type = null descriptor\n"); + break; } } diff --git a/src/property.h b/src/property.h index 3cb2752..5fd2323 100644 --- a/src/property.h +++ b/src/property.h @@ -348,8 +348,11 @@ class DescriptorReader: public DescriptorStream { bool IsTransition() { PropertyType t = type(); ASSERT(t != INTERCEPTOR); - if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true; - return false; + return t == MAP_TRANSITION || t == CONSTANT_TRANSITION; + } + + bool IsNullDescriptor() { + return type() == NULL_DESCRIPTOR; } JSFunction* GetConstantFunction() { return JSFunction::cast(GetValue()); } diff --git a/src/runtime.cc b/src/runtime.cc index f61273e..b4a8b3b 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -247,8 +247,7 @@ static Object* Runtime_CreateApiFunction(Arguments args) { static Object* Runtime_IsTemplate(Arguments args) { ASSERT(args.length() == 1); Object* arg = args[0]; - bool result = arg->IsObjectTemplateInfo() - || arg->IsFunctionTemplateInfo(); + bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); return Heap::ToBoolean(result); } @@ -794,11 +793,12 @@ static Object* Runtime_FunctionSetLength(Arguments args) { static Object* Runtime_FunctionSetPrototype(Arguments args) { - HandleScope scope; + NoHandleAllocation ha; ASSERT(args.length() == 2); CONVERT_CHECKED(JSFunction, fun, args[0]); - Accessors::FunctionSetPrototype(fun, args[1], NULL); + Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL); + if (obj->IsFailure()) return obj; return args[0]; // return TOS } @@ -858,14 +858,12 @@ static Object* Runtime_SetCode(Arguments args) { static Object* CharCodeAt(String* subject, Object* index) { uint32_t i = 0; - if (!Array::IndexFromObject(index, &i)) - return Heap::nan_value(); + if (!Array::IndexFromObject(index, &i)) return Heap::nan_value(); // Flatten the string. If someone wants to get a char at an index // in a cons string, it is likely that more indices will be // accessed. subject->TryFlatten(); - if (i >= static_cast(subject->length())) - return Heap::nan_value(); + if (i >= static_cast(subject->length())) return Heap::nan_value(); return Smi::FromInt(subject->Get(i)); } @@ -1315,12 +1313,13 @@ Object* Runtime::SetObjectProperty(Handle object, return *value; } + HandleScope scope; + // Handlify object and value before calling into JavaScript again. Handle object_handle = Handle::cast(object); Handle value_handle = value; // Call-back into JavaScript to convert the key to a string. - HandleScope scope; bool has_pending_exception = false; Handle converted = Execution::ToString(key, &has_pending_exception); if (has_pending_exception) return Failure::Exception(); @@ -1562,8 +1561,7 @@ static Object* Runtime_Typeof(Arguments args) { HeapObject* heap_obj = HeapObject::cast(obj); // typeof an undetectable object is 'undefined' - if (heap_obj->map()->is_undetectable()) - return Heap::undefined_symbol(); + if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol(); InstanceType instance_type = heap_obj->map()->instance_type(); if (instance_type < FIRST_NONSTRING_TYPE) { @@ -1888,7 +1886,7 @@ static unibrow::Mapping to_lower_mapping; template static Object* ConvertCase(Arguments args, - unibrow::Mapping *mapping) { + unibrow::Mapping* mapping) { NoHandleAllocation ha; CONVERT_CHECKED(String, s, args[0]); @@ -1916,12 +1914,10 @@ static Object* ConvertCase(Arguments args, Object* o = s->IsAscii() ? Heap::AllocateRawAsciiString(length) : Heap::AllocateRawTwoByteString(length); - if (o->IsFailure()) - return o; + if (o->IsFailure()) return o; String* result = String::cast(o); bool has_changed_character = false; - // Convert all characters to upper case, assuming that they will fit // in the buffer Access buffer(&string_input_buffer); @@ -2047,10 +2043,7 @@ static Object* Runtime_NumberToInteger(Arguments args) { ASSERT(args.length() == 1); Object* obj = args[0]; - - if (obj->IsSmi()) - return obj; - + if (obj->IsSmi()) return obj; CONVERT_DOUBLE_CHECKED(number, obj); return Heap::NumberFromDouble(DoubleToInteger(number)); } @@ -2184,8 +2177,9 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { return Top::Throw(Heap::illegal_argument_symbol()); } FixedArray* fixed_array = FixedArray::cast(array->elements()); - if (fixed_array->length() < array_length) + if (fixed_array->length() < array_length) { array_length = fixed_array->length(); + } if (array_length == 0) { return Heap::empty_string(); @@ -2214,8 +2208,9 @@ static Object* Runtime_StringBuilderConcat(Arguments args) { return Failure::OutOfMemoryException(); } position += element_length; - if (ascii && !element->IsAscii()) + if (ascii && !element->IsAscii()) { ascii = false; + } } else { return Top::Throw(Heap::illegal_argument_symbol()); } @@ -2408,17 +2403,15 @@ static Object* Runtime_StringCompare(Arguments args) { // A few fast case tests before we flatten. if (x == y) return Smi::FromInt(EQUAL); if (y->length() == 0) { - if (x->length() == 0) - return Smi::FromInt(EQUAL); + if (x->length() == 0) return Smi::FromInt(EQUAL); return Smi::FromInt(GREATER); } else if (x->length() == 0) { return Smi::FromInt(LESS); } - { - int d = x->Get(0) - y->Get(0); - if (d < 0) return Smi::FromInt(LESS); - else if (d > 0) return Smi::FromInt(GREATER); - } + + int d = x->Get(0) - y->Get(0); + if (d < 0) return Smi::FromInt(LESS); + else if (d > 0) return Smi::FromInt(GREATER); x->TryFlatten(); y->TryFlatten(); @@ -2821,8 +2814,6 @@ static Object* Runtime_LookupContext(Arguments args) { } - - // A mechanism to return pairs of Object*'s. This is somewhat // compiler-dependent as it assumes that a 64-bit value (a long long) // is returned via two registers (edx:eax on ia32). Both the ia32 and @@ -2888,7 +2879,7 @@ static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) { if (throw_error) { // The property doesn't exist - throw exception. Handle reference_error = - Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); + Factory::NewReferenceError("not_defined", HandleVector(&name, 1)); return MakePair(Top::Throw(*reference_error), NULL); } else { // The property doesn't exist - return undefined @@ -2913,7 +2904,7 @@ static Object* Runtime_StoreContextSlot(Arguments args) { Handle value(args[0]); CONVERT_ARG_CHECKED(Context, context, 1); - Handle name(String::cast(args[2])); + CONVERT_ARG_CHECKED(String, name, 2); int index; PropertyAttributes attributes; @@ -3473,8 +3464,7 @@ static Object* Runtime_GetArrayKeys(Arguments args) { CONVERT_CHECKED(JSArray, raw_array, args[0]); Handle array(raw_array); CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); - HeapObject* elements = array->elements(); - if (elements->IsDictionary()) { + if (array->elements()->IsDictionary()) { // Create an array and get all the keys into it, then remove all the // keys that are not integers in the range 0 to length-1. Handle keys = GetKeysInFixedArrayFor(array); @@ -3606,14 +3596,15 @@ static Object* DebugLookupResultValue(LookupResult* result) { case CONSTANT_FUNCTION: return result->GetConstantFunction(); case CALLBACKS: - return Heap::undefined_value(); - case MAP_TRANSITION: - return Heap::undefined_value(); case INTERCEPTOR: + case MAP_TRANSITION: + case CONSTANT_TRANSITION: + case NULL_DESCRIPTOR: return Heap::undefined_value(); default: UNREACHABLE(); } + UNREACHABLE(); return Heap::undefined_value(); } @@ -3788,8 +3779,7 @@ static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) { CONVERT_ARG_CHECKED(String, name, 1); PropertyAttributes attributes; - Object* result = obj->GetPropertyWithInterceptor(*obj, *name, &attributes); - return result; + return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); } @@ -3803,8 +3793,7 @@ static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) { RUNTIME_ASSERT(obj->HasIndexedInterceptor()); CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); - Object* result = obj->GetElementWithInterceptor(*obj, index); - return result; + return obj->GetElementWithInterceptor(*obj, index); } @@ -3868,8 +3857,8 @@ static Object* Runtime_GetFrameDetails(Arguments args) { ASSERT(args.length() == 2); // Check arguments. - Object* result = Runtime_CheckExecutionState(args); - if (result->IsFailure()) return result; + Object* check = Runtime_CheckExecutionState(args); + if (check->IsFailure()) return check; CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); // Find the relevant frame with the requested index. @@ -4258,8 +4247,8 @@ static Object* Runtime_PrepareStep(Arguments args) { HandleScope scope; ASSERT(args.length() == 3); // Check arguments. - Object* check_result = Runtime_CheckExecutionState(args); - if (check_result->IsFailure()) return check_result; + Object* check = Runtime_CheckExecutionState(args); + if (check->IsFailure()) return check; if (!args[1]->IsNumber() || !args[2]->IsNumber()) { return Top::Throw(Heap::illegal_argument_symbol()); } diff --git a/src/v8natives.js b/src/v8natives.js index 3755f74..d97345e 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -212,7 +212,8 @@ $Object.prototype.constructor = $Object; %AddProperty(global, "execScript", function(expr, lang) { // NOTE: We don't care about the character casing. if (!lang || /javascript/i.test(lang)) { - %CompileString(ToString(expr), false)(); + var f = %CompileString(ToString(expr), false); + f.call(global); } return null; }, DONT_ENUM); diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc index 53604f4..eef295f 100644 --- a/test/cctest/cctest.cc +++ b/test/cctest/cctest.cc @@ -25,17 +25,18 @@ // (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 #include #include #include #include "cctest.h" -CcTest* CcTest::first_ = NULL; +CcTest* CcTest::last_ = NULL; CcTest::CcTest(TestFunction* callback, const char* file, const char* name) - : callback_(callback), name_(name), prev_(first_) { + : callback_(callback), name_(name), prev_(last_) { // Find the base name of this test (const_cast required on Windows). char *basename = strrchr(const_cast(file), '/'); if (!basename) { @@ -51,15 +52,67 @@ CcTest::CcTest(TestFunction* callback, const char* file, const char* name) if (extension) *extension = 0; // Install this test in the list of tests file_ = basename; - prev_ = first_; - first_ = this; + prev_ = last_; + last_ = this; } -int main(int argc, char *argv[]) { - CcTest* current = CcTest::first(); - while (current != NULL) { - printf("%s/%s\n", current->file(), current->name()); - current = current->prev(); +static void PrintTestList(CcTest* current) { + if (current == NULL) return; + PrintTestList(current->prev()); + printf("%s/%s\n", current->file(), current->name()); +} + + +static int RunMatchingTests(CcTest* current, char* file_or_name) { + if (current == NULL) return 0; + int run_count = 0; + if (strcmp(current->file(), file_or_name) == 0 + || strcmp(current->name(), file_or_name) == 0) { + current->Run(); + run_count++; + } + return run_count + RunMatchingTests(current->prev(), file_or_name); +} + + +static int RunMatchingTests(CcTest* current, char* file, char* name) { + if (current == NULL) return 0; + int run_count = 0; + if (strcmp(current->file(), file) == 0 + && strcmp(current->name(), name) == 0) { + current->Run(); + run_count++; + } + return run_count + RunMatchingTests(current->prev(), file, name); +} + + +int main(int argc, char* argv[]) { + v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true); + int tests_run = 0; + bool print_run_count = true; + for (int i = 1; i < argc; i++) { + char* arg = argv[i]; + if (strcmp(arg, "--list") == 0) { + PrintTestList(CcTest::last()); + print_run_count = false; + } else { + char* arg_copy = strdup(arg); + char* testname = strchr(arg_copy, '/'); + if (testname) { + // Split the string in two by nulling the slash and then run + // exact matches. + *testname = 0; + tests_run += RunMatchingTests(CcTest::last(), arg_copy, testname + 1); + } else { + // Run all tests with the specified file or test name. + tests_run += RunMatchingTests(CcTest::last(), arg_copy); + } + free(arg_copy); + } } + if (print_run_count && tests_run != 1) + printf("Ran %i tests.\n", tests_run); + return 0; } diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h index ee2794c..e3de881 100644 --- a/test/cctest/cctest.h +++ b/test/cctest/cctest.h @@ -40,17 +40,17 @@ class CcTest { public: typedef void (TestFunction)(); CcTest(TestFunction* callback, const char* file, const char* name); + void Run() { callback_(); } static int test_count(); - static CcTest* first() { return first_; } + static CcTest* last() { return last_; } CcTest* prev() { return prev_; } const char* file() { return file_; } const char* name() { return name_; } - private: TestFunction* callback_; const char* file_; const char* name_; - static CcTest* first_; + static CcTest* last_; CcTest* prev_; }; diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 94013d5..5a49f38 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -121,9 +121,9 @@ static inline void CheckNonEqualsHelper(const char* file, int line, // Helper class for creating a V8 enviromnent for running tests -class LocalContext { +class DebugLocalContext { public: - inline LocalContext( + inline DebugLocalContext( v8::ExtensionConfiguration* extensions = 0, v8::Handle global_template = v8::Handle(), @@ -131,7 +131,7 @@ class LocalContext { : context_(v8::Context::New(extensions, global_template, global_object)) { context_->Enter(); } - inline ~LocalContext() { + inline ~DebugLocalContext() { context_->Exit(); context_.Dispose(); } @@ -159,7 +159,7 @@ class LocalContext { // Compile and run the supplied source and return the fequested function. -static v8::Local CompileFunction(LocalContext* env, +static v8::Local CompileFunction(DebugLocalContext* env, const char* source, const char* function_name) { v8::Script::Compile(v8::String::New(source))->Run(); @@ -377,7 +377,7 @@ class TestBreakLocationIterator: public v8::internal::BreakLocationIterator { // Compile a function, set a break point and check that the call at the break // location in the code is the expected debug_break function. -void CheckDebugBreakFunction(LocalContext* env, +void CheckDebugBreakFunction(DebugLocalContext* env, const char* source, const char* name, int position, v8::internal::RelocMode mode, Code* debug_break) { @@ -668,7 +668,7 @@ static void MessageCallbackCount(v8::Handle message, TEST(DebugStub) { using ::v8::internal::Builtins; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // TODO(1240753): Make the test architecture independent or split // parts of the debugger into architecture dependent files. This @@ -740,7 +740,7 @@ TEST(DebugStub) { // debugged. TEST(DebugInfo) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a couple of functions for the test. v8::Local foo = CompileFunction(&env, "function foo(){}", "foo"); @@ -777,7 +777,7 @@ TEST(DebugInfo) { TEST(BreakPointICStore) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run(); @@ -808,7 +808,7 @@ TEST(BreakPointICStore) { TEST(BreakPointICLoad) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); v8::Script::Compile(v8::String::New("bar=1"))->Run(); @@ -840,7 +840,7 @@ TEST(BreakPointICLoad) { TEST(BreakPointICCall) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); v8::Script::Compile(v8::String::New("function bar(){}"))->Run(); @@ -872,7 +872,7 @@ TEST(BreakPointICCall) { TEST(BreakPointReturn) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); v8::Script::Compile(v8::String::New("function foo(){}"))->Run(); @@ -914,7 +914,7 @@ static void CallWithBreakPoints(v8::Local recv, TEST(GCDuringBreakPointProcessing) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointCollectGarbage, v8::Undefined()); @@ -971,7 +971,7 @@ static void CallAndGC(v8::Local recv, v8::Local f) { TEST(BreakPointSurviveGC) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); @@ -1005,7 +1005,7 @@ TEST(BreakPointSurviveGC) { TEST(BreakPointThroughJavaScript) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1059,7 +1059,7 @@ TEST(BreakPointThroughJavaScript) { TEST(ScriptBreakPointThroughJavaScript) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1178,7 +1178,7 @@ TEST(ScriptBreakPointThroughJavaScript) { TEST(EnableDisableScriptBreakPoint) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1234,7 +1234,7 @@ TEST(EnableDisableScriptBreakPoint) { TEST(ConditionalScriptBreakPoint) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1295,7 +1295,7 @@ TEST(ConditionalScriptBreakPoint) { TEST(ScriptBreakPointIgnoreCount) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1349,7 +1349,7 @@ TEST(ScriptBreakPointIgnoreCount) { TEST(ScriptBreakPointReload) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1407,7 +1407,7 @@ TEST(ScriptBreakPointReload) { TEST(ScriptBreakPointMultiple) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1472,7 +1472,7 @@ TEST(ScriptBreakPointMultiple) { TEST(ScriptBreakPointLineOffset) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, @@ -1526,7 +1526,7 @@ TEST(ScriptBreakPointLineOffset) { // Test script break points set on lines. TEST(ScriptBreakPointLine) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); // Create a function for checking the function when hitting a break point. @@ -1632,7 +1632,7 @@ TEST(ScriptBreakPointLine) { // inside the break handling of that break point. TEST(RemoveBreakPointInBreak) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Local foo = CompileFunction(&env, "function foo(){a=1;}", "foo"); @@ -1657,7 +1657,7 @@ TEST(RemoveBreakPointInBreak) { TEST(DebuggerStatement) { break_point_hit_count = 0; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount, v8::Undefined()); v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run(); @@ -1684,7 +1684,7 @@ TEST(DebuggerStatement) { // the correct results. TEST(DebugEvaluate) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); // Create a function for checking the evaluation when hitting a break point. @@ -1797,7 +1797,7 @@ TEST(DebugEvaluate) { // Simple test of the stepping mechanism using only store ICs. TEST(DebugStepLinear) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for testing stepping. v8::Local foo = CompileFunction(&env, @@ -1833,7 +1833,7 @@ TEST(DebugStepLinear) { // Test the stepping mechanism with different ICs. TEST(DebugStepLinearMixedICs) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for testing stepping. v8::Local foo = CompileFunction(&env, @@ -1877,7 +1877,7 @@ TEST(DebugStepLinearMixedICs) { TEST(DebugStepIf) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Register a debug event listener which steps and counts. v8::Debug::AddDebugEventListener(DebugEventStep); @@ -1917,7 +1917,7 @@ TEST(DebugStepIf) { TEST(DebugStepSwitch) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Register a debug event listener which steps and counts. v8::Debug::AddDebugEventListener(DebugEventStep); @@ -1969,7 +1969,7 @@ TEST(DebugStepSwitch) { TEST(DebugStepFor) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Register a debug event listener which steps and counts. v8::Debug::AddDebugEventListener(DebugEventStep); @@ -2006,7 +2006,7 @@ TEST(DebugStepFor) { TEST(StepInOutSimple) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for checking the function when hitting a break point. frame_function_name = CompileFunction(&env, @@ -2051,7 +2051,7 @@ TEST(StepInOutSimple) { TEST(StepInOutTree) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for checking the function when hitting a break point. frame_function_name = CompileFunction(&env, @@ -2097,7 +2097,7 @@ TEST(StepInOutTree) { TEST(StepInOutBranch) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for checking the function when hitting a break point. frame_function_name = CompileFunction(&env, @@ -2129,7 +2129,7 @@ TEST(StepInOutBranch) { // Test that step in does not step into native functions. TEST(DebugStepNatives) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for testing stepping. v8::Local foo = CompileFunction( @@ -2170,7 +2170,7 @@ TEST(DebugStepNatives) { // for them. TEST(BreakOnException) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); v8::internal::Top::TraceException(false); @@ -2311,7 +2311,7 @@ TEST(BreakOnException) { TEST(StepWithException) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Create a function for checking the function when hitting a break point. frame_function_name = CompileFunction(&env, @@ -2392,7 +2392,7 @@ TEST(StepWithException) { TEST(DebugBreak) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // This test should be run with option --verify-heap. This is an ASSERT and // not a CHECK as --verify-heap is only available in debug mode. @@ -2447,7 +2447,7 @@ TEST(DebugBreak) { // through the stack limit flag is set but breaks are disabled. TEST(DisableBreak) { v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; // Register a debug event listener which sets the break flag and counts. v8::Debug::AddDebugEventListener(DebugEventCounter); @@ -2522,7 +2522,7 @@ static v8::Handle IndexedGetter(uint32_t index, TEST(InterceptorPropertyMirror) { // Create a V8 environment with debug access. v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; env.ExposeDebug(); // Create object with named interceptor. @@ -2864,7 +2864,7 @@ MessageQueueDebuggerThread message_queue_debugger_thread; TEST(MessageQueues) { // Create a V8 environment v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; message_queue_barriers.Initialize(); v8::Debug::SetMessageHandler(MessageHandler); message_queue_debugger_thread.Start(); @@ -2938,7 +2938,7 @@ void V8Thread::Run() { const char* source_2 = "foo();\n"; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::SetMessageHandler(&ThreadedMessageHandler); CompileRun(source_1); @@ -3047,7 +3047,7 @@ void BreakpointsV8Thread::Run() { "cat(19);\n"; v8::HandleScope scope; - LocalContext env; + DebugLocalContext env; v8::Debug::SetMessageHandler(&BreakpointsMessageHandler); CompileRun(source_1); diff --git a/test/cctest/test-flags.cc b/test/cctest/test-flags.cc index 99ee19c..7b1b988 100644 --- a/test/cctest/test-flags.cc +++ b/test/cctest/test-flags.cc @@ -124,10 +124,10 @@ TEST(Flags4) { SetFlagsToDefault(); int argc = 3; const char* argv[] = { "Test4", "--bool_flag", "--foo" }; - CHECK_EQ(2, FlagList::SetFlagsFromCommandLine(&argc, + CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc, const_cast(argv), true)); - CHECK_EQ(3, argc); + CHECK_EQ(2, argc); } diff --git a/test/cctest/testcfg.py b/test/cctest/testcfg.py new file mode 100644 index 0000000..552fac3 --- /dev/null +++ b/test/cctest/testcfg.py @@ -0,0 +1,84 @@ +# Copyright 2008 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER 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. + +import test +import os +from os.path import join, dirname +import platform + + +DEBUG_FLAGS = ['--enable-slow-asserts', '--debug-code', '--verify-heap'] + + +class CcTestCase(test.TestCase): + + def __init__(self, path, executable, mode, raw_name, context): + super(CcTestCase, self).__init__(context, path) + self.executable = executable + self.mode = mode + self.raw_name = raw_name + + def GetLabel(self): + return "%s %s %s" % (self.mode, self.path[-2], self.path[-1]) + + def GetName(self): + return self.path[-1] + + def GetCommand(self): + result = [ self.executable, self.raw_name ] + if self.mode == 'debug': + result += DEBUG_FLAGS + return result + + +class CcTestConfiguration(test.TestConfiguration): + + def __init__(self, context, root): + super(CcTestConfiguration, self).__init__(context, root) + + def GetBuildRequirements(self): + return ['cctests'] + + def ListTests(self, current_path, path, mode): + executable = join('obj', 'test', mode, 'cctest') + if (platform.system() == 'Windows'): + executable += '.exe' + output = test.Execute([executable, '--list'], self.context) + if output.exit_code != 0: + print output.stdout + print output.stderr + return [] + result = [] + for raw_test in output.stdout.strip().split(): + full_path = current_path + raw_test.split('/') + if self.Contains(path, full_path): + result.append(CcTestCase(full_path, executable, mode, raw_test, self.context)) + return result + + +def GetConfiguration(context, root): + return CcTestConfiguration(context, root) diff --git a/test/mjsunit/debug-script.js b/test/mjsunit/debug-script.js index d4da499..5a5caf1 100644 --- a/test/mjsunit/debug-script.js +++ b/test/mjsunit/debug-script.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug +// Flags: --expose-debug-as debug --expose-gc // Get the Debug object exposed from the debug context global object. Debug = debug.Debug @@ -55,7 +55,7 @@ for (i = 0; i < scripts.length; i++) { // This has to be updated if the number of native and extension scripts change. assertEquals(12, native_count); -assertEquals(5, extension_count); +assertEquals(1, extension_count); assertEquals(2, normal_count); // This script and mjsunit.js. // Test a builtins script. @@ -80,7 +80,7 @@ assertEquals(Debug.ScriptType.Extension, extension_gc_script.type); // Test a normal script. var mjsunit_js_script = Debug.findScript(/mjsunit.js/); -assertEquals('mjsunit.js', mjsunit_js_script.name); +assertTrue(/mjsunit.js/.test(mjsunit_js_script.name)); assertEquals(Debug.ScriptType.Normal, mjsunit_js_script.type); // Check a nonexistent script. diff --git a/test/mjsunit/function-source.js b/test/mjsunit/function-source.js index 88b0f48..ddb53b4 100644 --- a/test/mjsunit/function-source.js +++ b/test/mjsunit/function-source.js @@ -47,5 +47,3 @@ function g() { assertEquals(Debug.scriptSource(f), Debug.scriptSource(g)); f(); g(); - -assertEquals("function print() { [native code] }", print); diff --git a/test/mjsunit/mirror-object.js b/test/mjsunit/mirror-object.js index 4dc7363..75962d9 100644 --- a/test/mjsunit/mirror-object.js +++ b/test/mjsunit/mirror-object.js @@ -48,7 +48,7 @@ function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) { assertTrue(mirror.prototypeObject() instanceof debug.Mirror); assertFalse(mirror.hasNamedInterceptor(), "hasNamedInterceptor()"); assertFalse(mirror.hasIndexedInterceptor(), "hasIndexedInterceptor()"); - + var names = mirror.propertyNames(); var properties = mirror.properties() assertEquals(names.length, properties.length); @@ -77,10 +77,11 @@ function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) { assertEquals('object', fromJSON.type); assertEquals(cls_name, fromJSON.className); assertEquals('function', fromJSON.constructorFunction.type); - assertEquals(ctor_name, fromJSON.constructorFunction.name); + if (ctor_name !== undefined) + assertEquals(ctor_name, fromJSON.constructorFunction.name); assertEquals(void 0, fromJSON.namedInterceptor); assertEquals(void 0, fromJSON.indexedInterceptor); - + // For array the index properties are seperate from named properties. if (!cls_name == 'Array') { assertEquals(names.length, fromJSON.properties.length, 'Some properties missing in JSON'); @@ -134,7 +135,7 @@ testObjectMirror({}, 'Object', 'Object'); testObjectMirror({'a':1,'b':2}, 'Object', 'Object'); testObjectMirror({'1':void 0,'2':null,'f':function pow(x,y){return Math.pow(x,y);}}, 'Object', 'Object'); testObjectMirror(new Point(-1.2,2.003), 'Object', 'Point'); -testObjectMirror(this, 'global', 'Object', true); // Global object has special properties +testObjectMirror(this, 'global', undefined, true); // Global object has special properties testObjectMirror([], 'Array', 'Array'); testObjectMirror([1,2], 'Array', 'Array'); diff --git a/test/mjsunit/regexp-multiline-stack-trace.js b/test/mjsunit/regexp-multiline-stack-trace.js index a4acc8a..cc960cb 100644 --- a/test/mjsunit/regexp-multiline-stack-trace.js +++ b/test/mjsunit/regexp-multiline-stack-trace.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --trace-calls --preallocated-stack-trace-memory 1000000 +// Flags: --trace-calls --preallocate-message-memory /** * @fileoverview Check that various regexp constructs work as intended. diff --git a/test/mjsunit/regress/regress-1341167.js b/test/mjsunit/regress/regress-1341167.js new file mode 100644 index 0000000..5367d23 --- /dev/null +++ b/test/mjsunit/regress/regress-1341167.js @@ -0,0 +1,33 @@ +// Copyright 2008 Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER 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. + +// Make sure that 'this' is bound to the global object when using +// execScript. + +var result; +execScript("result = this"); +assertTrue(result === this); diff --git a/test/mjsunit/testcfg.py b/test/mjsunit/testcfg.py index 4fcd0a6..bd056d5 100644 --- a/test/mjsunit/testcfg.py +++ b/test/mjsunit/testcfg.py @@ -36,21 +36,24 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") class MjsunitTestCase(test.TestCase): - def __init__(self, path, file, config): - super(MjsunitTestCase, self).__init__(path) + def __init__(self, path, file, mode, context, config): + super(MjsunitTestCase, self).__init__(context, path) self.file = file self.config = config + self.mode = mode + def GetLabel(self): + return "%s %s" % (self.mode, self.GetName()) + def GetName(self): return self.path[-1] - + def GetCommand(self): - result = [self.config.context.vm] + result = [self.config.context.GetVm(self.mode)] source = open(self.file).read() flags_match = FLAGS_PATTERN.search(source) if flags_match: - runtime_flags = flags_match.group(1).strip().split() - result += ["--runtime-flags", " ".join(runtime_flags)] + result += flags_match.group(1).strip().split() framework = join(dirname(self.config.root), 'mjsunit', 'mjsunit.js') result += [framework, self.file] return result @@ -65,29 +68,21 @@ class MjsunitTestConfiguration(test.TestConfiguration): def SelectTest(name): return name.endswith('.js') and name != 'mjsunit.js' return [f[:-3] for f in os.listdir(path) if SelectTest(f)] - - def Contains(self, path, file): - if len(path) > len(file): - return False - for i in xrange(len(path)): - if path[i] != file[i]: - return False - return True - + def ListTests(self, current_path, path, mode): - mjsunit = [[t] for t in self.Ls(self.root)] - regress = [['regress', t] for t in self.Ls(join(self.root, 'regress'))] + mjsunit = [current_path + [t] for t in self.Ls(self.root)] + regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))] all_tests = mjsunit + regress result = [] for test in all_tests: if self.Contains(path, test): full_name = current_path + test - file_path = join(self.root, reduce(join, test, "") + ".js") - result.append(MjsunitTestCase(full_name, file_path, self)) + file_path = join(self.root, reduce(join, test[1:], "") + ".js") + result.append(MjsunitTestCase(full_name, file_path, mode, self.context, self)) return result def GetBuildRequirements(self): - return ['sample=shell'] + return ['sample', 'sample=shell'] def GetConfiguration(context, root): diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status new file mode 100644 index 0000000..2fe1da7 --- /dev/null +++ b/test/mozilla/mozilla.status @@ -0,0 +1,762 @@ +# Copyright 2008 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER 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. + +# -------------------------------------------------------------------- +# If you add a test case to this file, please try to provide +# an explanation of why the test fails; this may ease future +# debugging. +# -------------------------------------------------------------------- + +prefix mozilla_js_tests +def FAIL_OK = FAIL, OKAY + + +##################### SKIPPED TESTS ##################### + +# This test checks that we behave properly in an out-of-memory +# situation. The test fails in V8 with an exception and takes a long +# time to do so. +js1_5/Regress/regress-271716-n: SKIP + + +##################### SLOW TESTS ##################### + +# This takes a long time to run (~100 seconds). It should only be run +# by the really patient. +js1_5/GC/regress-324278: SLOW + +# This takes a long time to run because our indexOf operation is +# pretty slow - it causes a lot of GCs; see issue +# #926379. We could consider marking this SKIP because it takes a +# while to run to completion. +js1_5/GC/regress-338653: SLOW + +# This test is designed to run until it runs out of memory. This takes +# a very long time because it builds strings character by character +# and compiles a lot of regular expressions. We could consider marking +# this SKIP because it takes a while to run to completion. +js1_5/GC/regress-346794: SLOW + +# Runs out of memory while trying to build huge string of 'x' +# characters. This takes a long time to run (~32 seconds). +js1_5/GC/regress-348532: SLOW + + +##################### FLAKY TESTS ##################### + +# These tests time out in debug mode but pass in product mode +js1_5/Regress/regress-280769-3: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-203278-1: PASS || ($DEBUG && FAIL) +js1_5/GC/regress-203278-2: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-244470: PASS || ($DEBUG && FAIL) +ecma_3/RegExp/regress-209067: PASS || ($DEBUG && FAIL) +js1_5/GC/regress-278725: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-360969-03: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-360969-04: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-360969-05: PASS || ($DEBUG && FAIL) +js1_5/Regress/regress-360969-06: PASS || ($DEBUG && FAIL) +js1_5/extensions/regress-365527: PASS || ($DEBUG && FAIL) +# http://b/issue?id=1206983 +js1_5/Regress/regress-367561-03: PASS || ($DEBUG && FAIL) +ecma/Date/15.9.5.10-2: PASS || ($DEBUG && FAIL) + +# These tests create two Date objects just after each other and +# expects them to match. Sometimes this happens on the border +# between one second and the next. +ecma/Date/15.9.2.1: PASS || FAIL +ecma/Date/15.9.2.2-1: PASS || FAIL +ecma/Date/15.9.2.2-2: PASS || FAIL +ecma/Date/15.9.2.2-3: PASS || FAIL +ecma/Date/15.9.2.2-4: PASS || FAIL +ecma/Date/15.9.2.2-5: PASS || FAIL +ecma/Date/15.9.2.2-6: PASS || FAIL + +# 1026139: These date tests fail on arm +ecma/Date/15.9.5.29-1: PASS || ($ARM && FAIL) +ecma/Date/15.9.5.34-1: PASS || ($ARM && FAIL) +ecma/Date/15.9.5.28-1: PASS || ($ARM && FAIL) + +# 1050186: Arm vm is broken; probably unrelated to dates +ecma/Array/15.4.4.5-3: PASS || ($ARM && FAIL) +ecma/Date/15.9.5.22-2: PASS || ($ARM && FAIL) + +# Severely brain-damaged test. Access to local variables must not +# be more than 2.5 times faster than access to global variables? WTF? +js1_5/Regress/regress-169559: PASS || FAIL + + +# Test that rely on specific timezone (not working in Denmark). +js1_5/Regress/regress-58116: PASS || FAIL + + +# Flaky random() test. Tests the distribution of calls to Math.random(). +js1_5/Regress/regress-211590: PASS || FAIL + + +# Flaky tests; expect BigO-order computations to yield 1, but the code +# cannot handle outliers. See bug #925864. +ecma_3/RegExp/regress-311414: PASS || FAIL +ecma_3/RegExp/regress-289669: PASS || FAIL +js1_5/String/regress-314890: PASS || FAIL +js1_5/String/regress-56940-01: PASS || FAIL +js1_5/String/regress-56940-02: PASS || FAIL +js1_5/String/regress-157334-01: PASS || FAIL +js1_5/String/regress-322772: PASS || FAIL +js1_5/Array/regress-99120-01: PASS || FAIL +js1_5/Array/regress-99120-02: PASS || FAIL +js1_5/Regress/regress-347306-01: PASS || FAIL +js1_5/Regress/regress-416628: PASS || FAIL + + +# The following two tests assume that daylight savings time starts first Sunday +# in April. This is not true when executing the tests outside California! +# In Denmark the adjustment starts one week earlier!. +# Tests based on shell that use dates in this gap are flaky. +ecma/Date/15.9.5.10-1: PASS || FAIL +ecma/Date/15.9.5.12-1: PASS || FAIL +ecma/Date/15.9.5.14: PASS || FAIL +ecma/Date/15.9.5.34-1: PASS || FAIL + + +# These tests sometimes pass (in particular on Windows). They build up +# a lot of stuff on the stack, which normally causes a stack overflow, +# but sometimes it makes it through? +js1_5/Regress/regress-290575: PASS || FAIL +js1_5/Regress/regress-98901: PASS || FAIL + + +# Tests that sorting arrays of ints is less than 3 times as fast +# as sorting arrays of strings. +js1_5/extensions/regress-371636: PASS || FAIL + + +# Test depends on GC timings. Inherently flaky. +js1_5/GC/regress-383269-01: PASS || FAIL + + +##################### INCOMPATIBLE TESTS ##################### + +# This section is for tests that fail in both V8 and KJS. Thus they +# have been determined to be incompatible between Mozilla and V8/KJS. + +# Fail because of toLowerCase and toUpperCase conversion. +ecma/String/15.5.4.11-2: FAIL_OK +ecma/String/15.5.4.11-5: FAIL_OK +ecma/String/15.5.4.12-1: FAIL_OK +ecma/String/15.5.4.12-4: FAIL_OK + +# This test uses an older version of the unicode standard that fails +# us because we correctly convert the armenian small ligature ech-yiwn +# to the two upper-case characters ECH and YIWN, whereas the older +# unicode version converts it to itself. +ecma/String/15.5.4.12-5: FAIL_OK + +# Creates a linked list of arrays until we run out of memory. +js1_5/Regress/regress-312588: FAIL_OK + + +# Runs out of memory because it compiles huge functions. +js1_5/Function/regress-338001: FAIL_OK +js1_5/Function/regress-338121-01: FAIL_OK +js1_5/Function/regress-338121-02: FAIL_OK +js1_5/Function/regress-338121-03: FAIL_OK + + +# Length of objects whose prototype chain includes a function +ecma_3/Function/regress-313570: FAIL_OK + + +#:=== RegExp:=== +# To be compatible with KJS we silently ignore flags that do not make +# sense. This test expects us to throw exceptions. +ecma_3/RegExp/regress-57631: FAIL_OK + +# PCRE doesn't allow subpattern nesting deeper than 200, this tests +# depth 500. KJS detects the case, and return null from the match, +# and passes this test (the test doesn't check for a correct return +# value). +ecma_3/RegExp/regress-119909: FAIL_OK + + +# Difference in the way capturing subpatterns work. In JS, when the +# 'minimum repeat count' is reached, the empty string must not match. +# In this case, we are similar but not identical to KJS. Hard to +# support the JS behavior with PCRE, so maybe emulate KJS? +# +# Note: We do not support toSource currently so we cannot run this +# test. We should make an isolated test case for the regexp issue. +ecma_3/RegExp/regress-209919: FAIL_OK + + +# PCRE's match limit is reached. SpiderMonkey hangs on the first one, +# KJS returns true somehow. Maybe they up the match limit? There is +# an open V8 bug 676063 about this. +ecma_3/RegExp/regress-330684: FAIL_OK + + +# We do not detect overflow in bounds for back references and {} +# quantifiers. Might fix by parsing numbers differently? +js1_5/Regress/regress-230216-2: FAIL_OK + + +# According to ECMA-262, \b is a 'word' boundary, where words are only +# ASCII characters. PCRE supports non-ASCII word characters. +js1_5/Regress/regress-247179: FAIL_OK + + +# Regexp too long for PCRE. +js1_5/Regress/regress-280769: FAIL_OK +js1_5/Regress/regress-280769-1: FAIL_OK +js1_5/Regress/regress-280769-2: FAIL_OK +js1_5/Regress/regress-280769-4: FAIL_OK +js1_5/Regress/regress-280769-5: FAIL_OK + + +# We do not support static RegExp.multiline - should we?. +js1_2/regexp/RegExp_multiline: FAIL_OK +js1_2/regexp/RegExp_multiline_as_array: FAIL_OK +js1_2/regexp/beginLine: FAIL_OK +js1_2/regexp/endLine: FAIL_OK + + +# Date trouble? +js1_5/Date/regress-301738-02: FAIL_OK + + +# This test fails for all browsers on in the CET timezone. +ecma/Date/15.9.5.35-1: PASS || FAIL_OK + + +# Spidermonkey allows stuff in parenthesis directly after the minutes +# in a date. KJS does not, so we don't either. +js1_5/Date/regress-309925-02: FAIL_OK + + +# Print string after deleting array element? +js1_5/Expressions/regress-96526-delelem: FAIL_OK + + +# Stack overflows should be InternalError: too much recursion? +js1_5/Regress/regress-234389: FAIL_OK + + +# This may very well be a bogus test. I'm not sure yet. +js1_5/Regress/regress-320119: FAIL_OK + + +# We do not support explicit global evals through .eval(...). +js1_5/Regress/regress-68498-003: FAIL_OK + + +# No support for toSource(). +js1_5/Regress/regress-248444: FAIL_OK +js1_5/Regress/regress-313967-01: FAIL_OK +js1_5/Regress/regress-313967-02: FAIL_OK + +# This fails because we don't have stack space for Function.prototype.apply +# with very large numbers of arguments. The test uses 2^24 arguments. +js1_5/Array/regress-350256-03: FAIL_OK + + +# Extra arguments not handled properly in String.prototype.match +js1_5/Regress/regress-179524: FAIL_OK + + +# Uncategorized failures. Please help categorize (or fix) these failures. +js1_5/Regress/regress-172699: FAIL_OK + + +# Calls regexp objects with function call syntax; non-ECMA behavior. +js1_2/Objects/toString-001: FAIL_OK + + +# Assumes that the prototype of a function is enumerable. Non-ECMA, +# see section 15.3.3.1, page 86. +ecma/GlobalObject/15.1.2.2-1: FAIL_OK +ecma/GlobalObject/15.1.2.3-1: FAIL_OK +ecma/GlobalObject/15.1.2.4: FAIL_OK +ecma/GlobalObject/15.1.2.5-1: FAIL_OK +ecma/GlobalObject/15.1.2.6: FAIL_OK +ecma/GlobalObject/15.1.2.7: FAIL_OK + + +# Tests that rely on specific details of function decompilation or +# print strings for errors. Non-ECMA behavior. +js1_2/function/tostring-2: FAIL_OK +js1_5/Exceptions/regress-332472: FAIL_OK +js1_5/Regress/regress-173067: FAIL_OK +js1_5/Regress/regress-355556: FAIL_OK +js1_5/Regress/regress-328664: FAIL_OK +js1_5/Regress/regress-252892: FAIL_OK +js1_5/Regress/regress-352208: FAIL_OK +ecma_3/Array/15.4.5.1-01: FAIL_OK +ecma_3/Array/regress-387501: FAIL_OK +ecma_3/LexicalConventions/7.9.1: FAIL_OK +ecma_3/RegExp/regress-375711: FAIL_OK +ecma_3/Unicode/regress-352044-01: FAIL_OK +ecma_3/extensions/regress-274152: FAIL_OK +js1_5/Regress/regress-372364: FAIL_OK +js1_5/Regress/regress-420919: FAIL_OK +js1_5/Regress/regress-422348: FAIL_OK +ecma_3/RegExp/regress-375715-04: FAIL_OK + + +# Uses Mozilla-specific QName, XML, XMLList and Iterator. +js1_5/Regress/regress-407323: FAIL_OK +js1_5/Regress/regress-407957: FAIL_OK + + +# Relies on JavaScript 1.2 / 1.3 deprecated features. +js1_2/function/String: FAIL_OK +js1_2/operator/equality: FAIL_OK +js1_2/version120/boolean-001: FAIL_OK +js1_2/String/concat: FAIL_OK +js1_2/function/Function_object: FAIL_OK +js1_2/function/tostring-1: FAIL_OK +js1_2/version120/regress-99663: FAIL_OK +js1_2/regexp/RegExp_lastIndex: FAIL_OK +js1_2/regexp/string_split: FAIL_OK + + +# We do not check for bad surrogate pairs when quoting strings. +js1_5/Regress/regress-315974: FAIL_OK + + +# Use unsupported "watch". +js1_5/Regress/regress-213482: FAIL_OK +js1_5/Regress/regress-240577: FAIL_OK +js1_5/Regress/regress-355344: FAIL_OK +js1_5/Object/regress-362872-01: FAIL_OK +js1_5/Object/regress-362872-02: FAIL_OK +js1_5/Regress/regress-361467: FAIL_OK +js1_5/Regress/regress-385393-06: FAIL_OK + + +# Use special Mozilla getter/setter syntax +js1_5/Regress/regress-354924: FAIL_OK +js1_5/Regress/regress-355341: FAIL_OK +js1_5/GC/regress-316885-01: FAIL_OK +js1_5/GetSet/getset-002: FAIL_OK +js1_5/GetSet/regress-353264: FAIL_OK +js1_5/Regress/regress-361617: FAIL_OK +js1_5/Regress/regress-362583: FAIL_OK + + +# 'native' *is* a keyword in V8. +js1_5/Regress/regress-240317: FAIL_OK + + +# Requires Mozilla-specific strict mode or options() function. +ecma_3/Object/8.6.1-01: FAIL_OK +js1_5/Exceptions/regress-315147: FAIL_OK +js1_5/Regress/regress-106244: FAIL_OK +js1_5/Regress/regress-317533: FAIL_OK +js1_5/Regress/regress-323314-1: FAIL_OK +js1_5/Regress/regress-352197: FAIL_OK +js1_5/Regress/regress-115436: FAIL_OK +js1_5/Regress/regress-214761: FAIL_OK +js1_5/Regress/regress-253150: FAIL_OK +js1_5/Regress/regress-306727: FAIL_OK +js1_5/Regress/regress-308566: FAIL_OK +js1_5/Regress/regress-312260: FAIL_OK +js1_5/Regress/regress-322430: FAIL_OK +js1_5/Regress/regress-383674: FAIL_OK + + +# Equivalent to assert(false). +ecma_2/RegExp/exec-001: FAIL_OK +ecma_2/String/replace-001: FAIL_OK + + +# We do not strip unicode format control characters. This is really +# required for working with non-latin character sets. We match KJS +# and IE here. Firefox matches the spec (section 7.1). +ecma_3/Unicode/uc-001: FAIL_OK + + +# A non-breaking space doesn't match \s in a regular expression. This behaviour +# matches KJS. All the VMs have different behaviours in which characters match +# \s so we do the same as KJS until they change. +ecma_3/Unicode/uc-002: FAIL_OK + + +# String.prototype.split on empty strings always returns an array +# with one element (as specified in ECMA-262). +js1_2/Array/array_split_1: FAIL_OK + + +# The concat() method is defined in Array.prototype; not Array. +js1_5/Array/regress-313153: FAIL_OK + + +# Properties stack, fileName, and lineNumber of Error instances are +# not supported. Mozilla specific extension. +js1_5/Exceptions/errstack-001: FAIL_OK +js1_5/Exceptions/regress-257751: FAIL_OK +js1_5/Regress/regress-119719: FAIL_OK +js1_5/Regress/regress-139316: FAIL_OK +js1_5/Regress/regress-167328: FAIL_OK +js1_5/Regress/regress-243869: FAIL_OK + + +# Unsupported import/export and literals. Mozilla extensions. +js1_5/Regress/regress-249211: FAIL_OK +js1_5/Regress/regress-309242: FAIL_OK +js1_5/Regress/regress-350692: FAIL_OK + + +# The length of Error functions is 1 not 3. +js1_5/Exceptions/regress-123002: FAIL_OK + + +# Reserved keywords as function names, etc is not supported. +js1_5/LexicalConventions/regress-343675: FAIL_OK + + +# Unsupported list comprehensions: [ ... for ... ] and for each. +js1_5/Regress/regress-352009: FAIL_OK +js1_5/Regress/regress-349648: FAIL_OK + + +# Expects top level arguments (passed on command line?) to be +# the empty string? +js1_5/Regress/regress-336100: FAIL_OK + + +# Regular expression test failures due to PCRE. We match KJS (ie, perl) +# behavior and not the ECMA spec. +ecma_3/RegExp/15.10.2-1: FAIL_OK +ecma_3/RegExp/perlstress-001: FAIL_OK +ecma_3/RegExp/regress-334158: FAIL_OK + + +# This test requires a failure if we try to compile a function with more +# than 65536 arguments. This seems to be a Mozilla restriction. +js1_5/Regress/regress-290575: FAIL_OK + + +# Fails because of the way function declarations are +# handled in V8/KJS. V8 follows IE behavior and introduce +# all nested function declarations when entering the +# surrounding function, whereas Spidermonkey declares +# them dynamically when the statement is executed. +ecma_3/Function/scope-001: FAIL_OK +ecma_3/FunExpr/fe-001: FAIL_OK +js1_5/Scope/regress-184107: FAIL_OK + + +# Function is deletable in V8 and KJS. +js1_5/Regress/regress-352604: FAIL_OK + + +# Cannot call strings as functions. Expects not to crash. +js1_5/Regress/regress-417893: FAIL_OK + + + +##################### FAILING TESTS ##################### + +# This section is for tests that fail in V8 and pass in KJS. +# Tests that fail in both V8 and KJS belong in the FAIL_OK +# category. + +# This fails because we don't handle Function.prototype.apply with very large +# numbers of arguments (depending on max stack size). 350256-02 needs more than +# 4Mbytes of stack space. +js1_5/Array/regress-350256-02: FAIL + + +# This fails because 'delete arguments[i]' does not disconnect the +# argument from the arguments array. See issue #900066. +ecma_3/Function/regress-137181: FAIL + + +# Calls regexp objects with function call syntax; non-ECMA behavior. +ecma_2/RegExp/regress-001: FAIL +js1_2/regexp/regress-6359: FAIL +js1_2/regexp/regress-9141: FAIL +js1_5/Regress/regress-224956: FAIL +js1_5/Regress/regress-325925: FAIL +js1_2/regexp/simple_form: FAIL + + +# Tests that rely on specific details of function decompilation or +# print strings for errors. Non-ECMA behavior. +js1_4/Regress/function-003: FAIL + + +# Relies on JavaScript 1.2 / 1.3 deprecated features. +js1_2/function/regexparg-1: FAIL + + +# 'export' and 'import' are not keywords in V8. +ecma_2/Exceptions/lexical-010: FAIL +ecma_2/Exceptions/lexical-022: FAIL + + +# Requires Mozilla-specific strict mode. +ecma_2/Exceptions/lexical-011: FAIL +ecma_2/Exceptions/lexical-014: FAIL +ecma_2/Exceptions/lexical-016: FAIL +ecma_2/Exceptions/lexical-021: FAIL +ecma_2/LexicalConventions/keywords-001: FAIL +js1_5/Regress/regress-306633: FAIL + + +# This test seems designed to fail (it produces a 700Mbyte string). +# We fail on out of memory. The important thing is not to crash. +js1_5/Regress/regress-303213: FAIL + + +# Bug 1193440: Ignore Unicode BOM characters when scanning. +ecma_3/extensions/regress-368516: FAIL + +# Bug 1202592:New ecma_3/String/15.5.4.11 is failing. +ecma_3/String/15.5.4.11: FAIL + +# Bug 1202597: New js1_5/Expressions/regress-394673 is failing. +# Marked as: Will not fix. V8 throws an acceptable RangeError. +js1_5/Expressions/regress-394673: FAIL + +# Bug 1202598: New mozilla test js1_5/Regress/regress-383682 fails. +js1_5/Regress/regress-383682: FAIL + + +##################### MOZILLA EXTENSION TESTS ##################### + +ecma/extensions/15.1.2.1-1: FAIL_OK +ecma_3/extensions/regress-385393-03: FAIL_OK +ecma_3/extensions/7.9.1: FAIL_OK +js1_5/extensions/catchguard-001: FAIL_OK +js1_5/extensions/catchguard-002: FAIL_OK +js1_5/extensions/catchguard-003: FAIL_OK +js1_5/extensions/getset-001: FAIL_OK +js1_5/extensions/getset-003: FAIL_OK +js1_5/extensions/no-such-method: FAIL_OK +js1_5/extensions/regress-104077: FAIL_OK +js1_5/extensions/regress-226078: FAIL_OK +js1_5/extensions/regress-303277: FAIL_OK +js1_5/extensions/regress-304897: FAIL_OK +js1_5/extensions/regress-306738: FAIL_OK +js1_5/extensions/regress-311161: FAIL_OK +js1_5/extensions/regress-311583: FAIL_OK +js1_5/extensions/regress-311792-01: FAIL_OK +js1_5/extensions/regress-312278: FAIL_OK +js1_5/extensions/regress-313630: FAIL_OK +js1_5/extensions/regress-313763: FAIL_OK +js1_5/extensions/regress-313803: FAIL_OK +js1_5/extensions/regress-314874: FAIL_OK +js1_5/extensions/regress-322957: FAIL_OK +js1_5/extensions/regress-328556: FAIL_OK +js1_5/extensions/regress-330569: FAIL_OK +js1_5/extensions/regress-333541: FAIL_OK +js1_5/extensions/regress-335700: FAIL_OK +js1_5/extensions/regress-336409-1: FAIL_OK +js1_5/extensions/regress-336409-2: FAIL_OK +js1_5/extensions/regress-336410-1: FAIL_OK +js1_5/extensions/regress-336410-2: FAIL_OK +js1_5/extensions/regress-341956-01: FAIL_OK +js1_5/extensions/regress-341956-02: FAIL_OK +js1_5/extensions/regress-341956-03: FAIL_OK +js1_5/extensions/regress-342960: FAIL_OK +js1_5/extensions/regress-345967: FAIL_OK +js1_5/extensions/regress-346494-01: FAIL_OK +js1_5/extensions/regress-346494: FAIL_OK +js1_5/extensions/regress-347306-02: FAIL_OK +js1_5/extensions/regress-348986: FAIL_OK +js1_5/extensions/regress-349616: FAIL_OK +js1_5/extensions/regress-350312-02: FAIL_OK +js1_5/extensions/regress-350312-03: FAIL_OK +js1_5/extensions/regress-350531: FAIL_OK +js1_5/extensions/regress-351102-01: FAIL_OK +js1_5/extensions/regress-351102-02: FAIL_OK +js1_5/extensions/regress-351102-06: FAIL_OK +js1_5/extensions/regress-351448: FAIL_OK +js1_5/extensions/regress-351973: FAIL_OK +js1_5/extensions/regress-352060: FAIL_OK +js1_5/extensions/regress-352094: FAIL_OK +js1_5/extensions/regress-352261: FAIL_OK +js1_5/extensions/regress-352281: FAIL_OK +js1_5/extensions/regress-352372: FAIL_OK +js1_5/extensions/regress-352455: FAIL_OK +js1_5/extensions/regress-352604: FAIL_OK +js1_5/extensions/regress-353214: FAIL_OK +js1_5/extensions/regress-355339: FAIL_OK +js1_5/extensions/regress-355497: FAIL_OK +js1_5/extensions/regress-355622: FAIL_OK +js1_5/extensions/regress-355736: FAIL_OK +js1_5/extensions/regress-356085: FAIL_OK +js1_5/extensions/regress-356106: FAIL_OK +js1_5/extensions/regress-358594-01: FAIL_OK +js1_5/extensions/regress-358594-02: FAIL_OK +js1_5/extensions/regress-358594-03: FAIL_OK +js1_5/extensions/regress-358594-04: FAIL_OK +js1_5/extensions/regress-358594-05: FAIL_OK +js1_5/extensions/regress-358594-06: FAIL_OK +js1_5/extensions/regress-361346: FAIL_OK +js1_5/extensions/regress-361360: FAIL_OK +js1_5/extensions/regress-361558: FAIL_OK +js1_5/extensions/regress-361571: FAIL_OK +js1_5/extensions/regress-361856: FAIL_OK +js1_5/extensions/regress-361964: FAIL_OK +js1_5/extensions/regress-363988: FAIL_OK +js1_5/extensions/regress-365869: FAIL_OK +js1_5/extensions/regress-367630: FAIL_OK +js1_5/extensions/regress-367923: FAIL_OK +js1_5/extensions/regress-368859: FAIL_OK +js1_5/extensions/regress-374589: FAIL_OK +js1_5/extensions/regress-375801: FAIL_OK +js1_5/extensions/regress-376052: FAIL_OK +js1_5/extensions/regress-379523: FAIL_OK +js1_5/extensions/regress-380581: FAIL_OK +js1_5/extensions/regress-380831: FAIL_OK +js1_5/extensions/regress-381205: FAIL_OK +js1_5/extensions/regress-381211: FAIL_OK +js1_5/extensions/regress-381304: FAIL_OK +js1_5/extensions/regress-382509: FAIL_OK +js1_5/extensions/regress-383965: FAIL_OK +js1_5/extensions/regress-384680: FAIL_OK +js1_5/extensions/regress-385393-09: FAIL_OK +js1_5/extensions/regress-407501: FAIL_OK +js1_5/extensions/regress-418730: FAIL_OK +js1_5/extensions/regress-420612: FAIL_OK +js1_5/extensions/regress-420869-01: FAIL_OK +js1_5/extensions/regress-424257: FAIL_OK +js1_5/extensions/regress-424683-01: FAIL_OK +js1_5/extensions/regress-44009: FAIL_OK +js1_5/extensions/regress-50447-1: FAIL_OK +js1_5/extensions/regress-50447: FAIL_OK +js1_5/extensions/regress-90596-001: FAIL_OK +js1_5/extensions/regress-90596-002: FAIL_OK +js1_5/extensions/regress-96284-001: FAIL_OK +js1_5/extensions/regress-96284-002: FAIL_OK +js1_5/extensions/scope-001: FAIL_OK +js1_5/extensions/toLocaleFormat-01: FAIL_OK +js1_5/extensions/toLocaleFormat-02: FAIL_OK + + +##################### DECOMPILATION TESTS ##################### + +# We don't really about the outcome of running the +# decompilation tests as long as they don't crash or +# timeout. + +js1_5/decompilation/regress-344120: PASS || FAIL +js1_5/decompilation/regress-346892: PASS || FAIL +js1_5/decompilation/regress-346902: PASS || FAIL +js1_5/decompilation/regress-346904: PASS || FAIL +js1_5/decompilation/regress-346915: PASS || FAIL +js1_5/decompilation/regress-349484: PASS || FAIL +js1_5/decompilation/regress-349489: PASS || FAIL +js1_5/decompilation/regress-349491: PASS || FAIL +js1_5/decompilation/regress-349596: PASS || FAIL +js1_5/decompilation/regress-349650: PASS || FAIL +js1_5/decompilation/regress-349663: PASS || FAIL +js1_5/decompilation/regress-350242: PASS || FAIL +js1_5/decompilation/regress-350263: PASS || FAIL +js1_5/decompilation/regress-350271: PASS || FAIL +js1_5/decompilation/regress-350666: PASS || FAIL +js1_5/decompilation/regress-350670: PASS || FAIL +js1_5/decompilation/regress-351104: PASS || FAIL +js1_5/decompilation/regress-351219: PASS || FAIL +js1_5/decompilation/regress-351336: PASS || FAIL +js1_5/decompilation/regress-351597: PASS || FAIL +js1_5/decompilation/regress-351625: PASS || FAIL +js1_5/decompilation/regress-351626: PASS || FAIL +js1_5/decompilation/regress-351693: PASS || FAIL +js1_5/decompilation/regress-351705: PASS || FAIL +js1_5/decompilation/regress-351793: PASS || FAIL +js1_5/decompilation/regress-352013: PASS || FAIL +js1_5/decompilation/regress-352022: PASS || FAIL +js1_5/decompilation/regress-352073: PASS || FAIL +js1_5/decompilation/regress-352202: PASS || FAIL +js1_5/decompilation/regress-352312: PASS || FAIL +js1_5/decompilation/regress-352360: PASS || FAIL +js1_5/decompilation/regress-352375: PASS || FAIL +js1_5/decompilation/regress-352453: PASS || FAIL +js1_5/decompilation/regress-352649: PASS || FAIL +js1_5/decompilation/regress-352873-01: PASS || FAIL +js1_5/decompilation/regress-352873-02: PASS || FAIL +js1_5/decompilation/regress-353000: PASS || FAIL +js1_5/decompilation/regress-353120: PASS || FAIL +js1_5/decompilation/regress-353146: PASS || FAIL +js1_5/decompilation/regress-354878: PASS || FAIL +js1_5/decompilation/regress-354910: PASS || FAIL +js1_5/decompilation/regress-355992: PASS || FAIL +js1_5/decompilation/regress-356083: PASS || FAIL +js1_5/decompilation/regress-356248: PASS || FAIL +js1_5/decompilation/regress-371692: PASS || FAIL +js1_5/decompilation/regress-373678: PASS || FAIL +js1_5/decompilation/regress-375639: PASS || FAIL +js1_5/decompilation/regress-375882: PASS || FAIL +js1_5/decompilation/regress-376564: PASS || FAIL +js1_5/decompilation/regress-383721: PASS || FAIL +js1_5/decompilation/regress-406555: PASS || FAIL + + +[ $FAST == yes ] + +# These tests take an unreasonable amount of time so we skip them +# in fast mode. + +js1_5/Regress/regress-312588: SKIP +js1_5/Regress/regress-271716-n: SKIP + +[ $FAST == yes && $ARCH == arm ] + +# In fast mode on arm we try to skip all tests that would time out, +# since running the tests takes so long in the first place. + +js1_5/Regress/regress-280769-2: SKIP +js1_5/Regress/regress-280769-3: SKIP +js1_5/Regress/regress-244470: SKIP +js1_5/Regress/regress-203278-1: SKIP +js1_5/Regress/regress-290575: SKIP +js1_5/Regress/regress-159334: SKIP +js1_5/Regress/regress-321971: SKIP +js1_5/Regress/regress-347306-01: SKIP +js1_5/Regress/regress-280769-1: SKIP +js1_5/Regress/regress-280769-5: SKIP +js1_5/GC/regress-306788: SKIP +js1_5/GC/regress-203278-2: SKIP +js1_5/GC/regress-278725: SKIP +js1_5/GC/regress-203278-3: SKIP +js1_5/GC/regress-311497: SKIP +js1_5/Array/regress-99120-02: SKIP +ecma/Date/15.9.5.22-1: SKIP +ecma/Date/15.9.5.20: SKIP +ecma/Date/15.9.5.12-2: SKIP +ecma/Date/15.9.5.8: SKIP +ecma/Date/15.9.5.9: SKIP +ecma/Date/15.9.5.10-2: SKIP +ecma/Date/15.9.5.11-2: SKIP +ecma/Expressions/11.7.2: SKIP +ecma/Expressions/11.10-2: SKIP +ecma/Expressions/11.7.3: SKIP +ecma/Expressions/11.10-3: SKIP +ecma/Expressions/11.7.1: SKIP +ecma_3/RegExp/regress-209067: SKIP diff --git a/test/mozilla/testcfg.py b/test/mozilla/testcfg.py new file mode 100644 index 0000000..a43ee0c --- /dev/null +++ b/test/mozilla/testcfg.py @@ -0,0 +1,125 @@ +# Copyright 2008 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER 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. + + +import os +from os.path import join, exists +import test + + +EXCLUDED = ['CVS'] + + +FRAMEWORK = """ + browser.js + shell.js + jsref.js + template.js +""".split() + + +TEST_DIRS = """ + ecma + ecma_2 + ecma_3 + js1_1 + js1_2 + js1_3 + js1_4 + js1_5 +""".split() + + +class MozillaTestCase(test.TestCase): + + def __init__(self, filename, path, context, mode, framework): + super(MozillaTestCase, self).__init__(context, path) + self.filename = filename + self.mode = mode + self.framework = framework + + def IsNegative(self): + return self.filename.endswith('-n.js') + + def GetLabel(self): + return "%s mozilla %s" % (self.mode, self.GetName()) + + def IsFailureOutput(self, output): + if output.exit_code != 0: + return True + return 'FAILED!' in output.stdout + + def GetCommand(self): + result = [self.context.GetVm(self.mode), '--expose-gc'] + result += self.framework + result.append(self.filename) + return result + + def GetName(self): + return self.path[-1] + + +class MozillaTestConfiguration(test.TestConfiguration): + + def __init__(self, context, root): + super(MozillaTestConfiguration, self).__init__(context, root) + + def ListTests(self, current_path, path, mode): + tests = [] + for test_dir in TEST_DIRS: + current_root = join(self.root, test_dir) + for root, dirs, files in os.walk(current_root): + for dotted in [x for x in dirs if x.startswith('.')]: + dirs.remove(dotted) + for excluded in EXCLUDED: + if excluded in dirs: + dirs.remove(excluded) + root_path = root[len(self.root):].split(os.path.sep) + root_path = current_path + [x for x in root_path if x] + framework = [] + for i in xrange(len(root_path)): + if i == 0: dir = root_path[1:] + else: dir = root_path[1:-i] + script = join(self.root, reduce(join, dir, ''), 'shell.js') + if exists(script): + framework.append(script) + framework.reverse() + for file in files: + if (not file in FRAMEWORK) and file.endswith('.js'): + full_path = root_path + [file[:-3]] + if self.Contains(path, full_path): + test = MozillaTestCase(join(root, file), full_path, self.context, + mode, framework) + tests.append(test) + return tests + + def GetBuildRequirements(self): + return ['sample', 'sample=shell'] + + +def GetConfiguration(context, root): + return MozillaTestConfiguration(context, root) diff --git a/tools/test.py b/tools/test.py index 17b5003..43d7804 100644 --- a/tools/test.py +++ b/tools/test.py @@ -33,6 +33,7 @@ import platform import re import subprocess import sys +import tempfile import time import utils @@ -61,7 +62,7 @@ class ProgressIndicator(object): case = test.case self.AboutToRun(case) output = case.Run() - if output.HasFailed(): + if output.UnexpectedOutput(): self.failed += 1 self.failed_tests.append(output) else: @@ -91,7 +92,7 @@ class SimpleProgressIndicator(ProgressIndicator): def Done(self): print for failed in self.failed_tests: - print "=== %s ===" % failed.test.GetName() + print "=== %s ===" % failed.test.GetLabel() print "Command: %s" % EscapeCommand(failed.command) if failed.output.stderr: print "--- stderr ---" @@ -113,11 +114,11 @@ class SimpleProgressIndicator(ProgressIndicator): class VerboseProgressIndicator(SimpleProgressIndicator): def AboutToRun(self, case): - print '%s:' % case.GetName(), + print '%s:' % case.GetLabel(), sys.stdout.flush() - def has_run(self, output): - if output.HasFailed(): + def HasRun(self, output): + if output.UnexpectedOutput(): print "FAIL" else: print "pass" @@ -128,11 +129,11 @@ class DotsProgressIndicator(SimpleProgressIndicator): def AboutToRun(self, case): pass - def has_run(self, output): + def HasRun(self, output): total = self.succeeded + self.failed if (total > 1) and (total % 50 == 1): sys.stdout.write('\n') - if output.HasFailed(): + if output.UnexpectedOutput(): sys.stdout.write('F') sys.stdout.flush() else: @@ -147,19 +148,19 @@ class CompactProgressIndicator(ProgressIndicator): self.templates = templates self.last_status_length = 0 self.start_time = time.time() - + def Starting(self): pass - + def Done(self): self.PrintProgress('Done') - + def AboutToRun(self, case): - self.PrintProgress(case.GetName()) - + self.PrintProgress(case.GetLabel()) + def HasRun(self, output): - if output.HasFailed(): - print "\n--- Failed: %s ---" % str(output.test.GetName()) + if output.UnexpectedOutput(): + print "\n--- Failed: %s ---" % str(output.test.GetLabel()) print "Command: %s" % EscapeCommand(output.command) stdout = output.output.stdout.strip() if len(stdout): @@ -200,7 +201,7 @@ class ColorProgressIndicator(CompactProgressIndicator): 'stderr': "\033[31m%s\033[0m", } super(ColorProgressIndicator, self).__init__(cases, templates) - + def ClearLine(self, last_line_length): print "\033[1K\r", @@ -216,7 +217,7 @@ class MonochromeProgressIndicator(CompactProgressIndicator): 'max_length': 78 } super(MonochromeProgressIndicator, self).__init__(cases, templates) - + def ClearLine(self, last_line_length): print ("\r" + (" " * last_line_length) + "\r"), @@ -244,12 +245,19 @@ class CommandOutput(object): class TestCase(object): - def __init__(self, path): + def __init__(self, context, path): self.path = path + self.context = context + + def IsNegative(self): + return False + + def IsFailureOutput(self, output): + return output.exit_code != 0 def Run(self): command = self.GetCommand() - output = Execute(command) + output = Execute(command, self.context) return TestOutput(self, command, output) @@ -260,27 +268,66 @@ class TestOutput(object): self.command = command self.output = output + def UnexpectedOutput(self): + if self.HasFailed(): + outcome = FAIL + else: + outcome = PASS + return not outcome in self.test.outcomes + def HasFailed(self): - return self.output.exit_code != 0 + execution_failed = self.test.IsFailureOutput(self.output) + if self.test.IsNegative(): + return not execution_failed + else: + return execution_failed + + +MAX_SLEEP_TIME = 0.1 +INITIAL_SLEEP_TIME = 0.0001 +SLEEP_TIME_FACTOR = 1.25 -def Execute(args): - if VERBOSE: print " ".join(args) +def RunProcess(context, **args): + if context.verbose: print "#", " ".join(args['args']) process = subprocess.Popen( + shell = (platform.system() == 'Windows'), + **args + ) + exit_code = None + sleep_time = INITIAL_SLEEP_TIME + while exit_code is None: + exit_code = process.poll() + time.sleep(sleep_time) + sleep_time = sleep_time * SLEEP_TIME_FACTOR + if sleep_time > MAX_SLEEP_TIME: + sleep_time = MAX_SLEEP_TIME + return (process, exit_code) + + +def Execute(args, context): + (fd_out, outname) = tempfile.mkstemp() + (fd_err, errname) = tempfile.mkstemp() + (process, exit_code) = RunProcess( + context, args = args, - stdout = subprocess.PIPE, - stderr = subprocess.PIPE + stdout = fd_out, + stderr = fd_err, ) - exit_code = process.wait() - output = process.stdout.read() - errors = process.stderr.read() + os.close(fd_out) + os.close(fd_err) + output = file(outname).read() + errors = file(errname).read() + os.unlink(outname) + os.unlink(errname) return CommandOutput(exit_code, output, errors) -def ExecuteNoCapture(args): - if VERBOSE: print " ".join(args) - process = subprocess.Popen(args = args) - exit_code = process.wait() +def ExecuteNoCapture(args, context): + (process, exit_code) = RunProcess( + context, + args = args, + ) return CommandOutput(exit_code, "", "") @@ -297,6 +344,14 @@ class TestConfiguration(object): self.context = context self.root = root + def Contains(self, path, file): + if len(path) > len(file): + return False + for i in xrange(len(path)): + if not path[i].match(file[i]): + return False + return True + class TestSuite(object): @@ -346,7 +401,7 @@ class LiteralTestSuite(TestSuite): (name, rest) = CarCdr(path) result = [ ] for test in self.tests: - if not name or name == test.GetName(): + if not name or name.match(test.GetName()): result += test.GetBuildRequirements(rest, context) return result @@ -355,29 +410,42 @@ class LiteralTestSuite(TestSuite): result = [ ] for test in self.tests: test_name = test.GetName() - if not name or name == test_name: + if not name or name.match(test_name): full_path = current_path + [test_name] - result += test.ListTests(full_path, rest, context, mode) + result += test.ListTests(full_path, path, context, mode) return result +PREFIX = {'debug': '_g', 'release': ''} + + class Context(object): - def __init__(self, workspace, buildspace, vm): + def __init__(self, workspace, buildspace, verbose, vm, timeout): self.workspace = workspace self.buildspace = buildspace - self.vm = vm - + self.verbose = verbose + self.vm_root = vm + self.timeout = timeout + + def GetVm(self, mode): + name = self.vm_root + PREFIX[mode] + if platform.system() == 'Windows': + return name + '.exe' + else: + return name def RunTestCases(all_cases, progress): - cases_to_run = [ c for c in all_cases if not SKIP in c.outcomes ] + def DoSkip(case): + return SKIP in c.outcomes or SLOW in c.outcomes + cases_to_run = [ c for c in all_cases if not DoSkip(c) ] progress = PROGRESS_INDICATORS[progress](cases_to_run) progress.Run() -def BuildRequirements(workspace, requirements, mode): - command_line = ['scons', '-Y', workspace, 'mode=' + ",".join(mode)] + requirements - output = ExecuteNoCapture(command_line) +def BuildRequirements(context, requirements, mode): + command_line = ['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)] + requirements + output = ExecuteNoCapture(command_line, context) return output.exit_code == 0 @@ -392,6 +460,7 @@ PASS = 'pass' OKAY = 'okay' TIMEOUT = 'timeout' CRASH = 'crash' +SLOW = 'slow' class Expression(object): @@ -424,7 +493,7 @@ class Outcome(Expression): def GetOutcomes(self, env, defs): if self.name in defs: - return defs[self.name].get_outcomes(env, defs) + return defs[self.name].GetOutcomes(env, defs) else: return ListSet([self.name]) @@ -437,7 +506,7 @@ class ListSet(Set): def __init__(self, elms): self.elms = elms - + def __str__(self): return "ListSet%s" % str(self.elms) @@ -450,7 +519,7 @@ class ListSet(Set): if not isinstance(that, ListSet): return that.Union(self) return ListSet(self.elms + [ x for x in that.elms if x not in self.elms ]) - + def IsEmpty(self): return len(self.elms) == 0 @@ -462,7 +531,7 @@ class Everything(Set): def Union(self, that): return self - + def IsEmpty(self): return False @@ -474,7 +543,7 @@ class Nothing(Set): def Union(self, that): return that - + def IsEmpty(self): return True @@ -527,7 +596,7 @@ class Tokenizer(object): self.tokens = None def Current(self, length = 1): - if not self.has_more(length): return "" + if not self.HasMore(length): return "" return self.expr[self.index:self.index+length] def HasMore(self, length = 1): @@ -540,7 +609,7 @@ class Tokenizer(object): self.tokens.append(token) def SkipSpaces(self): - while self.HasMore() and self.current().isspace(): + while self.HasMore() and self.Current().isspace(): self.Advance() def Tokenize(self): @@ -552,7 +621,7 @@ class Tokenizer(object): if self.Current() == '(': self.AddToken('(') self.Advance() - elif self.current() == ')': + elif self.Current() == ')': self.AddToken(')') self.Advance() elif self.Current() == '$': @@ -670,7 +739,7 @@ def ParseLogicalExpression(scan): def ParseCondition(expr): """Parses a logical expression into an Expression object""" - tokens = Tokenizer(expr).tokenize() + tokens = Tokenizer(expr).Tokenize() if not tokens: print "Malformed expression: '%s'" % expr return None @@ -705,8 +774,11 @@ class Configuration(object): matches = [ r for r in all_rules if r.Contains(case.path) ] outcomes = set([]) for rule in matches: - outcomes = outcomes.Union(rule.GetOutcomes(env, self.defs)) + outcomes = outcomes.union(rule.GetOutcomes(env, self.defs)) unused_rules.discard(rule) + if not outcomes: + outcomes = [PASS] + case.outcomes = outcomes result.append(ClassifiedTest(case, outcomes)) return (result, list(unused_rules)) @@ -727,7 +799,8 @@ class Rule(object): """A single rule that specifies the expected outcome for a single test.""" - def __init__(self, path, value): + def __init__(self, raw_path, path, value): + self.raw_path = raw_path self.path = path self.value = value @@ -735,24 +808,26 @@ class Rule(object): set = self.value.GetOutcomes(env, defs) assert isinstance(set, ListSet) return set.elms - + def Contains(self, path): if len(self.path) > len(path): return False for i in xrange(len(self.path)): - if path[i] != self.path[i]: + if not self.path[i].match(path[i]): return False return True HEADER_PATTERN = re.compile(r'\[([^]]+)\]') -RULE_PATTERN = re.compile(r'\s*(%?)([^: ]*)\s*:(.*)') +RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)') DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$') +PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$') def ReadConfigurationInto(path, sections, defs): current_section = Section(Constant(True)) sections.append(current_section) + prefix = [] for line in utils.ReadLinesFrom(path): header_match = HEADER_PATTERN.match(line) if header_match: @@ -764,12 +839,12 @@ def ReadConfigurationInto(path, sections, defs): continue rule_match = RULE_PATTERN.match(line) if rule_match: - path = SplitPath(rule_match.group(2).strip()) - value_str = rule_match.group(3).strip() + path = prefix + SplitPath(rule_match.group(1).strip()) + value_str = rule_match.group(2).strip() value = ParseCondition(value_str) if not value: return False - current_section.AddRule(Rule(path, value)) + current_section.AddRule(Rule(rule_match.group(1), path, value)) continue def_match = DEF_PATTERN.match(line) if def_match: @@ -779,6 +854,10 @@ def ReadConfigurationInto(path, sections, defs): return False defs[name] = value continue + prefix_match = PREFIX_PATTERN.match(line) + if prefix_match: + prefix = SplitPath(prefix_match.group(1).strip()) + continue print "Malformed line: '%s'." % line return False return True @@ -800,8 +879,8 @@ def ReadConfiguration(paths): def BuildOptions(): result = optparse.OptionParser() - result.add_option("-m", "--mode", help="The test mode in which to run", - choices=['release', 'debug']) + result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)", + default='release') result.add_option("-v", "--verbose", help="Verbose output", default=False, action="store_true") result.add_option("-p", "--progress", @@ -814,27 +893,31 @@ def BuildOptions(): default=False, action="store_true") result.add_option("--report", help="Print a summary of the tests to be run", default=False, action="store_true") + result.add_option("-s", "--suite", help="A test suite", + default=[], action="append") + result.add_option("-t", "--timeout", help="Timeout in seconds", + default=60, type="int") return result def ProcessOptions(options): global VERBOSE VERBOSE = options.verbose - mode = options.mode - if mode == 'all': mode = ['release', 'debug'] - elif not mode: mode = ['release'] - else: mode = [mode] - options.mode = mode + options.mode = options.mode.split(',') + for mode in options.mode: + if not mode in ['debug', 'release']: + print "Unknown mode %s" % mode + return False return True REPORT_TEMPLATE = """\ Total: %(total)i tests - * %(skipped)3d tests will be skipped - * %(nocrash)3d tests are expected to be flaky but not crash - * %(pass)3d tests are expected to pass - * %(fail_ok)3d tests are expected to fail that we won't fix - * %(fail)3d tests are expected to fail that we should fix\ + * %(skipped)4d tests will be skipped + * %(nocrash)4d tests are expected to be flaky but not crash + * %(pass)4d tests are expected to pass + * %(fail_ok)4d tests are expected to fail that we won't fix + * %(fail)4d tests are expected to fail that we should fix\ """ def PrintReport(cases): @@ -853,9 +936,28 @@ def PrintReport(cases): } +class Pattern(object): + + def __init__(self, pattern): + self.pattern = pattern + self.compiled = None + + def match(self, str): + if not self.compiled: + pattern = "^" + self.pattern.replace('*', '.*') + "$" + self.compiled = re.compile(pattern) + return self.compiled.match(str) + + def __str__(self): + return self.pattern + + def SplitPath(s): stripped = [ c.strip() for c in s.split('/') ] - return [ s for s in stripped if len(s) > 0 ] + return [ Pattern(s) for s in stripped if len(s) > 0 ] + + +BUILT_IN_TESTS = ['mjsunit', 'cctest'] def Main(): @@ -869,11 +971,12 @@ def Main(): return 1 workspace = abspath(join(dirname(sys.argv[0]), '..')) - tests = ['mjsunit'] - repositories = [TestRepository(join(workspace, 'test', name)) for name in tests] + repositories = [TestRepository(join(workspace, 'test', name)) for name in BUILT_IN_TESTS] + repositories += [TestRepository(a) for a in options.suite] + root = LiteralTestSuite(repositories) if len(args) == 0: - paths = [[]] + paths = [SplitPath(t) for t in BUILT_IN_TESTS] else: paths = [ ] for arg in args: @@ -882,36 +985,45 @@ def Main(): # First build the required targets buildspace = abspath('.') - context = Context(workspace, buildspace, join(buildspace, 'shell')) + context = Context(workspace, buildspace, VERBOSE, + join(buildspace, 'shell'), + options.timeout) if not options.no_build: reqs = [ ] for path in paths: reqs += root.GetBuildRequirements(path, context) reqs = list(set(reqs)) if len(reqs) > 0: - if not BuildRequirements(workspace, reqs, options.mode): + if not BuildRequirements(context, reqs, options.mode): return 1 # Then list the tests - cases = [ ] + all_cases = [ ] + all_unused = [ ] for path in paths: for mode in options.mode: - cases += root.ListTests([], path, context, mode) + env = { + 'mode': mode + } + test_list = root.ListTests([], path, context, mode) + (cases, unused_rules) = config.ClassifyTests(test_list, env) + all_cases += cases + all_unused.append(unused_rules) - env = { } - (cases, unused_rules) = config.ClassifyTests(cases, env) +# for rule in unused_rules: +# print "Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path]) - for rule in unused_rules: - print "Rule for '%s' was not used." % "/".join(rule.path) - return 0 - if options.report: - PrintReport(cases) - - if len(cases) == 0: + PrintReport(all_cases) + + if len(all_cases) == 0: print "No tests to run." else: - RunTestCases(cases, options.progress) + try: + RunTestCases(all_cases, options.progress) + except KeyboardInterrupt: + print "Interrupted" + return 1 return 0 -- 2.7.4