Changed shell sample to take flags directly from the command-line. Added api call that implements this.

Added better test support.

Added load, quit and version functions to the shell sample so it's easier to run benchmarks and tests.



git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
christian.plesner.hansen 2008-08-27 10:11:39 +00:00
parent c42f5829a1
commit 05bbf90b3a
42 changed files with 2113 additions and 666 deletions

View File

@ -28,6 +28,7 @@
import platform
import re
import sys
import os
from os.path import join, dirname, abspath
root_dir = dirname(File('SConstruct').rfile().abspath)
sys.path.append(join(root_dir, 'tools'))
@ -41,7 +42,8 @@ LIBRARY_FLAGS = {
'gcc': {
'all': {
'DIALECTFLAGS': ['-ansi'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS',
'-fno-strict-aliasing'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
'LIBS': ['pthread']
},
@ -52,6 +54,9 @@ LIBRARY_FLAGS = {
'mode:release': {
'CCFLAGS': ['-O2']
},
'wordsize:64': {
'CCFLAGS': ['-m32']
},
},
'msvc': {
'all': {
@ -83,10 +88,13 @@ LIBRARY_FLAGS = {
V8_EXTRA_FLAGS = {
'gcc': {
'all': {
'CXXFLAGS': ['-fvisibility=hidden'],
'CXXFLAGS': [], #['-fvisibility=hidden'],
'WARNINGFLAGS': ['-pedantic', '-Wall', '-Werror', '-W',
'-Wno-unused-parameter']
},
'arch:arm': {
'CPPDEFINES': ['ARM']
},
},
'msvc': {
'all': {
@ -95,6 +103,9 @@ V8_EXTRA_FLAGS = {
'library:shared': {
'CPPDEFINES': ['BUILDING_V8_SHARED']
},
'arch:arm': {
'CPPDEFINES': ['ARM']
},
}
}
@ -143,6 +154,9 @@ CCTEST_EXTRA_FLAGS = {
}
},
'msvc': {
'all': {
'CPPDEFINES': ['_HAS_EXCEPTIONS=0']
},
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
}
@ -198,17 +212,24 @@ def GuessOS():
elif id == 'Windows':
return 'win32'
else:
return '<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):
@ -218,21 +239,61 @@ 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
@ -252,51 +313,46 @@ def IsLegal(env, option, values):
def VerifyOptions(env):
if not IsLegal(env, 'mode', ['debug', 'release']):
return False
if not env['toolchain'] in ['gcc', 'msvc']:
Abort("Unknown toolchain '%s'." % env['toolchain'])
if not env['os'] in ['linux', 'macos', 'win32']:
Abort("Unknown os '%s'." % env['os'])
if not env['processor'] in ['arm', 'ia32']:
Abort("Unknown processor '%s'." % env['processor'])
if not env['snapshot'] in ['on', 'off']:
Abort("Illegal value for option snapshot: '%s'." % env['snapshot'])
if not env['library'] in ['static', 'shared', 'default']:
Abort("Illegal value for option library: '%s'." % env['library'])
if not IsLegal(env, 'sample', ["shell", "process"]):
return False
for (name, option) in SIMPLE_OPTIONS.items():
if (not option.get('default')) and (name not in ARGUMENTS):
message = ("A value for option %s must be specified (%s)." %
(name, ", ".join(option['values'])))
Abort(message)
if not env[name] in option['values']:
message = ("Unknown %s value '%s'. Possible values are (%s)." %
(name, env[name], ", ".join(option['values'])))
Abort(message)
class BuildContext(object):
def __init__(self, os, arch, toolchain, snapshot, library, samples, mode):
def __init__(self, options, samples):
self.library_targets = []
self.cctest_targets = []
self.sample_targets = []
self.os = os
self.arch = arch
self.toolchain = toolchain
self.snapshot = snapshot
self.library = library
self.options = options
self.samples = samples
self.mode = mode
self.use_snapshot = (snapshot == 'on')
self.use_snapshot = (options['snapshot'] == 'on')
self.flags = None
def AddRelevantFlags(self, initial, flags):
result = initial.copy()
self.AppendFlags(result, flags.get('all'))
self.AppendFlags(result, flags[self.toolchain].get('all'))
self.AppendFlags(result, flags[self.toolchain].get('mode:' + self.mode))
self.AppendFlags(result, flags[self.toolchain].get('library:' + self.library))
toolchain = self.options['toolchain']
self.AppendFlags(result, flags[toolchain].get('all'))
for option in sorted(self.options.keys()):
value = self.options[option]
self.AppendFlags(result, flags[toolchain].get(option + ':' + value))
return result
def GetRelevantSources(self, source):
result = []
result += source.get('all', [])
result += source.get('arch:' + self.arch, [])
result += source.get('os:' + self.os, [])
result += source.get('mode:' + self.mode, [])
return result
for (name, value) in self.options.items():
result += source.get(name + ':' + value, [])
return sorted(result)
def AppendFlags(self, options, added):
if not added:
@ -306,28 +362,39 @@ class BuildContext(object):
options[key] = value
else:
options[key] = options[key] + value
def ConfigureObject(self, env, input, **kw):
if self.library == 'static':
if self.options['library'] == 'static':
return env.StaticObject(input, **kw)
elif self.library == 'shared':
elif self.options['library'] == 'shared':
return env.SharedObject(input, **kw)
else:
return env.Object(input, **kw)
def 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)
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']
library_flags = context.AddRelevantFlags({}, LIBRARY_FLAGS)
def BuildSpecific(env, 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(os.environ, LIBRARY_FLAGS)
v8_flags = context.AddRelevantFlags(library_flags, V8_EXTRA_FLAGS)
jscre_flags = context.AddRelevantFlags(library_flags, JSCRE_EXTRA_FLAGS)
dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS)
cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS)
sample_flags = context.AddRelevantFlags({}, SAMPLE_FLAGS)
sample_flags = context.AddRelevantFlags(os.environ, SAMPLE_FLAGS)
context.flags = {
'v8': v8_flags,
@ -351,9 +418,9 @@ def BuildSpecific(env, mode):
)
# Link the object files into a library.
if context.library == 'static':
if context.options['library'] == 'static':
library = env.StaticLibrary(library_name, object_files)
elif context.library == 'shared':
elif context.options['library'] == 'shared':
# There seems to be a glitch in the way scons decides where to put
# PDB files when compiling using MSVC so we specify it manually.
# This should not affect any other platforms.

View File

@ -1673,6 +1673,14 @@ class EXPORT V8 {
*/
static void SetFlagsFromString(const char* str, int length);
/**
* Sets v8 flags from command line.
* TODO(758124): Describe flags?
*/
static void SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags);
/** Get the version string. */
static const char* GetVersion();

View File

@ -62,7 +62,7 @@ class HttpRequestProcessor {
// 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;
@ -78,17 +78,17 @@ class JsHttpRequestProcessor : public HttpRequestProcessor {
// Creates a new processor that processes requests by invoking the
// Process function of the JavaScript script given as an argument.
JsHttpRequestProcessor(Handle<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
@ -108,8 +108,9 @@ class JsHttpRequestProcessor : public HttpRequestProcessor {
// 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.
@ -142,7 +143,7 @@ static Handle<Value> LogCallback(const Arguments& args) {
// 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;
@ -223,7 +224,7 @@ bool JsHttpRequestProcessor::ExecuteScript(Handle<String> script) {
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
@ -335,7 +336,7 @@ string ObjectToString(Local<Value> value) {
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());
@ -355,7 +356,8 @@ Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name,
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());
@ -433,7 +435,7 @@ HttpRequest* JsHttpRequestProcessor::UnwrapRequest(Handle<Object> obj) {
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());
@ -446,7 +448,7 @@ Handle<Value> JsHttpRequestProcessor::GetPath(Local<String> name,
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());
@ -454,7 +456,7 @@ Handle<Value> JsHttpRequestProcessor::GetReferrer(Local<String> name,
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());
@ -462,7 +464,7 @@ Handle<Value> JsHttpRequestProcessor::GetHost(Local<String> name,
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());
@ -499,8 +501,10 @@ void HttpRequestProcessor::Log(const char* event) {
*/
class StringHttpRequest : public HttpRequest {
public:
StringHttpRequest(const string& path, const string& referrer,
const string& host, const string& user_agent);
StringHttpRequest(const string& path,
const string& referrer,
const string& host,
const string& user_agent);
virtual const string& Path() { return path_; }
virtual const string& Referrer() { return referrer_; }
virtual const string& Host() { return host_; }
@ -514,15 +518,19 @@ class StringHttpRequest : public HttpRequest {
StringHttpRequest::StringHttpRequest(const string& path,
const string& referrer, const string& host, const string& user_agent)
const string& referrer,
const string& host,
const string& user_agent)
: path_(path),
referrer_(referrer),
host_(host),
user_agent_(user_agent) { }
void ParseOptions(int argc, char* argv[], map<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);
@ -571,7 +579,7 @@ StringHttpRequest kSampleRequests[kSampleSize] = {
bool ProcessEntries(HttpRequestProcessor* processor, int count,
StringHttpRequest* reqs) {
StringHttpRequest* reqs) {
for (int i = 0; i < count; i++) {
if (!processor->Process(&reqs[i]))
return false;

View File

@ -28,6 +28,7 @@
#include <v8.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
void RunShell(v8::Handle<v8::Context> context);
@ -35,18 +36,28 @@ bool ExecuteString(v8::Handle<v8::String> source,
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);
@ -55,9 +66,8 @@ int main(int argc, char* argv[]) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "--runtime-flags") == 0) {
// Skip the --runtime-flags flag since it was processed earlier.
i++;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\n", str);
} else {
// Use all other arguments as names of files to load and run.
v8::HandleScope handle_scope;
@ -93,6 +103,39 @@ v8::Handle<v8::Value> Print(const v8::Arguments& args) {
}
// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called. Loads, compiles and executes its argument
// JavaScript file.
v8::Handle<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");
@ -161,14 +204,3 @@ bool ExecuteString(v8::Handle<v8::String> source,
}
}
}
// Set the vm flags before using the vm.
void ProcessRuntimeFlags(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--runtime-flags") == 0 && i + 1 < argc) {
i++;
v8::V8::SetFlagsFromString(argv[i], strlen(argv[i]));
}
}
}

View File

@ -50,10 +50,11 @@ SOURCES = {
],
'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
'cpu-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'ic-arm.cc',
'macro-assembler-arm.cc', 'simulator-arm.cc', 'stub-cache-arm.cc'],
'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
'macro-assembler-ia32.cc', 'simulator-ia32.cc', 'stub-cache-ia32.cc'],
'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'],
'simulator:arm': ['simulator-arm.cc'],
'os:linux': ['platform-linux.cc'],
'os:macos': ['platform-macos.cc'],
'os:nullos': ['platform-nullos.cc'],

View File

@ -223,6 +223,11 @@ void V8::SetFlagsFromString(const char* str, int length) {
}
void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) {
i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags);
}
v8::Handle<Value> ThrowException(v8::Handle<v8::Value> value) {
if (IsDeadCheck("v8::ThrowException()")) return v8::Handle<Value>();
i::Top::ScheduleThrow(*Utils::OpenHandle(*value));

View File

@ -1,29 +1,38 @@
// Copyright 2007-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:
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// * 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 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.
//
// - 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.
#ifndef V8_ASSEMBLER_ARM_INL_H_
#define V8_ASSEMBLER_ARM_INL_H_

View File

@ -1,29 +1,38 @@
// Copyright 2006-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:
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// * 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 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.
//
// - 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"

View File

@ -1,29 +1,38 @@
// Copyright 2007-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:
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// * 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 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.
//
// - 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.
// A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5

View File

@ -379,9 +379,9 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
// 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,
@ -481,8 +481,8 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
global_context()->set_initial_object_prototype(*prototype);
SetPrototype(object_fun, prototype);
object_function_map->set_instance_descriptors(
DescriptorArray::cast(Heap::empty_fixed_array()));
object_function_map->
set_instance_descriptors(Heap::empty_descriptor_array());
}
// Allocate the empty function as the prototype for function ECMAScript
@ -1192,7 +1192,8 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
// Ignore map transitions.
case NULL_DESCRIPTOR:
// Ignore non-properties.
break;
case NORMAL:
// Do not occur since the from object has fast properties.

View File

@ -352,7 +352,7 @@ BUILTIN_0(HandleApiCall) {
HandleScope scope;
// TODO(1238487): This is not nice. We need to get rid of this
// retarded behavior and start handling API calls in a more direct
// kludgy behavior and start handling API calls in a more direct
// way - maybe compile specialized stubs lazily?.
#ifdef USE_OLD_CALLING_CONVENTIONS
Handle<JSFunction> function =

View File

@ -1084,6 +1084,12 @@ class GenericBinaryOpStub : public CodeStub {
case Token::SUB: return "GenericBinaryOpStub_SUB";
case Token::MUL: return "GenericBinaryOpStub_MUL";
case Token::DIV: return "GenericBinaryOpStub_DIV";
case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
case Token::SAR: return "GenericBinaryOpStub_SAR";
case Token::SHL: return "GenericBinaryOpStub_SHL";
case Token::SHR: return "GenericBinaryOpStub_SHR";
default: return "GenericBinaryOpStub";
}
}
@ -1175,75 +1181,104 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
__ bind(&exit);
break;
}
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;
}
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;
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, 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();
}
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);
const char* GetName() { return "SmiOpStub"; }
#ifdef DEBUG
void Print() {
PrintF("SmiOpStub (token %s), (reversed %s)\n",
Token::String(op_), reversed_ ? "true" : "false");
}
#endif
};
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);
}
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);
}
break;
}
default: UNREACHABLE();
}
}
void StackCheckStub::Generate(MacroAssembler* masm) {
Label within_limit;
__ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
@ -1866,7 +1901,13 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
switch (op) {
case Token::ADD: // fall through.
case Token::SUB: // fall through.
case Token::MUL: {
case Token::MUL:
case Token::BIT_OR:
case Token::BIT_AND:
case Token::BIT_XOR:
case Token::SHL:
case Token::SHR:
case Token::SAR: {
__ pop(r0); // r0 : y
__ pop(r1); // r1 : x
GenericBinaryOpStub stub(op);
@ -1886,101 +1927,6 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
break;
}
case Token::BIT_OR:
case Token::BIT_AND:
case Token::BIT_XOR: {
Label slow, exit;
__ pop(r0); // get y
__ pop(r1); // get x
// tag check
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
ASSERT(kSmiTag == 0); // adjust code below
__ tst(r2, Operand(kSmiTagMask));
__ b(ne, &slow);
switch (op) {
case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
default: UNREACHABLE();
}
__ b(&exit);
__ bind(&slow);
__ push(r1); // restore stack
__ push(r0);
__ mov(r0, Operand(1)); // 1 argument (not counting receiver).
switch (op) {
case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, CALL_JS); break;
case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, CALL_JS); break;
case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, CALL_JS); break;
default: UNREACHABLE();
}
__ bind(&exit);
break;
}
case Token::SHL:
case Token::SHR:
case Token::SAR: {
Label slow, exit;
__ pop(r0); // get y
__ pop(r1); // get x
// tag check
__ orr(r2, r1, Operand(r0)); // r2 = x | y;
ASSERT(kSmiTag == 0); // adjust code below
__ tst(r2, Operand(kSmiTagMask));
__ b(ne, &slow);
// remove tags from operands (but keep sign)
__ mov(r3, Operand(r1, ASR, kSmiTagSize));
__ mov(r2, Operand(r0, ASR, kSmiTagSize));
// use only the 5 least significant bits of the shift count
__ and_(r2, r2, Operand(0x1f));
// perform operation
switch (op) {
case Token::SAR:
__ mov(r3, Operand(r3, ASR, r2));
// no checks of result necessary
break;
case Token::SHR:
__ mov(r3, Operand(r3, LSR, r2));
// check that the *unsigned* result fits in a smi
// neither of the two high-order bits can be set:
// - 0x80000000: high bit would be lost when smi tagging
// - 0x40000000: this number would convert to negative when
// smi tagging these two cases can only happen with shifts
// by 0 or 1 when handed a valid smi
__ and_(r2, r3, Operand(0xc0000000), SetCC);
__ b(ne, &slow);
break;
case Token::SHL:
__ mov(r3, Operand(r3, LSL, r2));
// check that the *signed* result fits in a smi
__ add(r2, r3, Operand(0x40000000), SetCC);
__ b(mi, &slow);
break;
default: UNREACHABLE();
}
// tag result and store it in r0
ASSERT(kSmiTag == 0); // adjust code below
__ mov(r0, Operand(r3, LSL, kSmiTagSize));
__ b(&exit);
// slow case
__ bind(&slow);
__ push(r1); // restore stack
__ push(r0);
__ mov(r0, Operand(1)); // 1 argument (not counting receiver).
switch (op) {
case Token::SAR: __ InvokeBuiltin("SAR", 1, CALL_JS); break;
case Token::SHR: __ InvokeBuiltin("SHR", 1, CALL_JS); break;
case Token::SHL: __ InvokeBuiltin("SHL", 1, CALL_JS); break;
default: UNREACHABLE();
}
__ bind(&exit);
break;
}
case Token::COMMA:
__ pop(r0);
// simply discard left value
@ -1995,6 +1941,82 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
}
class DeferredInlinedSmiOperation: public DeferredCode {
public:
DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
int value, bool reversed) :
DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
set_comment("[ DeferredInlinedSmiOperation");
}
virtual void Generate() {
switch (op_) {
case Token::ADD: {
if (reversed_) {
// revert optimistic add
__ sub(r0, r0, Operand(Smi::FromInt(value_)));
__ mov(r1, Operand(Smi::FromInt(value_))); // x
} else {
// revert optimistic add
__ sub(r1, r0, Operand(Smi::FromInt(value_)));
__ mov(r0, Operand(Smi::FromInt(value_)));
}
break;
}
case Token::SUB: {
if (reversed_) {
// revert optimistic sub
__ rsb(r0, r0, Operand(Smi::FromInt(value_)));
__ mov(r1, Operand(Smi::FromInt(value_)));
} else {
__ add(r1, r0, Operand(Smi::FromInt(value_)));
__ mov(r0, Operand(Smi::FromInt(value_)));
}
break;
}
case Token::BIT_OR:
case Token::BIT_XOR:
case Token::BIT_AND: {
if (reversed_) {
__ mov(r1, Operand(Smi::FromInt(value_)));
} else {
__ mov(r1, Operand(r0));
__ mov(r0, Operand(Smi::FromInt(value_)));
}
break;
}
case Token::SHL:
case Token::SHR:
case Token::SAR: {
if (!reversed_) {
__ mov(r1, Operand(r0));
__ mov(r0, Operand(Smi::FromInt(value_)));
} else {
UNREACHABLE(); // should have been handled in SmiOperation
}
break;
}
default:
// other cases should have been handled before this point.
UNREACHABLE();
break;
}
GenericBinaryOpStub igostub(op_);
__ CallStub(&igostub);
}
private:
Token::Value op_;
int value_;
bool reversed_;
};
void ArmCodeGenerator::SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed) {
@ -2007,45 +2029,108 @@ void ArmCodeGenerator::SmiOperation(Token::Value op,
// sp[0] : operand
ASSERT(value->IsSmi());
int int_value = Smi::cast(*value)->value();
Label exit;
__ pop(r0);
switch (op) {
case Token::ADD: {
Label slow;
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, int_value, reversed);
__ mov(r1, Operand(value));
__ add(r0, r0, Operand(r1), SetCC);
__ b(vs, &slow);
__ add(r0, r0, Operand(value), SetCC);
__ b(vs, deferred->enter());
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &exit);
__ bind(&slow);
SmiOpStub stub(Token::ADD, reversed);
__ CallStub(&stub);
__ b(ne, deferred->enter());
__ bind(deferred->exit());
break;
}
case Token::SUB: {
Label slow;
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, int_value, reversed);
__ mov(r1, Operand(value));
if (!reversed) {
__ sub(r2, r0, Operand(r1), SetCC);
__ sub(r0, r0, Operand(value), SetCC);
} else {
__ rsb(r2, r0, Operand(r1), SetCC);
__ rsb(r0, r0, Operand(value), SetCC);
}
__ b(vs, &slow);
__ tst(r2, Operand(kSmiTagMask));
__ mov(r0, Operand(r2), LeaveCC, eq); // conditionally set r0 to result
__ b(eq, &exit);
__ b(vs, deferred->enter());
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, deferred->enter());
__ bind(deferred->exit());
break;
}
__ bind(&slow);
case Token::BIT_OR:
case Token::BIT_XOR:
case Token::BIT_AND: {
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, int_value, reversed);
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, deferred->enter());
switch (op) {
case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
default: UNREACHABLE();
}
__ bind(deferred->exit());
break;
}
SmiOpStub stub(Token::SUB, reversed);
__ CallStub(&stub);
case Token::SHL:
case Token::SHR:
case Token::SAR: {
if (reversed) {
__ mov(ip, Operand(value));
__ push(ip);
__ push(r0);
GenericBinaryOperation(op);
} else {
int shift_value = int_value & 0x1f; // least significant 5 bits
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, op, shift_value, false);
__ tst(r0, Operand(kSmiTagMask));
__ b(ne, deferred->enter());
__ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
switch (op) {
case Token::SHL: {
__ mov(r2, Operand(r2, LSL, shift_value));
// check that the *unsigned* result fits in a smi
__ add(r3, r2, Operand(0x40000000), SetCC);
__ b(mi, deferred->enter());
break;
}
case Token::SHR: {
// LSR by immediate 0 means shifting 32 bits.
if (shift_value != 0) {
__ mov(r2, Operand(r2, LSR, shift_value));
}
// check that the *unsigned* result fits in a smi
// neither of the two high-order bits can be set:
// - 0x80000000: high bit would be lost when smi tagging
// - 0x40000000: this number would convert to negative when
// smi tagging these two cases can only happen with shifts
// by 0 or 1 when handed a valid smi
__ and_(r3, r2, Operand(0xc0000000), SetCC);
__ b(ne, deferred->enter());
break;
}
case Token::SAR: {
if (shift_value != 0) {
// ASR by immediate 0 means shifting 32 bits.
__ mov(r2, Operand(r2, ASR, shift_value));
}
break;
}
default: UNREACHABLE();
}
__ mov(r0, Operand(r2, LSL, kSmiTagSize));
__ bind(deferred->exit());
}
break;
}

