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'))
'gcc': {
'all': {
'DIALECTFLAGS': ['-ansi'],
- 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
+ 'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS',
+ '-fno-strict-aliasing'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
'LIBS': ['pthread']
},
'mode:release': {
'CCFLAGS': ['-O2']
},
+ 'wordsize:64': {
+ 'CCFLAGS': ['-m32']
+ },
},
'msvc': {
'all': {
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': {
'library:shared': {
'CPPDEFINES': ['BUILDING_V8_SHARED']
},
+ 'arch:arm': {
+ 'CPPDEFINES': ['ARM']
+ },
}
}
}
},
'msvc': {
+ 'all': {
+ 'CPPDEFINES': ['_HAS_EXCEPTIONS=0']
+ },
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
}
elif id == 'Windows':
return 'win32'
else:
- return '<none>'
+ 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 '<none>'
+ return None
+
+
+def GuessWordsize():
+ if '64' in platform.machine():
+ return '64'
+ else:
+ return '32'
def GuessToolchain(os):
elif 'msvc' in tools:
return 'msvc'
else:
- return '<none>'
+ 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
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:
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,
)
# 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.
*/
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();
// Initialize this processor. The map contains options that control
// how requests should be processed.
virtual bool Initialize(map<string, string>* options,
- map<string, string>* output) = 0;
+ map<string, string>* output) = 0;
// Process a single request.
virtual bool Process(HttpRequest* req) = 0;
// Creates a new processor that processes requests by invoking the
// Process function of the JavaScript script given as an argument.
- JsHttpRequestProcessor(Handle<String> script) : script_(script) { }
+ explicit JsHttpRequestProcessor(Handle<String> script) : script_(script) { }
virtual ~JsHttpRequestProcessor();
virtual bool Initialize(map<string, string>* opts,
- map<string, string>* output);
+ map<string, string>* 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<String> script);
// Wrap the options and output map in a JavaScript objects and
// Callbacks that access maps
static Handle<Value> MapGet(Local<String> name, const AccessorInfo& info);
- static Handle<Value> MapSet(Local<String> name, Local<Value> value,
- const AccessorInfo& info);
+ static Handle<Value> MapSet(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info);
// Utility methods for wrapping C++ objects as JavaScript objects,
// and going back again.
// Execute the script and fetch the Process method.
bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
- map<string, string>* output) {
+ map<string, string>* output) {
// Create a handle scope to hold the temporary references.
HandleScope handle_scope;
bool JsHttpRequestProcessor::InstallMaps(map<string, string>* opts,
- map<string, string>* output) {
+ map<string, string>* output) {
HandleScope handle_scope;
// Wrap the map object in a JavaScript wrapper
Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name,
- const AccessorInfo& info) {
+ const AccessorInfo& info) {
// Fetch the map wrapped by this object.
map<string, string>* obj = UnwrapMap(info.Holder());
Handle<Value> JsHttpRequestProcessor::MapSet(Local<String> name,
- Local<Value> value_obj, const AccessorInfo& info) {
+ Local<Value> value_obj,
+ const AccessorInfo& info) {
// Fetch the map wrapped by this object.
map<string, string>* obj = UnwrapMap(info.Holder());
Handle<Value> JsHttpRequestProcessor::GetPath(Local<String> name,
- const AccessorInfo& info) {
+ const AccessorInfo& info) {
// Extract the C++ request object from the JavaScript wrapper.
HttpRequest* request = UnwrapRequest(info.Holder());
Handle<Value> JsHttpRequestProcessor::GetReferrer(Local<String> 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());
Handle<Value> JsHttpRequestProcessor::GetHost(Local<String> 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());
Handle<Value> JsHttpRequestProcessor::GetUserAgent(Local<String> 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());
*/
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_; }
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<string, string>& options,
- string* file) {
+void ParseOptions(int argc,
+ char* argv[],
+ map<string, string>& options,
+ string* file) {
for (int i = 1; i < argc; i++) {
string arg = argv[i];
int index = arg.find('=', 0);
bool ProcessEntries(HttpRequestProcessor* processor, int count,
- StringHttpRequest* reqs) {
+ StringHttpRequest* reqs) {
for (int i = 0; i < count; i++) {
if (!processor->Process(&reqs[i]))
return false;
#include <v8.h>
#include <cstring>
#include <cstdio>
+#include <cstdlib>
void RunShell(v8::Handle<v8::Context> context);
v8::Handle<v8::Value> name,
bool print_result);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
+v8::Handle<v8::Value> Load(const v8::Arguments& args);
+v8::Handle<v8::Value> Quit(const v8::Arguments& args);
+v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::String> 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<v8::ObjectTemplate> 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<v8::Context> context = v8::Context::New(NULL, global);
// Enter the newly created execution environment.
v8::Context::Scope context_scope(context);
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;
}
+// The callback that is invoked by v8 whenever the JavaScript 'load'
+// function is called. Loads, compiles and executes its argument
+// JavaScript file.
+v8::Handle<v8::Value> 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<v8::String> 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<v8::Value> 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<v8::Value> Version(const v8::Arguments& args) {
+ return v8::String::New(v8::V8::GetVersion());
+}
+
+
// Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(const char* name) {
FILE* file = fopen(name, "rb");
}
}
}
-
-
-// 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]));
- }
- }
-}
],
'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'],
}
+void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
+ i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
+}
+
+
v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) {
if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>();
i::Top::ScheduleThrow(*Utils::OpenHandle(*value));
-// 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_
-// 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"
-// 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
// Add prototype.
PropertyAttributes attributes = static_cast<PropertyAttributes>(
- (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,
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
}
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.
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<JSFunction> function =
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";
}
}
__ 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()));
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);
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
}
+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<Object> value,
bool reversed) {
// 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;
}
Handle<JSObject> Factory::NewObjectLiteral(int expected_number_of_properties) {
Handle<Map> map = Handle<Map>(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);
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
- if (array->length() > 0) {
+ if (!array->IsEmpty()) {
map->set_instance_descriptors(*array);
}
SYMBOL_LIST(SYMBOL_ACCESSOR)
#undef SYMBOL_ACCESSOR
- static Handle<DescriptorArray> empty_descriptor_array() {
- return Handle<DescriptorArray>::cast(empty_fixed_array());
- }
-
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,
// 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
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
};
}
-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
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);
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<DescriptorArray*>(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.
if (obj->IsFailure()) return false;
shared_function_info_map_ = Map::cast(obj);
+ ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
return true;
}
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.
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.
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) \
// 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,
JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint();
break;
case JS_VALUE_TYPE:
+ PrintF("Value wrapper around:");
JSValue::cast(this)->value()->Print();
break;
case CODE_TYPE:
}
+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));
} 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);
// 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();
}
case INTERCEPTOR:
return SetPropertyWithInterceptor(name, value, NONE);
case CONSTANT_TRANSITION:
+ case NULL_DESCRIPTOR:
+ UNREACHABLE();
break;
}
}
case INTERCEPTOR:
return result->holder()->
GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
+ case MAP_TRANSITION:
+ case CONSTANT_TRANSITION:
+ case NULL_DESCRIPTOR:
+ return ABSENT;
default:
+ UNREACHABLE();
break;
}
}
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;
}
}
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);
}
+#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;
}
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),
// 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);
}
+#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<StringInputBuffer> string_input_buffer;
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);
}
}
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);
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<uint32_t>(new_capacity) > index);
Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
if (obj->IsFailure()) return obj;
}
// 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));
}
-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.
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();
}
}
}
ASSERT(!storage || storage->length() >= counter);
} else {
- if (storage)
+ if (storage) {
element_dictionary()->CopyKeysTo(storage, filter);
+ }
counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
}
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.
}
// 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;
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);
}
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;
// - Array
// - ByteArray
// - FixedArray
+// - DescriptorArray
// - HashTable
// - Dictionary
// - SymbolTable
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_); }
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,
// 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();
static const uint32_t kMaxGap = 1024;
static const int kMaxFastElementsLength = 5000;
+ static const int kMaxFastProperties = 8;
// Layout description.
static const int kPropertiesOffset = HeapObject::kSize;
#ifdef DEBUG
void FixedArrayPrint();
void FixedArrayVerify();
+ // Checks if two FixedArrays have identical contents.
+ bool IsEqualTo(FixedArray* other);
#endif
// Swap two elements.
//
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();
// 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() {
// 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.
// 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
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
if (is_pre_parsing_) return NULL;
- Handle<FixedArray> constant_properties = (number_of_constant_properties == 0)
- ? Factory::empty_fixed_array()
- : Factory::NewFixedArray(number_of_constant_properties*2, TENURED);
+ Handle<FixedArray> 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);
case CONSTANT_TRANSITION:
PrintF(" -type = constant property transition\n");
break;
+ case NULL_DESCRIPTOR:
+ PrintF(" =type = null descriptor\n");
+ break;
}
}
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()); }
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);
}
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
}
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<uint32_t>(subject->length()))
- return Heap::nan_value();
+ if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
return Smi::FromInt(subject->Get(i));
}
return *value;
}
+ HandleScope scope;
+
// Handlify object and value before calling into JavaScript again.
Handle<JSObject> object_handle = Handle<JSObject>::cast(object);
Handle<Object> value_handle = value;
// Call-back into JavaScript to convert the key to a string.
- HandleScope scope;
bool has_pending_exception = false;
Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
if (has_pending_exception) return Failure::Exception();
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) {
template <class Converter>
static Object* ConvertCase(Arguments args,
- unibrow::Mapping<Converter, 128> *mapping) {
+ unibrow::Mapping<Converter, 128>* mapping) {
NoHandleAllocation ha;
CONVERT_CHECKED(String, s, args[0]);
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<StringInputBuffer> buffer(&string_input_buffer);
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));
}
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();
return Failure::OutOfMemoryException();
}
position += element_length;
- if (ascii && !element->IsAscii())
+ if (ascii && !element->IsAscii()) {
ascii = false;
+ }
} else {
return Top::Throw(Heap::illegal_argument_symbol());
}
// 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();
}
-
-
// 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
if (throw_error) {
// The property doesn't exist - throw exception.
Handle<Object> 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
Handle<Object> value(args[0]);
CONVERT_ARG_CHECKED(Context, context, 1);
- Handle<String> name(String::cast(args[2]));
+ CONVERT_ARG_CHECKED(String, name, 2);
int index;
PropertyAttributes attributes;
CONVERT_CHECKED(JSArray, raw_array, args[0]);
Handle<JSArray> 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<FixedArray> keys = GetKeysInFixedArrayFor(array);
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();
}
CONVERT_ARG_CHECKED(String, name, 1);
PropertyAttributes attributes;
- Object* result = obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
- return result;
+ return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
}
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);
}
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.
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());
}
%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);
// (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 <v8.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#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<char *>(file), '/');
if (!basename) {
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;
}
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_;
};
// 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<v8::ObjectTemplate> global_template =
v8::Handle<v8::ObjectTemplate>(),
: context_(v8::Context::New(extensions, global_template, global_object)) {
context_->Enter();
}
- inline ~LocalContext() {
+ inline ~DebugLocalContext() {
context_->Exit();
context_.Dispose();
}
// Compile and run the supplied source and return the fequested function.
-static v8::Local<v8::Function> CompileFunction(LocalContext* env,
+static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
const char* source,
const char* function_name) {
v8::Script::Compile(v8::String::New(source))->Run();
// 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) {
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
// debugged.
TEST(DebugInfo) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
// Create a couple of functions for the test.
v8::Local<v8::Function> foo =
CompileFunction(&env, "function foo(){}", "foo");
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();
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();
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();
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();
TEST(GCDuringBreakPointProcessing) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointCollectGarbage,
v8::Undefined());
TEST(BreakPointSurviveGC) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
TEST(BreakPointThroughJavaScript) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ScriptBreakPointThroughJavaScript) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(EnableDisableScriptBreakPoint) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ConditionalScriptBreakPoint) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ScriptBreakPointIgnoreCount) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ScriptBreakPointReload) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ScriptBreakPointMultiple) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
TEST(ScriptBreakPointLineOffset) {
break_point_hit_count = 0;
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
// 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.
// inside the break handling of that break point.
TEST(RemoveBreakPointInBreak) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
v8::Local<v8::Function> foo =
CompileFunction(&env, "function foo(){a=1;}", "foo");
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();
// 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.
// 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<v8::Function> foo = CompileFunction(&env,
// Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(&env,
TEST(DebugStepIf) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
TEST(DebugStepSwitch) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
TEST(DebugStepFor) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
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,
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,
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,
// 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<v8::Function> foo = CompileFunction(
// for them.
TEST(BreakOnException) {
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
v8::internal::Top::TraceException(false);
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,
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.
// 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);
TEST(InterceptorPropertyMirror) {
// Create a V8 environment with debug access.
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
env.ExposeDebug();
// Create object with named interceptor.
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();
const char* source_2 = "foo();\n";
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
CompileRun(source_1);
"cat(19);\n";
v8::HandleScope scope;
- LocalContext env;
+ DebugLocalContext env;
v8::Debug::SetMessageHandler(&BreakpointsMessageHandler);
CompileRun(source_1);
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<char **>(argv),
true));
- CHECK_EQ(3, argc);
+ CHECK_EQ(2, argc);
}
--- /dev/null
+# 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)
// (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
// 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.
// 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.
assertEquals(Debug.scriptSource(f), Debug.scriptSource(g));
f();
g();
-
-assertEquals("function print() { [native code] }", print);
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);
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');
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');
// (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.
--- /dev/null
+// 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);
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
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):
--- /dev/null
+# 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 <global>.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 <xml> 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
--- /dev/null
+# 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)
import re
import subprocess
import sys
+import tempfile
import time
import utils
case = test.case
self.AboutToRun(case)
output = case.Run()
- if output.HasFailed():
+ if output.UnexpectedOutput():
self.failed += 1
self.failed_tests.append(output)
else:
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 ---"
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"
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:
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):
'stderr': "\033[31m%s\033[0m",
}
super(ColorProgressIndicator, self).__init__(cases, templates)
-
+
def ClearLine(self, last_line_length):
print "\033[1K\r",
'max_length': 78
}
super(MonochromeProgressIndicator, self).__init__(cases, templates)
-
+
def ClearLine(self, last_line_length):
print ("\r" + (" " * last_line_length) + "\r"),
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)
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, "", "")
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):
(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
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
OKAY = 'okay'
TIMEOUT = 'timeout'
CRASH = 'crash'
+SLOW = 'slow'
class Expression(object):
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])
def __init__(self, elms):
self.elms = elms
-
+
def __str__(self):
return "ListSet%s" % str(self.elms)
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
def Union(self, that):
return self
-
+
def IsEmpty(self):
return False
def Union(self, that):
return that
-
+
def IsEmpty(self):
return True
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):
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):
if self.Current() == '(':
self.AddToken('(')
self.Advance()
- elif self.current() == ')':
+ elif self.Current() == ')':
self.AddToken(')')
self.Advance()
elif self.Current() == '$':
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
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))
"""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
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:
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:
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
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",
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):
}
+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():
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:
# 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