View File

@ -555,8 +555,7 @@ Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
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);
@ -704,7 +703,7 @@ Handle<JSFunction> Factory::CreateApiFunction(
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
if (array->length() > 0) {
if (!array->IsEmpty()) {
map->set_instance_descriptors(*array);
}

View File

@ -281,10 +281,6 @@ class Factory : public AllStatic {
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>,

View File

@ -301,8 +301,16 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
// lookup the flag
Flag* flag = Lookup(name);
if (flag == NULL) {
fprintf(stderr, "Error: unrecognized flag %s\n", arg);
return j;
if (remove_flags) {
// We don't recognize this flag but since we're removing
// the flags we recognize we assume that the remaining flags
// will be processed somewhere else so this flag might make
// sense there.
continue;
} else {
fprintf(stderr, "Error: unrecognized flag %s\n", arg);
return j;
}
}
// if we still need a flag value, use the next argument if available

View File

@ -304,7 +304,8 @@ enum PropertyType {
FIELD = 3, // only in fast mode
CALLBACKS = 4,
CONSTANT_TRANSITION = 5, // only in fast mode
INTERCEPTOR = 6
INTERCEPTOR = 6,
NULL_DESCRIPTOR = 7 // only in fast mode
};

View File

@ -160,14 +160,6 @@ void Heap::RecordWrite(Address address, int offset) {
}
Object* Heap::AllocatePropertyStorageForMap(Map* map) {
if (map->unused_property_fields() > 0) {
return AllocateFixedArray(map->unused_property_fields());
}
return Heap::empty_fixed_array();
}
AllocationSpace Heap::TargetSpace(HeapObject* object) {
// Heap numbers and sequential strings are promoted to code space, all
// other object types are promoted to old space. We do not use

View File

@ -861,7 +861,7 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
map->set_prototype(null_value());
map->set_constructor(null_value());
map->set_instance_size(instance_size);
map->set_instance_descriptors(DescriptorArray::cast(empty_fixed_array()));
map->set_instance_descriptors(empty_descriptor_array());
map->set_code_cache(empty_fixed_array());
map->set_unused_property_fields(0);
map->set_bit_field(0);
@ -894,17 +894,20 @@ bool Heap::CreateInitialMaps() {
if (obj->IsFailure()) return false;
null_value_ = obj;
// Fix the instance_descriptors for the existing maps.
DescriptorArray* empty_descriptors =
DescriptorArray::cast(empty_fixed_array());
// Allocate the empty descriptor array. AllocateMap can now be used.
obj = AllocateEmptyFixedArray();
if (obj->IsFailure()) return false;
// There is a check against empty_descriptor_array() in cast().
empty_descriptor_array_ = reinterpret_cast<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.
@ -1004,6 +1007,7 @@ bool Heap::CreateInitialMaps() {
if (obj->IsFailure()) return false;
shared_function_info_map_ = Map::cast(obj);
ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
return true;
}
@ -1701,7 +1705,7 @@ Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
// Allocate the backing storage for the properties.
Object* properties = AllocatePropertyStorageForMap(map);
Object* properties = AllocateFixedArray(map->unused_property_fields());
if (properties->IsFailure()) return properties;
// Allocate the JSObject.
@ -1749,7 +1753,7 @@ Object* Heap::ReinitializeJSGlobalObject(JSFunction* constructor,
ASSERT(map->instance_size() == object->map()->instance_size());
// Allocate the backing storage for the properties.
Object* properties = AllocatePropertyStorageForMap(map);
Object* properties = AllocateFixedArray(map->unused_property_fields());
if (properties->IsFailure()) return properties;
// Reset the map for the object.

View File

@ -112,6 +112,7 @@ namespace v8 { namespace internal {
V(Object, false_value) \
V(String, empty_string) \
V(FixedArray, empty_fixed_array) \
V(DescriptorArray, empty_descriptor_array) \
V(Object, the_hole_value) \
V(Map, neander_map) \
V(JSObject, message_listeners) \
@ -811,10 +812,6 @@ class Heap : public AllStatic {
// inlined).
static inline Object* AllocateRawMap(int size_in_bytes);
// Allocate storage for JSObject properties.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
static inline Object* AllocatePropertyStorageForMap(Map* map);
// Initializes a JSObject based on its map.
static void InitializeJSObjectFromMap(JSObject* obj,

View File

@ -133,6 +133,7 @@ void HeapObject::HeapObjectPrint() {
JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint();
break;
case JS_VALUE_TYPE:
PrintF("Value wrapper around:");
JSValue::cast(this)->value()->Print();
break;
case CODE_TYPE:

View File

@ -979,6 +979,13 @@ void FixedArray::set_the_hole(int index) {
}
bool DescriptorArray::IsEmpty() {
ASSERT(this == Heap::empty_descriptor_array() ||
this->length() > 2);
return this == Heap::empty_descriptor_array();
}
void DescriptorArray::fast_swap(FixedArray* array, int first, int second) {
Object* tmp = array->get(first);
fast_set(array, first, array->get(second));

View File

@ -1030,8 +1030,7 @@ Object* JSObject::AddFastProperty(String* name,
} else {
ASSERT(map()->unused_property_fields() == 0);
static const int kFastNofProperties = 8;
if (properties()->length() > kFastNofProperties) {
if (properties()->length() > kMaxFastProperties) {
Object* obj = NormalizeProperties();
if (obj->IsFailure()) return obj;
return AddSlowProperty(name, value, attributes);
@ -1553,6 +1552,8 @@ Object* JSObject::SetProperty(LookupResult* result,
// if the value is a function.
// AddProperty has been extended to do this, in this case.
return AddFastProperty(name, value, attributes);
case NULL_DESCRIPTOR:
UNREACHABLE();
default:
UNREACHABLE();
}
@ -1612,6 +1613,8 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(String* name,
case INTERCEPTOR:
return SetPropertyWithInterceptor(name, value, NONE);
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
UNREACHABLE();
break;
}
}
@ -1727,7 +1730,12 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
case INTERCEPTOR:
return result->holder()->
GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return ABSENT;
default:
UNREACHABLE();
break;
}
}
@ -1790,8 +1798,14 @@ Object* JSObject::NormalizeProperties() {
dictionary = Dictionary::cast(result);
break;
}
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
case INTERCEPTOR:
break;
default:
ASSERT(details.IsTransition());
case NORMAL:
UNREACHABLE();
break;
}
}
@ -1800,17 +1814,15 @@ Object* JSObject::NormalizeProperties() {
int index = map()->instance_descriptors()->NextEnumerationIndex();
dictionary->SetNextEnumerationIndex(index);
// Descriptors with type MAP_TRANSITION is ignored.
// Allocate new map.
obj = map()->Copy();
if (obj->IsFailure()) return obj;
// We have now sucessfully allocated all the necessary objects.
// Changes can now be made with the guarantee that all of them take effect.
set_map(Map::cast(obj));
map()->
set_instance_descriptors(DescriptorArray::cast(Heap::empty_fixed_array()));
map()->set_instance_descriptors(Heap::empty_descriptor_array());
// We have now allocate all the necessary object and change can be applied.
map()->set_unused_property_fields(0);
set_properties(dictionary);
@ -2569,20 +2581,33 @@ void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
}
#ifdef DEBUG
bool FixedArray::IsEqualTo(FixedArray* other) {
if (length() != other->length()) return false;
for (int i = 0 ; i < length(); ++i) {
if (get(i) != other->get(i)) return false;
}
return true;
}
#endif
Object* DescriptorArray::Allocate(int number_of_descriptors) {
// Allocate the descriptor array.
if (number_of_descriptors == 0) {
return Heap::empty_descriptor_array();
}
// Allocate the array of keys.
Object* array = Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors));
if (array->IsFailure()) return array;
DescriptorArray* result = DescriptorArray::cast(array);
// Do not use DescriptorArray::cast on incomplete object.
FixedArray* result = FixedArray::cast(array);
// Allocate the content array and set it in the descriptor array.
array = Heap::AllocateFixedArray(number_of_descriptors << 1);
if (array->IsFailure()) return array;
result->set(kContentArrayIndex, array);
// Initialize the next enumeration index.
result->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
result->set(kEnumerationIndexIndex,
Smi::FromInt(PropertyDetails::kInitialIndex));
return result;
}
@ -2594,7 +2619,7 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
FixedArray::cast(get(kEnumerationIndexIndex))->
set(kEnumCacheBridgeCacheIndex, new_cache);
} else {
if (length() == 0) return; // Do nothing for empty descriptor array.
if (IsEmpty()) return; // Do nothing for empty descriptor array.
FixedArray::cast(bridge_storage)->
set(kEnumCacheBridgeCacheIndex, new_cache);
fast_set(FixedArray::cast(bridge_storage),
@ -2706,7 +2731,6 @@ Object* DescriptorArray::CopyRemove(String* name) {
// Set the enumeration index in the descriptors and set the enumeration index
// in the result.
new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
// Write the old content and the descriptor information
DescriptorWriter w(new_descriptors);
DescriptorReader r(this);
@ -2801,6 +2825,19 @@ int DescriptorArray::BinarySearch(String* name, int low, int high) {
}
#ifdef DEBUG
bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
if (IsEmpty()) return other->IsEmpty();
if (other->IsEmpty()) return false;
if (length() != other->length()) return false;
for (int i = 0; i < length(); ++i) {
if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
}
return GetContentArray()->IsEqualTo(other->GetContentArray());
}
#endif
static StaticResource<StringInputBuffer> string_input_buffer;
@ -3775,7 +3812,8 @@ Object* JSFunction::SetPrototype(Object* value) {
map()->set_constructor(value);
map()->set_non_instance_prototype(true);
construct_prototype = *Top::initial_object_prototype();
construct_prototype =
Top::context()->global_context()->initial_object_prototype();
} else {
map()->set_non_instance_prototype(false);
}
@ -4210,8 +4248,8 @@ Object* JSObject::SetElementsLength(Object* len) {
}
int min = NewElementsCapacity(old_capacity);
int new_capacity = value > min ? value : min;
if (KeepInFastCase(new_capacity) ||
new_capacity <= kMaxFastElementsLength) {
if (new_capacity <= kMaxFastElementsLength ||
!ShouldConvertToSlowElements(new_capacity)) {
Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
if (obj->IsFailure()) return obj;
if (IsJSArray()) JSArray::cast(this)->set_length(smi_length);
@ -4463,8 +4501,8 @@ Object* JSObject::SetFastElement(uint32_t index, Object* value) {
if ((index - elms_length) < kMaxGap) {
// Try allocating extra space.
int new_capacity = NewElementsCapacity(index+1);
if (KeepInFastCase(new_capacity) ||
new_capacity <= kMaxFastElementsLength) {
if (new_capacity <= kMaxFastElementsLength ||
!ShouldConvertToSlowElements(new_capacity)) {
ASSERT(static_cast<uint32_t>(new_capacity) > index);
Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity);
if (obj->IsFailure()) return obj;
@ -4519,7 +4557,7 @@ Object* JSObject::SetElement(uint32_t index, Object* value) {
}
// Attempt to put this object back in fast case.
if (ShouldHaveFastElements()) {
if (ShouldConvertToFastElements()) {
uint32_t new_length = 0;
if (IsJSArray()) {
CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length));
@ -4671,17 +4709,17 @@ bool JSObject::HasDenseElements() {
}
bool JSObject::KeepInFastCase(int new_capacity) {
bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ASSERT(HasFastElements());
// Keep the array in fast case if the current backing storage is
// almost filled and if the new capacity is no more than twice the
// old capacity.
int elements_length = FixedArray::cast(elements())->length();
return HasDenseElements() && ((new_capacity / 2) <= elements_length);
return !HasDenseElements() || ((new_capacity / 2) > elements_length);
}
bool JSObject::ShouldHaveFastElements() {
bool JSObject::ShouldConvertToFastElements() {
ASSERT(!HasFastElements());
Dictionary* dictionary = Dictionary::cast(elements());
// If the elements are sparse, we should not go back to fast case.
@ -4864,8 +4902,15 @@ bool JSObject::HasRealNamedProperty(String* key) {
case NORMAL: // fall through.
case FIELD: // fall through.
case CALLBACKS: // fall through.
case CONSTANT_FUNCTION: return true;
default: return false;
case CONSTANT_FUNCTION:
return true;
case INTERCEPTOR:
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return false;
default:
UNREACHABLE();
}
}
@ -5099,8 +5144,9 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
}
ASSERT(!storage || storage->length() >= counter);
} else {
if (storage)
if (storage) {
element_dictionary()->CopyKeysTo(storage, filter);
}
counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
}
@ -5506,7 +5552,7 @@ Object* Dictionary::GenerateNewEnumerationIndices() {
Object* Dictionary::EnsureCapacity(int n, Key* key) {
// Check whether there is enough enumeration indices for adding n elements.
// Check whether there are enough enumeration indices to add n elements.
if (key->IsStringKey() &&
!PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
// If not, we generate new indices for the properties.
@ -5793,9 +5839,10 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
}
// Allocate the instance descriptor.
Object* instance_descriptors =
Object* descriptors_unchecked =
DescriptorArray::Allocate(instance_descriptor_length);
if (instance_descriptors->IsFailure()) return instance_descriptors;
if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
int number_of_allocated_fields = number_of_fields + unused_property_fields;
@ -5804,7 +5851,7 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
if (fields->IsFailure()) return fields;
// Fill in the instance descriptor and the fields.
DescriptorWriter w(DescriptorArray::cast(instance_descriptors));
DescriptorWriter w(descriptors);
int current_offset = 0;
for (int i = 0; i < capacity; i++) {
Object* k = KeyAt(i);
@ -5841,25 +5888,20 @@ Object* Dictionary::TransformPropertiesToFastFor(JSObject* obj,
}
ASSERT(current_offset == number_of_fields);
// Sort the instance descriptors.
DescriptorArray::cast(instance_descriptors)->Sort();
descriptors->Sort();
// Allocate new map.
Object* new_map = obj->map()->Copy();
if (new_map->IsFailure()) return new_map;
// Transform the object.
Map::cast(new_map)->
set_instance_descriptors(DescriptorArray::cast(instance_descriptors));
Map::cast(new_map)->set_unused_property_fields(unused_property_fields);
obj->set_map(Map::cast(new_map));
obj->map()->set_instance_descriptors(descriptors);
obj->map()->set_unused_property_fields(unused_property_fields);
obj->set_properties(FixedArray::cast(fields));
ASSERT(obj->IsJSObject());
// Transfer next enumeration index from dictionary to instance descriptors.
DescriptorArray::cast(instance_descriptors)->
SetNextEnumerationIndex(NextEnumerationIndex());
descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
// Check it really works.
ASSERT(obj->HasFastProperties());
return obj;

View File

@ -52,6 +52,7 @@
// - Array
// - ByteArray
// - FixedArray
// - DescriptorArray
// - HashTable
// - Dictionary
// - SymbolTable
@ -135,8 +136,7 @@ class PropertyDetails BASE_EMBEDDED {
bool IsTransition() {
PropertyType t = type();
ASSERT(t != INTERCEPTOR);
if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
return false;
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
}
PropertyAttributes attributes() { return AttributesField::decode(value_); }
@ -1095,23 +1095,20 @@ class HeapNumber: public HeapObject {
class JSObject: public HeapObject {
public:
// [properties]: Backing storage for properties.
DECL_ACCESSORS(properties, FixedArray)
// properties is a FixedArray in the fast case, and a Dictionary in the
// slow case.
DECL_ACCESSORS(properties, FixedArray) // Get and set fast properties.
inline void initialize_properties();
// [elements]: The elements in the fast case.
DECL_ACCESSORS(elements, HeapObject)
inline void initialize_elements();
// Accessors for properties.
inline bool HasFastProperties();
inline Dictionary* property_dictionary(); // Gets slow properties.
// Do we want to keep the elements in fast case when increasing the
// capacity?
bool KeepInFastCase(int new_capacity);
// Accessors for slow properties
inline Dictionary* property_dictionary(); // asserts !HasFastProperties
inline Dictionary* element_dictionary(); // asserts !HasFastElements
// [elements]: The elements (properties with names that are integers).
// elements is a FixedArray in the fast case, and a Dictionary in the slow
// case.
DECL_ACCESSORS(elements, HeapObject) // Get and set fast elements.
inline void initialize_elements();
inline bool HasFastElements();
inline Dictionary* element_dictionary(); // Gets slow elements.
Object* SetProperty(String* key,
Object* value,
@ -1188,14 +1185,14 @@ class JSObject: public HeapObject {
// Tests for the fast common case for property enumeration.
bool IsSimpleEnum();
// Tells whether the backing storage for elements is fast (FixedArray).
inline bool HasFastElements();
// Do we want to keep the elements in fast case when increasing the
// capacity?
bool ShouldConvertToSlowElements(int new_capacity);
// Returns true if the backing storage for the slow-case elements of
// this object takes up nearly as much space as a fast-case backing
// storage would. In that case the JSObject should have fast
// elements.
bool ShouldHaveFastElements();
bool ShouldConvertToFastElements();
// Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype();
@ -1370,6 +1367,7 @@ class JSObject: public HeapObject {
static const uint32_t kMaxGap = 1024;
static const int kMaxFastElementsLength = 5000;
static const int kMaxFastProperties = 8;
// Layout description.
static const int kPropertiesOffset = HeapObject::kSize;
@ -1477,6 +1475,8 @@ class FixedArray: public Array {
#ifdef DEBUG
void FixedArrayPrint();
void FixedArrayVerify();
// Checks if two FixedArrays have identical contents.
bool IsEqualTo(FixedArray* other);
#endif
// Swap two elements.
@ -1505,14 +1505,15 @@ class FixedArray: public Array {
//
class DescriptorArray: public FixedArray {
public:
// Is this the singleton empty_descriptor_array?
inline bool IsEmpty();
// Returns the number of descriptors in the array.
int number_of_descriptors() {
int len = length();
return len == 0 ? 0 : len - kFirstIndex;
return IsEmpty() ? 0 : length() - kFirstIndex;
}
int NextEnumerationIndex() {
if (length() == 0) return PropertyDetails::kInitialIndex;
if (IsEmpty()) return PropertyDetails::kInitialIndex;
Object* obj = get(kEnumerationIndexIndex);
if (obj->IsSmi()) {
return Smi::cast(obj)->value();
@ -1524,11 +1525,12 @@ class DescriptorArray: public FixedArray {
// Set next enumeration index and flush any enum cache.
void SetNextEnumerationIndex(int value) {
fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value));
if (!IsEmpty()) {
fast_set(this, kEnumerationIndexIndex, Smi::FromInt(value));
}
}
bool HasEnumCache() {
return length() > 0 && !get(kEnumerationIndexIndex)->IsSmi();
return !IsEmpty() && !get(kEnumerationIndexIndex)->IsSmi();
}
Object* GetEnumCache() {
@ -1579,6 +1581,9 @@ class DescriptorArray: public FixedArray {
// with low=0 and high=2.
int BinarySearch(String* name, int low, int high);
// Allocates a DescriptorArray, but returns the singleton
// empty descriptor array object if number_of_descriptors is 0.
static Object* Allocate(int number_of_descriptors);
// Casting.
@ -1612,6 +1617,9 @@ class DescriptorArray: public FixedArray {
// Is the descriptor array sorted and without duplicates?
bool IsSortedNoDuplicates();
// Are two DescriptorArrays equal?
bool IsEqualTo(DescriptorArray* other);
#endif
// The maximum number of descriptors we want in a descriptor array (should

View File

@ -2726,9 +2726,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
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);

View File

@ -87,6 +87,9 @@ void LookupResult::Print() {
case CONSTANT_TRANSITION:
PrintF(" -type = constant property transition\n");
break;
case NULL_DESCRIPTOR:
PrintF(" =type = null descriptor\n");
break;
}
}

View File

@ -348,8 +348,11 @@ class DescriptorReader: public DescriptorStream {
bool IsTransition() {
PropertyType t = type();
ASSERT(t != INTERCEPTOR);
if (t == MAP_TRANSITION || t == CONSTANT_TRANSITION) return true;
return false;
return t == MAP_TRANSITION || t == CONSTANT_TRANSITION;
}
bool IsNullDescriptor() {
return type() == NULL_DESCRIPTOR;
}
JSFunction* GetConstantFunction() { return JSFunction::cast(GetValue()); }

View File

@ -247,8 +247,7 @@ static Object* Runtime_CreateApiFunction(Arguments args) {
static Object* Runtime_IsTemplate(Arguments args) {
ASSERT(args.length() == 1);
Object* arg = args[0];
bool result = arg->IsObjectTemplateInfo()
|| arg->IsFunctionTemplateInfo();
bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
return Heap::ToBoolean(result);
}
@ -794,11 +793,12 @@ static Object* Runtime_FunctionSetLength(Arguments args) {
static Object* Runtime_FunctionSetPrototype(Arguments args) {
HandleScope scope;
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSFunction, fun, args[0]);
Accessors::FunctionSetPrototype(fun, args[1], NULL);
Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
if (obj->IsFailure()) return obj;
return args[0]; // return TOS
}
@ -858,14 +858,12 @@ static Object* Runtime_SetCode(Arguments args) {
static Object* CharCodeAt(String* subject, Object* index) {
uint32_t i = 0;
if (!Array::IndexFromObject(index, &i))
return Heap::nan_value();
if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
// Flatten the string. If someone wants to get a char at an index
// in a cons string, it is likely that more indices will be
// accessed.
subject->TryFlatten();
if (i >= static_cast<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));
}
@ -1315,12 +1313,13 @@ Object* Runtime::SetObjectProperty(Handle<Object> object,
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();
@ -1562,8 +1561,7 @@ static Object* Runtime_Typeof(Arguments args) {
HeapObject* heap_obj = HeapObject::cast(obj);
// typeof an undetectable object is 'undefined'
if (heap_obj->map()->is_undetectable())
return Heap::undefined_symbol();
if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
InstanceType instance_type = heap_obj->map()->instance_type();
if (instance_type < FIRST_NONSTRING_TYPE) {
@ -1888,7 +1886,7 @@ static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
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]);
@ -1916,12 +1914,10 @@ static Object* ConvertCase(Arguments args,
Object* o = s->IsAscii()
? Heap::AllocateRawAsciiString(length)
: Heap::AllocateRawTwoByteString(length);
if (o->IsFailure())
return o;
if (o->IsFailure()) return o;
String* result = String::cast(o);
bool has_changed_character = false;
// Convert all characters to upper case, assuming that they will fit
// in the buffer
Access<StringInputBuffer> buffer(&string_input_buffer);
@ -2047,10 +2043,7 @@ static Object* Runtime_NumberToInteger(Arguments args) {
ASSERT(args.length() == 1);
Object* obj = args[0];
if (obj->IsSmi())
return obj;
if (obj->IsSmi()) return obj;
CONVERT_DOUBLE_CHECKED(number, obj);
return Heap::NumberFromDouble(DoubleToInteger(number));
}
@ -2184,8 +2177,9 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
return Top::Throw(Heap::illegal_argument_symbol());
}
FixedArray* fixed_array = FixedArray::cast(array->elements());
if (fixed_array->length() < array_length)
if (fixed_array->length() < array_length) {
array_length = fixed_array->length();
}
if (array_length == 0) {
return Heap::empty_string();
@ -2214,8 +2208,9 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
return Failure::OutOfMemoryException();
}
position += element_length;
if (ascii && !element->IsAscii())
if (ascii && !element->IsAscii()) {
ascii = false;
}
} else {
return Top::Throw(Heap::illegal_argument_symbol());
}
@ -2408,17 +2403,15 @@ static Object* Runtime_StringCompare(Arguments args) {
// A few fast case tests before we flatten.
if (x == y) return Smi::FromInt(EQUAL);
if (y->length() == 0) {
if (x->length() == 0)
return Smi::FromInt(EQUAL);
if (x->length() == 0) return Smi::FromInt(EQUAL);
return Smi::FromInt(GREATER);
} else if (x->length() == 0) {
return Smi::FromInt(LESS);
}
{
int d = x->Get(0) - y->Get(0);
if (d < 0) return Smi::FromInt(LESS);
else if (d > 0) return Smi::FromInt(GREATER);
}
int d = x->Get(0) - y->Get(0);
if (d < 0) return Smi::FromInt(LESS);
else if (d > 0) return Smi::FromInt(GREATER);
x->TryFlatten();
y->TryFlatten();
@ -2821,8 +2814,6 @@ static Object* Runtime_LookupContext(Arguments args) {
}
// A mechanism to return pairs of Object*'s. This is somewhat
// compiler-dependent as it assumes that a 64-bit value (a long long)
// is returned via two registers (edx:eax on ia32). Both the ia32 and
@ -2888,7 +2879,7 @@ static ObjPair LoadContextSlotHelper(Arguments args, bool throw_error) {
if (throw_error) {
// The property doesn't exist - throw exception.
Handle<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
@ -2913,7 +2904,7 @@ static Object* Runtime_StoreContextSlot(Arguments args) {
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;
@ -3473,8 +3464,7 @@ static Object* Runtime_GetArrayKeys(Arguments args) {
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);
@ -3606,14 +3596,15 @@ static Object* DebugLookupResultValue(LookupResult* result) {
case CONSTANT_FUNCTION:
return result->GetConstantFunction();
case CALLBACKS:
return Heap::undefined_value();
case MAP_TRANSITION:
return Heap::undefined_value();
case INTERCEPTOR:
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
case NULL_DESCRIPTOR:
return Heap::undefined_value();
default:
UNREACHABLE();
}
UNREACHABLE();
return Heap::undefined_value();
}
@ -3788,8 +3779,7 @@ static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
CONVERT_ARG_CHECKED(String, name, 1);
PropertyAttributes attributes;
Object* result = obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
return result;
return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
}
@ -3803,8 +3793,7 @@ static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
RUNTIME_ASSERT(obj->HasIndexedInterceptor());
CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
Object* result = obj->GetElementWithInterceptor(*obj, index);
return result;
return obj->GetElementWithInterceptor(*obj, index);
}
@ -3868,8 +3857,8 @@ static Object* Runtime_GetFrameDetails(Arguments args) {
ASSERT(args.length() == 2);
// Check arguments.
Object* result = Runtime_CheckExecutionState(args);
if (result->IsFailure()) return result;
Object* check = Runtime_CheckExecutionState(args);
if (check->IsFailure()) return check;
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
// Find the relevant frame with the requested index.
@ -4258,8 +4247,8 @@ static Object* Runtime_PrepareStep(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 3);
// Check arguments.
Object* check_result = Runtime_CheckExecutionState(args);
if (check_result->IsFailure()) return check_result;
Object* check = Runtime_CheckExecutionState(args);
if (check->IsFailure()) return check;
if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
return Top::Throw(Heap::illegal_argument_symbol());
}

View File

@ -212,7 +212,8 @@ $Object.prototype.constructor = $Object;
%AddProperty(global, "execScript", function(expr, lang) {
// NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) {
%CompileString(ToString(expr), false)();
var f = %CompileString(ToString(expr), false);
f.call(global);
}
return null;
}, DONT_ENUM);

View File

@ -25,17 +25,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <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) {
@ -51,15 +52,67 @@ CcTest::CcTest(TestFunction* callback, const char* file, const char* name)
if (extension) *extension = 0;
// Install this test in the list of tests
file_ = basename;
prev_ = first_;
first_ = this;
prev_ = last_;
last_ = this;
}
int main(int argc, char *argv[]) {
CcTest* current = CcTest::first();
while (current != NULL) {
printf("%s/%s\n", current->file(), current->name());
current = current->prev();
static void PrintTestList(CcTest* current) {
if (current == NULL) return;
PrintTestList(current->prev());
printf("%s/%s\n", current->file(), current->name());
}
static int RunMatchingTests(CcTest* current, char* file_or_name) {
if (current == NULL) return 0;
int run_count = 0;
if (strcmp(current->file(), file_or_name) == 0
|| strcmp(current->name(), file_or_name) == 0) {
current->Run();
run_count++;
}
return run_count + RunMatchingTests(current->prev(), file_or_name);
}
static int RunMatchingTests(CcTest* current, char* file, char* name) {
if (current == NULL) return 0;
int run_count = 0;
if (strcmp(current->file(), file) == 0
&& strcmp(current->name(), name) == 0) {
current->Run();
run_count++;
}
return run_count + RunMatchingTests(current->prev(), file, name);
}
int main(int argc, char* argv[]) {
v8::internal::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
int tests_run = 0;
bool print_run_count = true;
for (int i = 1; i < argc; i++) {
char* arg = argv[i];
if (strcmp(arg, "--list") == 0) {
PrintTestList(CcTest::last());
print_run_count = false;
} else {
char* arg_copy = strdup(arg);
char* testname = strchr(arg_copy, '/');
if (testname) {
// Split the string in two by nulling the slash and then run
// exact matches.
*testname = 0;
tests_run += RunMatchingTests(CcTest::last(), arg_copy, testname + 1);
} else {
// Run all tests with the specified file or test name.
tests_run += RunMatchingTests(CcTest::last(), arg_copy);
}
free(arg_copy);
}
}
if (print_run_count && tests_run != 1)
printf("Ran %i tests.\n", tests_run);
return 0;
}

View File

@ -40,17 +40,17 @@ class CcTest {
public:
typedef void (TestFunction)();
CcTest(TestFunction* callback, const char* file, const char* name);
void Run() { callback_(); }
static int test_count();
static CcTest* first() { return first_; }
static CcTest* last() { return last_; }
CcTest* prev() { return prev_; }
const char* file() { return file_; }
const char* name() { return name_; }
private:
TestFunction* callback_;
const char* file_;
const char* name_;
static CcTest* first_;
static CcTest* last_;
CcTest* prev_;
};

View File

@ -121,9 +121,9 @@ static inline void CheckNonEqualsHelper(const char* file, int line,
// Helper class for creating a V8 enviromnent for running tests
class LocalContext {
class DebugLocalContext {
public:
inline LocalContext(
inline DebugLocalContext(
v8::ExtensionConfiguration* extensions = 0,
v8::Handle<v8::ObjectTemplate> global_template =
v8::Handle<v8::ObjectTemplate>(),
@ -131,7 +131,7 @@ class LocalContext {
: context_(v8::Context::New(extensions, global_template, global_object)) {
context_->Enter();
}
inline ~LocalContext() {
inline ~DebugLocalContext() {
context_->Exit();
context_.Dispose();
}
@ -159,7 +159,7 @@ class LocalContext {
// Compile and run the supplied source and return the fequested function.
static v8::Local<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();
@ -377,7 +377,7 @@ class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
// Compile a function, set a break point and check that the call at the break
// location in the code is the expected debug_break function.
void CheckDebugBreakFunction(LocalContext* env,
void CheckDebugBreakFunction(DebugLocalContext* env,
const char* source, const char* name,
int position, v8::internal::RelocMode mode,
Code* debug_break) {
@ -668,7 +668,7 @@ static void MessageCallbackCount(v8::Handle<v8::Message> message,
TEST(DebugStub) {
using ::v8::internal::Builtins;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// TODO(1240753): Make the test architecture independent or split
// parts of the debugger into architecture dependent files. This
@ -740,7 +740,7 @@ TEST(DebugStub) {
// debugged.
TEST(DebugInfo) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a couple of functions for the test.
v8::Local<v8::Function> foo =
CompileFunction(&env, "function foo(){}", "foo");
@ -777,7 +777,7 @@ TEST(DebugInfo) {
TEST(BreakPointICStore) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
@ -808,7 +808,7 @@ TEST(BreakPointICStore) {
TEST(BreakPointICLoad) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("bar=1"))->Run();
@ -840,7 +840,7 @@ TEST(BreakPointICLoad) {
TEST(BreakPointICCall) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
@ -872,7 +872,7 @@ TEST(BreakPointICCall) {
TEST(BreakPointReturn) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
@ -914,7 +914,7 @@ static void CallWithBreakPoints(v8::Local<v8::Object> recv,
TEST(GCDuringBreakPointProcessing) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointCollectGarbage,
v8::Undefined());
@ -971,7 +971,7 @@ static void CallAndGC(v8::Local<v8::Object> recv, v8::Local<v8::Function> f) {
TEST(BreakPointSurviveGC) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
@ -1005,7 +1005,7 @@ TEST(BreakPointSurviveGC) {
TEST(BreakPointThroughJavaScript) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1059,7 +1059,7 @@ TEST(BreakPointThroughJavaScript) {
TEST(ScriptBreakPointThroughJavaScript) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1178,7 +1178,7 @@ TEST(ScriptBreakPointThroughJavaScript) {
TEST(EnableDisableScriptBreakPoint) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1234,7 +1234,7 @@ TEST(EnableDisableScriptBreakPoint) {
TEST(ConditionalScriptBreakPoint) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1295,7 +1295,7 @@ TEST(ConditionalScriptBreakPoint) {
TEST(ScriptBreakPointIgnoreCount) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1349,7 +1349,7 @@ TEST(ScriptBreakPointIgnoreCount) {
TEST(ScriptBreakPointReload) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1407,7 +1407,7 @@ TEST(ScriptBreakPointReload) {
TEST(ScriptBreakPointMultiple) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1472,7 +1472,7 @@ TEST(ScriptBreakPointMultiple) {
TEST(ScriptBreakPointLineOffset) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
@ -1526,7 +1526,7 @@ TEST(ScriptBreakPointLineOffset) {
// Test script break points set on lines.
TEST(ScriptBreakPointLine) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
// Create a function for checking the function when hitting a break point.
@ -1632,7 +1632,7 @@ TEST(ScriptBreakPointLine) {
// inside the break handling of that break point.
TEST(RemoveBreakPointInBreak) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Local<v8::Function> foo =
CompileFunction(&env, "function foo(){a=1;}", "foo");
@ -1657,7 +1657,7 @@ TEST(RemoveBreakPointInBreak) {
TEST(DebuggerStatement) {
break_point_hit_count = 0;
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::AddDebugEventListener(DebugEventBreakPointHitCount,
v8::Undefined());
v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
@ -1684,7 +1684,7 @@ TEST(DebuggerStatement) {
// the correct results.
TEST(DebugEvaluate) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
// Create a function for checking the evaluation when hitting a break point.
@ -1797,7 +1797,7 @@ TEST(DebugEvaluate) {
// Simple test of the stepping mechanism using only store ICs.
TEST(DebugStepLinear) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(&env,
@ -1833,7 +1833,7 @@ TEST(DebugStepLinear) {
// Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(&env,
@ -1877,7 +1877,7 @@ TEST(DebugStepLinearMixedICs) {
TEST(DebugStepIf) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
@ -1917,7 +1917,7 @@ TEST(DebugStepIf) {
TEST(DebugStepSwitch) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
@ -1969,7 +1969,7 @@ TEST(DebugStepSwitch) {
TEST(DebugStepFor) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::AddDebugEventListener(DebugEventStep);
@ -2006,7 +2006,7 @@ TEST(DebugStepFor) {
TEST(StepInOutSimple) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for checking the function when hitting a break point.
frame_function_name = CompileFunction(&env,
@ -2051,7 +2051,7 @@ TEST(StepInOutSimple) {
TEST(StepInOutTree) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for checking the function when hitting a break point.
frame_function_name = CompileFunction(&env,
@ -2097,7 +2097,7 @@ TEST(StepInOutTree) {
TEST(StepInOutBranch) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for checking the function when hitting a break point.
frame_function_name = CompileFunction(&env,
@ -2129,7 +2129,7 @@ TEST(StepInOutBranch) {
// Test that step in does not step into native functions.
TEST(DebugStepNatives) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(
@ -2170,7 +2170,7 @@ TEST(DebugStepNatives) {
// for them.
TEST(BreakOnException) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
v8::internal::Top::TraceException(false);
@ -2311,7 +2311,7 @@ TEST(BreakOnException) {
TEST(StepWithException) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Create a function for checking the function when hitting a break point.
frame_function_name = CompileFunction(&env,
@ -2392,7 +2392,7 @@ TEST(StepWithException) {
TEST(DebugBreak) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// This test should be run with option --verify-heap. This is an ASSERT and
// not a CHECK as --verify-heap is only available in debug mode.
@ -2447,7 +2447,7 @@ TEST(DebugBreak) {
// through the stack limit flag is set but breaks are disabled.
TEST(DisableBreak) {
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
// Register a debug event listener which sets the break flag and counts.
v8::Debug::AddDebugEventListener(DebugEventCounter);
@ -2522,7 +2522,7 @@ static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
TEST(InterceptorPropertyMirror) {
// Create a V8 environment with debug access.
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
env.ExposeDebug();
// Create object with named interceptor.
@ -2864,7 +2864,7 @@ MessageQueueDebuggerThread message_queue_debugger_thread;
TEST(MessageQueues) {
// Create a V8 environment
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
message_queue_barriers.Initialize();
v8::Debug::SetMessageHandler(MessageHandler);
message_queue_debugger_thread.Start();
@ -2938,7 +2938,7 @@ void V8Thread::Run() {
const char* source_2 = "foo();\n";
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
CompileRun(source_1);
@ -3047,7 +3047,7 @@ void BreakpointsV8Thread::Run() {
"cat(19);\n";
v8::HandleScope scope;
LocalContext env;
DebugLocalContext env;
v8::Debug::SetMessageHandler(&BreakpointsMessageHandler);
CompileRun(source_1);

View File

@ -124,10 +124,10 @@ TEST(Flags4) {
SetFlagsToDefault();
int argc = 3;
const char* argv[] = { "Test4", "--bool_flag", "--foo" };
CHECK_EQ(2, FlagList::SetFlagsFromCommandLine(&argc,
CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
const_cast<char **>(argv),
true));
CHECK_EQ(3, argc);
CHECK_EQ(2, argc);
}

84
test/cctest/testcfg.py Normal file
View File

@ -0,0 +1,84 @@
# Copyright 2008 Google Inc. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import test
import os
from os.path import join, dirname
import platform
DEBUG_FLAGS = ['--enable-slow-asserts', '--debug-code', '--verify-heap']
class CcTestCase(test.TestCase):
def __init__(self, path, executable, mode, raw_name, context):
super(CcTestCase, self).__init__(context, path)
self.executable = executable
self.mode = mode
self.raw_name = raw_name
def GetLabel(self):
return "%s %s %s" % (self.mode, self.path[-2], self.path[-1])
def GetName(self):
return self.path[-1]
def GetCommand(self):
result = [ self.executable, self.raw_name ]
if self.mode == 'debug':
result += DEBUG_FLAGS
return result
class CcTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(CcTestConfiguration, self).__init__(context, root)
def GetBuildRequirements(self):
return ['cctests']
def ListTests(self, current_path, path, mode):
executable = join('obj', 'test', mode, 'cctest')
if (platform.system() == 'Windows'):
executable += '.exe'
output = test.Execute([executable, '--list'], self.context)
if output.exit_code != 0:
print output.stdout
print output.stderr
return []
result = []
for raw_test in output.stdout.strip().split():
full_path = current_path + raw_test.split('/')
if self.Contains(path, full_path):
result.append(CcTestCase(full_path, executable, mode, raw_test, self.context))
return result
def GetConfiguration(context, root):
return CcTestConfiguration(context, root)

View File

@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-debug-as debug
// Flags: --expose-debug-as debug --expose-gc
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
@ -55,7 +55,7 @@ for (i = 0; i < scripts.length; i++) {
// This has to be updated if the number of native and extension scripts change.
assertEquals(12, native_count);
assertEquals(5, extension_count);
assertEquals(1, extension_count);
assertEquals(2, normal_count); // This script and mjsunit.js.
// Test a builtins script.
@ -80,7 +80,7 @@ assertEquals(Debug.ScriptType.Extension, extension_gc_script.type);
// Test a normal script.
var mjsunit_js_script = Debug.findScript(/mjsunit.js/);
assertEquals('mjsunit.js', mjsunit_js_script.name);
assertTrue(/mjsunit.js/.test(mjsunit_js_script.name));
assertEquals(Debug.ScriptType.Normal, mjsunit_js_script.type);
// Check a nonexistent script.

View File

@ -47,5 +47,3 @@ function g() {
assertEquals(Debug.scriptSource(f), Debug.scriptSource(g));
f();
g();
assertEquals("function print() { [native code] }", print);

View File

@ -48,7 +48,7 @@ function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) {
assertTrue(mirror.prototypeObject() instanceof debug.Mirror);
assertFalse(mirror.hasNamedInterceptor(), "hasNamedInterceptor()");
assertFalse(mirror.hasIndexedInterceptor(), "hasIndexedInterceptor()");
var names = mirror.propertyNames();
var properties = mirror.properties()
assertEquals(names.length, properties.length);
@ -77,10 +77,11 @@ function testObjectMirror(o, cls_name, ctor_name, hasSpecialProperties) {
assertEquals('object', fromJSON.type);
assertEquals(cls_name, fromJSON.className);
assertEquals('function', fromJSON.constructorFunction.type);
assertEquals(ctor_name, fromJSON.constructorFunction.name);
if (ctor_name !== undefined)
assertEquals(ctor_name, fromJSON.constructorFunction.name);
assertEquals(void 0, fromJSON.namedInterceptor);
assertEquals(void 0, fromJSON.indexedInterceptor);
// For array the index properties are seperate from named properties.
if (!cls_name == 'Array') {
assertEquals(names.length, fromJSON.properties.length, 'Some properties missing in JSON');
@ -134,7 +135,7 @@ testObjectMirror({}, 'Object', 'Object');
testObjectMirror({'a':1,'b':2}, 'Object', 'Object');
testObjectMirror({'1':void 0,'2':null,'f':function pow(x,y){return Math.pow(x,y);}}, 'Object', 'Object');
testObjectMirror(new Point(-1.2,2.003), 'Object', 'Point');
testObjectMirror(this, 'global', 'Object', true); // Global object has special properties
testObjectMirror(this, 'global', undefined, true); // Global object has special properties
testObjectMirror([], 'Array', 'Array');
testObjectMirror([1,2], 'Array', 'Array');

View File

@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --trace-calls --preallocated-stack-trace-memory 1000000
// Flags: --trace-calls --preallocate-message-memory
/**
* @fileoverview Check that various regexp constructs work as intended.

View File

@ -0,0 +1,33 @@
// Copyright 2008 Google Inc. All Rights Reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Make sure that 'this' is bound to the global object when using
// execScript.
var result;
execScript("result = this");
assertTrue(result === this);

View File

@ -36,21 +36,24 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
class MjsunitTestCase(test.TestCase):
def __init__(self, path, file, config):
super(MjsunitTestCase, self).__init__(path)
def __init__(self, path, file, mode, context, config):
super(MjsunitTestCase, self).__init__(context, path)
self.file = file
self.config = config
self.mode = mode
def GetLabel(self):
return "%s %s" % (self.mode, self.GetName())
def GetName(self):
return self.path[-1]
def GetCommand(self):
result = [self.config.context.vm]
result = [self.config.context.GetVm(self.mode)]
source = open(self.file).read()
flags_match = FLAGS_PATTERN.search(source)
if flags_match:
runtime_flags = flags_match.group(1).strip().split()
result += ["--runtime-flags", " ".join(runtime_flags)]
result += flags_match.group(1).strip().split()
framework = join(dirname(self.config.root), 'mjsunit', 'mjsunit.js')
result += [framework, self.file]
return result
@ -65,29 +68,21 @@ class MjsunitTestConfiguration(test.TestConfiguration):
def SelectTest(name):
return name.endswith('.js') and name != 'mjsunit.js'
return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def Contains(self, path, file):
if len(path) > len(file):
return False
for i in xrange(len(path)):
if path[i] != file[i]:
return False
return True
def ListTests(self, current_path, path, mode):
mjsunit = [[t] for t in self.Ls(self.root)]
regress = [['regress', t] for t in self.Ls(join(self.root, 'regress'))]
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
all_tests = mjsunit + regress
result = []
for test in all_tests:
if self.Contains(path, test):
full_name = current_path + test
file_path = join(self.root, reduce(join, test, "") + ".js")
result.append(MjsunitTestCase(full_name, file_path, self))
file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(MjsunitTestCase(full_name, file_path, mode, self.context, self))
return result
def GetBuildRequirements(self):
return ['sample=shell']
return ['sample', 'sample=shell']
def GetConfiguration(context, root):

762
test/mozilla/mozilla.status Normal file
View File

@ -0,0 +1,762 @@
# Copyright 2008 Google Inc. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# --------------------------------------------------------------------
# If you add a test case to this file, please try to provide
# an explanation of why the test fails; this may ease future
# debugging.
# --------------------------------------------------------------------
prefix mozilla_js_tests
def FAIL_OK = FAIL, OKAY
##################### SKIPPED TESTS #####################
# This test checks that we behave properly in an out-of-memory
# situation. The test fails in V8 with an exception and takes a long
# time to do so.
js1_5/Regress/regress-271716-n: SKIP
##################### SLOW TESTS #####################
# This takes a long time to run (~100 seconds). It should only be run
# by the really patient.
js1_5/GC/regress-324278: SLOW
# This takes a long time to run because our indexOf operation is
# pretty slow - it causes a lot of GCs; see issue
# #926379. We could consider marking this SKIP because it takes a
# while to run to completion.
js1_5/GC/regress-338653: SLOW
# This test is designed to run until it runs out of memory. This takes
# a very long time because it builds strings character by character
# and compiles a lot of regular expressions. We could consider marking
# this SKIP because it takes a while to run to completion.
js1_5/GC/regress-346794: SLOW
# Runs out of memory while trying to build huge string of 'x'
# characters. This takes a long time to run (~32 seconds).
js1_5/GC/regress-348532: SLOW
##################### FLAKY TESTS #####################
# These tests time out in debug mode but pass in product mode
js1_5/Regress/regress-280769-3: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-203278-1: PASS || ($DEBUG && FAIL)
js1_5/GC/regress-203278-2: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-244470: PASS || ($DEBUG && FAIL)
ecma_3/RegExp/regress-209067: PASS || ($DEBUG && FAIL)
js1_5/GC/regress-278725: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-360969-03: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-360969-04: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-360969-05: PASS || ($DEBUG && FAIL)
js1_5/Regress/regress-360969-06: PASS || ($DEBUG && FAIL)
js1_5/extensions/regress-365527: PASS || ($DEBUG && FAIL)
# http://b/issue?id=1206983
js1_5/Regress/regress-367561-03: PASS || ($DEBUG && FAIL)
ecma/Date/15.9.5.10-2: PASS || ($DEBUG && FAIL)
# These tests create two Date objects just after each other and
# expects them to match. Sometimes this happens on the border
# between one second and the next.
ecma/Date/15.9.2.1: PASS || FAIL
ecma/Date/15.9.2.2-1: PASS || FAIL
ecma/Date/15.9.2.2-2: PASS || FAIL
ecma/Date/15.9.2.2-3: PASS || FAIL
ecma/Date/15.9.2.2-4: PASS || FAIL
ecma/Date/15.9.2.2-5: PASS || FAIL
ecma/Date/15.9.2.2-6: PASS || FAIL
# 1026139: These date tests fail on arm
ecma/Date/15.9.5.29-1: PASS || ($ARM && FAIL)
ecma/Date/15.9.5.34-1: PASS || ($ARM && FAIL)
ecma/Date/15.9.5.28-1: PASS || ($ARM && FAIL)
# 1050186: Arm vm is broken; probably unrelated to dates
ecma/Array/15.4.4.5-3: PASS || ($ARM && FAIL)
ecma/Date/15.9.5.22-2: PASS || ($ARM && FAIL)
# Severely brain-damaged test. Access to local variables must not
# be more than 2.5 times faster than access to global variables? WTF?
js1_5/Regress/regress-169559: PASS || FAIL
# Test that rely on specific timezone (not working in Denmark).
js1_5/Regress/regress-58116: PASS || FAIL
# Flaky random() test. Tests the distribution of calls to Math.random().
js1_5/Regress/regress-211590: PASS || FAIL
# Flaky tests; expect BigO-order computations to yield 1, but the code
# cannot handle outliers. See bug #925864.
ecma_3/RegExp/regress-311414: PASS || FAIL
ecma_3/RegExp/regress-289669: PASS || FAIL
js1_5/String/regress-314890: PASS || FAIL
js1_5/String/regress-56940-01: PASS || FAIL
js1_5/String/regress-56940-02: PASS || FAIL
js1_5/String/regress-157334-01: PASS || FAIL
js1_5/String/regress-322772: PASS || FAIL
js1_5/Array/regress-99120-01: PASS || FAIL
js1_5/Array/regress-99120-02: PASS || FAIL
js1_5/Regress/regress-347306-01: PASS || FAIL
js1_5/Regress/regress-416628: PASS || FAIL
# The following two tests assume that daylight savings time starts first Sunday
# in April. This is not true when executing the tests outside California!
# In Denmark the adjustment starts one week earlier!.
# Tests based on shell that use dates in this gap are flaky.
ecma/Date/15.9.5.10-1: PASS || FAIL
ecma/Date/15.9.5.12-1: PASS || FAIL
ecma/Date/15.9.5.14: PASS || FAIL
ecma/Date/15.9.5.34-1: PASS || FAIL
# These tests sometimes pass (in particular on Windows). They build up
# a lot of stuff on the stack, which normally causes a stack overflow,
# but sometimes it makes it through?
js1_5/Regress/regress-290575: PASS || FAIL
js1_5/Regress/regress-98901: PASS || FAIL
# Tests that sorting arrays of ints is less than 3 times as fast
# as sorting arrays of strings.
js1_5/extensions/regress-371636: PASS || FAIL
# Test depends on GC timings. Inherently flaky.
js1_5/GC/regress-383269-01: PASS || FAIL
##################### INCOMPATIBLE TESTS #####################
# This section is for tests that fail in both V8 and KJS. Thus they
# have been determined to be incompatible between Mozilla and V8/KJS.
# Fail because of toLowerCase and toUpperCase conversion.
ecma/String/15.5.4.11-2: FAIL_OK
ecma/String/15.5.4.11-5: FAIL_OK
ecma/String/15.5.4.12-1: FAIL_OK
ecma/String/15.5.4.12-4: FAIL_OK
# This test uses an older version of the unicode standard that fails
# us because we correctly convert the armenian small ligature ech-yiwn
# to the two upper-case characters ECH and YIWN, whereas the older
# unicode version converts it to itself.
ecma/String/15.5.4.12-5: FAIL_OK
# Creates a linked list of arrays until we run out of memory.
js1_5/Regress/regress-312588: FAIL_OK
# Runs out of memory because it compiles huge functions.
js1_5/Function/regress-338001: FAIL_OK
js1_5/Function/regress-338121-01: FAIL_OK
js1_5/Function/regress-338121-02: FAIL_OK
js1_5/Function/regress-338121-03: FAIL_OK
# Length of objects whose prototype chain includes a function
ecma_3/Function/regress-313570: FAIL_OK
#:=== RegExp:===
# To be compatible with KJS we silently ignore flags that do not make
# sense. This test expects us to throw exceptions.
ecma_3/RegExp/regress-57631: FAIL_OK
# PCRE doesn't allow subpattern nesting deeper than 200, this tests
# depth 500. KJS detects the case, and return null from the match,
# and passes this test (the test doesn't check for a correct return
# value).
ecma_3/RegExp/regress-119909: FAIL_OK
# Difference in the way capturing subpatterns work. In JS, when the
# 'minimum repeat count' is reached, the empty string must not match.
# In this case, we are similar but not identical to KJS. Hard to
# support the JS behavior with PCRE, so maybe emulate KJS?
#
# Note: We do not support toSource currently so we cannot run this
# test. We should make an isolated test case for the regexp issue.
ecma_3/RegExp/regress-209919: FAIL_OK
# PCRE's match limit is reached. SpiderMonkey hangs on the first one,
# KJS returns true somehow. Maybe they up the match limit? There is
# an open V8 bug 676063 about this.
ecma_3/RegExp/regress-330684: FAIL_OK
# We do not detect overflow in bounds for back references and {}
# quantifiers. Might fix by parsing numbers differently?
js1_5/Regress/regress-230216-2: FAIL_OK
# According to ECMA-262, \b is a 'word' boundary, where words are only
# ASCII characters. PCRE supports non-ASCII word characters.
js1_5/Regress/regress-247179: FAIL_OK
# Regexp too long for PCRE.
js1_5/Regress/regress-280769: FAIL_OK
js1_5/Regress/regress-280769-1: FAIL_OK
js1_5/Regress/regress-280769-2: FAIL_OK
js1_5/Regress/regress-280769-4: FAIL_OK
js1_5/Regress/regress-280769-5: FAIL_OK
# We do not support static RegExp.multiline - should we?.
js1_2/regexp/RegExp_multiline: FAIL_OK
js1_2/regexp/RegExp_multiline_as_array: FAIL_OK
js1_2/regexp/beginLine: FAIL_OK
js1_2/regexp/endLine: FAIL_OK
# Date trouble?
js1_5/Date/regress-301738-02: FAIL_OK
# This test fails for all browsers on in the CET timezone.
ecma/Date/15.9.5.35-1: PASS || FAIL_OK
# Spidermonkey allows stuff in parenthesis directly after the minutes
# in a date. KJS does not, so we don't either.
js1_5/Date/regress-309925-02: FAIL_OK
# Print string after deleting array element?
js1_5/Expressions/regress-96526-delelem: FAIL_OK
# Stack overflows should be InternalError: too much recursion?
js1_5/Regress/regress-234389: FAIL_OK
# This may very well be a bogus test. I'm not sure yet.
js1_5/Regress/regress-320119: FAIL_OK
# We do not support explicit global evals through <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

125
test/mozilla/testcfg.py Normal file
View File

@ -0,0 +1,125 @@
# Copyright 2008 Google Inc. All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
from os.path import join, exists
import test
EXCLUDED = ['CVS']
FRAMEWORK = """
browser.js
shell.js
jsref.js
template.js
""".split()
TEST_DIRS = """
ecma
ecma_2
ecma_3
js1_1
js1_2
js1_3
js1_4
js1_5
""".split()
class MozillaTestCase(test.TestCase):
def __init__(self, filename, path, context, mode, framework):
super(MozillaTestCase, self).__init__(context, path)
self.filename = filename
self.mode = mode
self.framework = framework
def IsNegative(self):
return self.filename.endswith('-n.js')
def GetLabel(self):
return "%s mozilla %s" % (self.mode, self.GetName())
def IsFailureOutput(self, output):
if output.exit_code != 0:
return True
return 'FAILED!' in output.stdout
def GetCommand(self):
result = [self.context.GetVm(self.mode), '--expose-gc']
result += self.framework
result.append(self.filename)
return result
def GetName(self):
return self.path[-1]
class MozillaTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(MozillaTestConfiguration, self).__init__(context, root)
def ListTests(self, current_path, path, mode):
tests = []
for test_dir in TEST_DIRS:
current_root = join(self.root, test_dir)
for root, dirs, files in os.walk(current_root):
for dotted in [x for x in dirs if x.startswith('.')]:
dirs.remove(dotted)
for excluded in EXCLUDED:
if excluded in dirs:
dirs.remove(excluded)
root_path = root[len(self.root):].split(os.path.sep)
root_path = current_path + [x for x in root_path if x]
framework = []
for i in xrange(len(root_path)):
if i == 0: dir = root_path[1:]
else: dir = root_path[1:-i]
script = join(self.root, reduce(join, dir, ''), 'shell.js')
if exists(script):
framework.append(script)
framework.reverse()
for file in files:
if (not file in FRAMEWORK) and file.endswith('.js'):
full_path = root_path + [file[:-3]]
if self.Contains(path, full_path):
test = MozillaTestCase(join(root, file), full_path, self.context,
mode, framework)
tests.append(test)
return tests
def GetBuildRequirements(self):
return ['sample', 'sample=shell']
def GetConfiguration(context, root):
return MozillaTestConfiguration(context, root)

View File

@ -33,6 +33,7 @@ import platform
import re
import subprocess
import sys
import tempfile
import time
import utils
@ -61,7 +62,7 @@ class ProgressIndicator(object):
case = test.case
self.AboutToRun(case)
output = case.Run()
if output.HasFailed():
if output.UnexpectedOutput():
self.failed += 1
self.failed_tests.append(output)
else:
@ -91,7 +92,7 @@ class SimpleProgressIndicator(ProgressIndicator):
def Done(self):
print
for failed in self.failed_tests:
print "=== %s ===" % failed.test.GetName()
print "=== %s ===" % failed.test.GetLabel()
print "Command: %s" % EscapeCommand(failed.command)
if failed.output.stderr:
print "--- stderr ---"
@ -113,11 +114,11 @@ class SimpleProgressIndicator(ProgressIndicator):
class VerboseProgressIndicator(SimpleProgressIndicator):
def AboutToRun(self, case):
print '%s:' % case.GetName(),
print '%s:' % case.GetLabel(),
sys.stdout.flush()
def has_run(self, output):
if output.HasFailed():
def HasRun(self, output):
if output.UnexpectedOutput():
print "FAIL"
else:
print "pass"
@ -128,11 +129,11 @@ class DotsProgressIndicator(SimpleProgressIndicator):
def AboutToRun(self, case):
pass
def has_run(self, output):
def HasRun(self, output):
total = self.succeeded + self.failed
if (total > 1) and (total % 50 == 1):
sys.stdout.write('\n')
if output.HasFailed():
if output.UnexpectedOutput():
sys.stdout.write('F')
sys.stdout.flush()
else:
@ -147,19 +148,19 @@ class CompactProgressIndicator(ProgressIndicator):
self.templates = templates
self.last_status_length = 0
self.start_time = time.time()
def Starting(self):
pass
def Done(self):
self.PrintProgress('Done')
def AboutToRun(self, case):
self.PrintProgress(case.GetName())
self.PrintProgress(case.GetLabel())
def HasRun(self, output):
if output.HasFailed():
print "\n--- Failed: %s ---" % str(output.test.GetName())
if output.UnexpectedOutput():
print "\n--- Failed: %s ---" % str(output.test.GetLabel())
print "Command: %s" % EscapeCommand(output.command)
stdout = output.output.stdout.strip()
if len(stdout):
@ -200,7 +201,7 @@ class ColorProgressIndicator(CompactProgressIndicator):
'stderr': "\033[31m%s\033[0m",
}
super(ColorProgressIndicator, self).__init__(cases, templates)
def ClearLine(self, last_line_length):
print "\033[1K\r",
@ -216,7 +217,7 @@ class MonochromeProgressIndicator(CompactProgressIndicator):
'max_length': 78
}
super(MonochromeProgressIndicator, self).__init__(cases, templates)
def ClearLine(self, last_line_length):
print ("\r" + (" " * last_line_length) + "\r"),
@ -244,12 +245,19 @@ class CommandOutput(object):
class TestCase(object):
def __init__(self, path):
def __init__(self, context, path):
self.path = path
self.context = context
def IsNegative(self):
return False
def IsFailureOutput(self, output):
return output.exit_code != 0
def Run(self):
command = self.GetCommand()
output = Execute(command)
output = Execute(command, self.context)
return TestOutput(self, command, output)
@ -260,27 +268,66 @@ class TestOutput(object):
self.command = command
self.output = output
def UnexpectedOutput(self):
if self.HasFailed():
outcome = FAIL
else:
outcome = PASS
return not outcome in self.test.outcomes
def HasFailed(self):
return self.output.exit_code != 0
execution_failed = self.test.IsFailureOutput(self.output)
if self.test.IsNegative():
return not execution_failed
else:
return execution_failed
def Execute(args):
if VERBOSE: print " ".join(args)
MAX_SLEEP_TIME = 0.1
INITIAL_SLEEP_TIME = 0.0001
SLEEP_TIME_FACTOR = 1.25
def RunProcess(context, **args):
if context.verbose: print "#", " ".join(args['args'])
process = subprocess.Popen(
args = args,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
shell = (platform.system() == 'Windows'),
**args
)
exit_code = process.wait()
output = process.stdout.read()
errors = process.stderr.read()
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 = fd_out,
stderr = fd_err,
)
os.close(fd_out)
os.close(fd_err)
output = file(outname).read()
errors = file(errname).read()
os.unlink(outname)
os.unlink(errname)
return CommandOutput(exit_code, output, errors)
def ExecuteNoCapture(args):
if VERBOSE: print " ".join(args)
process = subprocess.Popen(args = args)
exit_code = process.wait()
def ExecuteNoCapture(args, context):
(process, exit_code) = RunProcess(
context,
args = args,
)
return CommandOutput(exit_code, "", "")
@ -297,6 +344,14 @@ class TestConfiguration(object):
self.context = context
self.root = root
def Contains(self, path, file):
if len(path) > len(file):
return False
for i in xrange(len(path)):
if not path[i].match(file[i]):
return False
return True
class TestSuite(object):
@ -346,7 +401,7 @@ class LiteralTestSuite(TestSuite):
(name, rest) = CarCdr(path)
result = [ ]
for test in self.tests:
if not name or name == test.GetName():
if not name or name.match(test.GetName()):
result += test.GetBuildRequirements(rest, context)
return result
@ -355,29 +410,42 @@ class LiteralTestSuite(TestSuite):
result = [ ]
for test in self.tests:
test_name = test.GetName()
if not name or name == test_name:
if not name or name.match(test_name):
full_path = current_path + [test_name]
result += test.ListTests(full_path, rest, context, mode)
result += test.ListTests(full_path, path, context, mode)
return result
PREFIX = {'debug': '_g', 'release': ''}
class Context(object):
def __init__(self, workspace, buildspace, vm):
def __init__(self, workspace, buildspace, verbose, vm, timeout):
self.workspace = workspace
self.buildspace = buildspace
self.vm = vm
self.verbose = verbose
self.vm_root = vm
self.timeout = timeout
def GetVm(self, mode):
name = self.vm_root + PREFIX[mode]
if platform.system() == 'Windows':
return name + '.exe'
else:
return name
def RunTestCases(all_cases, progress):
cases_to_run = [ c for c in all_cases if not SKIP in c.outcomes ]
def DoSkip(case):
return SKIP in c.outcomes or SLOW in c.outcomes
cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
progress = PROGRESS_INDICATORS[progress](cases_to_run)
progress.Run()
def BuildRequirements(workspace, requirements, mode):
command_line = ['scons', '-Y', workspace, 'mode=' + ",".join(mode)] + requirements
output = ExecuteNoCapture(command_line)
def BuildRequirements(context, requirements, mode):
command_line = ['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)] + requirements
output = ExecuteNoCapture(command_line, context)
return output.exit_code == 0
@ -392,6 +460,7 @@ PASS = 'pass'
OKAY = 'okay'
TIMEOUT = 'timeout'
CRASH = 'crash'
SLOW = 'slow'
class Expression(object):
@ -424,7 +493,7 @@ class Outcome(Expression):
def GetOutcomes(self, env, defs):
if self.name in defs:
return defs[self.name].get_outcomes(env, defs)
return defs[self.name].GetOutcomes(env, defs)
else:
return ListSet([self.name])
@ -437,7 +506,7 @@ class ListSet(Set):
def __init__(self, elms):
self.elms = elms
def __str__(self):
return "ListSet%s" % str(self.elms)
@ -450,7 +519,7 @@ class ListSet(Set):
if not isinstance(that, ListSet):
return that.Union(self)
return ListSet(self.elms + [ x for x in that.elms if x not in self.elms ])
def IsEmpty(self):
return len(self.elms) == 0
@ -462,7 +531,7 @@ class Everything(Set):
def Union(self, that):
return self
def IsEmpty(self):
return False
@ -474,7 +543,7 @@ class Nothing(Set):
def Union(self, that):
return that
def IsEmpty(self):
return True
@ -527,7 +596,7 @@ class Tokenizer(object):
self.tokens = None
def Current(self, length = 1):
if not self.has_more(length): return ""
if not self.HasMore(length): return ""
return self.expr[self.index:self.index+length]
def HasMore(self, length = 1):
@ -540,7 +609,7 @@ class Tokenizer(object):
self.tokens.append(token)
def SkipSpaces(self):
while self.HasMore() and self.current().isspace():
while self.HasMore() and self.Current().isspace():
self.Advance()
def Tokenize(self):
@ -552,7 +621,7 @@ class Tokenizer(object):
if self.Current() == '(':
self.AddToken('(')
self.Advance()
elif self.current() == ')':
elif self.Current() == ')':
self.AddToken(')')
self.Advance()
elif self.Current() == '$':
@ -670,7 +739,7 @@ def ParseLogicalExpression(scan):
def ParseCondition(expr):
"""Parses a logical expression into an Expression object"""
tokens = Tokenizer(expr).tokenize()
tokens = Tokenizer(expr).Tokenize()
if not tokens:
print "Malformed expression: '%s'" % expr
return None
@ -705,8 +774,11 @@ class Configuration(object):
matches = [ r for r in all_rules if r.Contains(case.path) ]
outcomes = set([])
for rule in matches:
outcomes = outcomes.Union(rule.GetOutcomes(env, self.defs))
outcomes = outcomes.union(rule.GetOutcomes(env, self.defs))
unused_rules.discard(rule)
if not outcomes:
outcomes = [PASS]
case.outcomes = outcomes
result.append(ClassifiedTest(case, outcomes))
return (result, list(unused_rules))
@ -727,7 +799,8 @@ class Rule(object):
"""A single rule that specifies the expected outcome for a single
test."""
def __init__(self, path, value):
def __init__(self, raw_path, path, value):
self.raw_path = raw_path
self.path = path
self.value = value
@ -735,24 +808,26 @@ class Rule(object):
set = self.value.GetOutcomes(env, defs)
assert isinstance(set, ListSet)
return set.elms
def Contains(self, path):
if len(self.path) > len(path):
return False
for i in xrange(len(self.path)):
if path[i] != self.path[i]:
if not self.path[i].match(path[i]):
return False
return True
HEADER_PATTERN = re.compile(r'\[([^]]+)\]')
RULE_PATTERN = re.compile(r'\s*(%?)([^: ]*)\s*:(.*)')
RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$')
def ReadConfigurationInto(path, sections, defs):
current_section = Section(Constant(True))
sections.append(current_section)
prefix = []
for line in utils.ReadLinesFrom(path):
header_match = HEADER_PATTERN.match(line)
if header_match:
@ -764,12 +839,12 @@ def ReadConfigurationInto(path, sections, defs):
continue
rule_match = RULE_PATTERN.match(line)
if rule_match:
path = SplitPath(rule_match.group(2).strip())
value_str = rule_match.group(3).strip()
path = prefix + SplitPath(rule_match.group(1).strip())
value_str = rule_match.group(2).strip()
value = ParseCondition(value_str)
if not value:
return False
current_section.AddRule(Rule(path, value))
current_section.AddRule(Rule(rule_match.group(1), path, value))
continue
def_match = DEF_PATTERN.match(line)
if def_match:
@ -779,6 +854,10 @@ def ReadConfigurationInto(path, sections, defs):
return False
defs[name] = value
continue
prefix_match = PREFIX_PATTERN.match(line)
if prefix_match:
prefix = SplitPath(prefix_match.group(1).strip())
continue
print "Malformed line: '%s'." % line
return False
return True
@ -800,8 +879,8 @@ def ReadConfiguration(paths):
def BuildOptions():
result = optparse.OptionParser()
result.add_option("-m", "--mode", help="The test mode in which to run",
choices=['release', 'debug'])
result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)",
default='release')
result.add_option("-v", "--verbose", help="Verbose output",
default=False, action="store_true")
result.add_option("-p", "--progress",
@ -814,27 +893,31 @@ def BuildOptions():
default=False, action="store_true")
result.add_option("--report", help="Print a summary of the tests to be run",
default=False, action="store_true")
result.add_option("-s", "--suite", help="A test suite",
default=[], action="append")
result.add_option("-t", "--timeout", help="Timeout in seconds",
default=60, type="int")
return result
def ProcessOptions(options):
global VERBOSE
VERBOSE = options.verbose
mode = options.mode
if mode == 'all': mode = ['release', 'debug']
elif not mode: mode = ['release']
else: mode = [mode]
options.mode = mode
options.mode = options.mode.split(',')
for mode in options.mode:
if not mode in ['debug', 'release']:
print "Unknown mode %s" % mode
return False
return True
REPORT_TEMPLATE = """\
Total: %(total)i tests
* %(skipped)3d tests will be skipped
* %(nocrash)3d tests are expected to be flaky but not crash
* %(pass)3d tests are expected to pass
* %(fail_ok)3d tests are expected to fail that we won't fix
* %(fail)3d tests are expected to fail that we should fix\
* %(skipped)4d tests will be skipped
* %(nocrash)4d tests are expected to be flaky but not crash
* %(pass)4d tests are expected to pass
* %(fail_ok)4d tests are expected to fail that we won't fix
* %(fail)4d tests are expected to fail that we should fix\
"""
def PrintReport(cases):
@ -853,9 +936,28 @@ def PrintReport(cases):
}
class Pattern(object):
def __init__(self, pattern):
self.pattern = pattern
self.compiled = None
def match(self, str):
if not self.compiled:
pattern = "^" + self.pattern.replace('*', '.*') + "$"
self.compiled = re.compile(pattern)
return self.compiled.match(str)
def __str__(self):
return self.pattern
def SplitPath(s):
stripped = [ c.strip() for c in s.split('/') ]
return [ s for s in stripped if len(s) > 0 ]
return [ Pattern(s) for s in stripped if len(s) > 0 ]
BUILT_IN_TESTS = ['mjsunit', 'cctest']
def Main():
@ -869,11 +971,12 @@ def Main():
return 1
workspace = abspath(join(dirname(sys.argv[0]), '..'))
tests = ['mjsunit']
repositories = [TestRepository(join(workspace, 'test', name)) for name in tests]
repositories = [TestRepository(join(workspace, 'test', name)) for name in BUILT_IN_TESTS]
repositories += [TestRepository(a) for a in options.suite]
root = LiteralTestSuite(repositories)
if len(args) == 0:
paths = [[]]
paths = [SplitPath(t) for t in BUILT_IN_TESTS]
else:
paths = [ ]
for arg in args:
@ -882,36 +985,45 @@ def Main():
# First build the required targets
buildspace = abspath('.')
context = Context(workspace, buildspace, join(buildspace, 'shell'))
context = Context(workspace, buildspace, VERBOSE,
join(buildspace, 'shell'),
options.timeout)
if not options.no_build:
reqs = [ ]
for path in paths:
reqs += root.GetBuildRequirements(path, context)
reqs = list(set(reqs))
if len(reqs) > 0:
if not BuildRequirements(workspace, reqs, options.mode):
if not BuildRequirements(context, reqs, options.mode):
return 1
# Then list the tests
cases = [ ]
all_cases = [ ]
all_unused = [ ]
for path in paths:
for mode in options.mode:
cases += root.ListTests([], path, context, mode)
env = {
'mode': mode
}
test_list = root.ListTests([], path, context, mode)
(cases, unused_rules) = config.ClassifyTests(test_list, env)
all_cases += cases
all_unused.append(unused_rules)
env = { }
(cases, unused_rules) = config.ClassifyTests(cases, env)
# for rule in unused_rules:
# print "Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path])
for rule in unused_rules:
print "Rule for '%s' was not used." % "/".join(rule.path)
return 0
if options.report:
PrintReport(cases)
if len(cases) == 0:
PrintReport(all_cases)
if len(all_cases) == 0:
print "No tests to run."
else:
RunTestCases(cases, options.progress)
try:
RunTestCases(all_cases, options.progress)
except KeyboardInterrupt:
print "Interrupted"
return 1
return 0