Changed shell sample to take flags directly from the command-line. Added api call...
authorchristian.plesner.hansen <christian.plesner.hansen@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Aug 2008 10:11:39 +0000 (10:11 +0000)
committerchristian.plesner.hansen <christian.plesner.hansen@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Aug 2008 10:11:39 +0000 (10:11 +0000)
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

42 files changed:
SConstruct
public/v8.h
samples/process.cc
samples/shell.cc
src/SConscript
src/api.cc
src/assembler-arm-inl.h
src/assembler-arm.cc
src/assembler-arm.h
src/bootstrapper.cc
src/builtins.cc
src/codegen-arm.cc
src/factory.cc
src/factory.h
src/flags.cc
src/globals.h
src/heap-inl.h
src/heap.cc
src/heap.h
src/objects-debug.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/parser.cc
src/property.cc
src/property.h
src/runtime.cc
src/v8natives.js
test/cctest/cctest.cc
test/cctest/cctest.h
test/cctest/test-debug.cc
test/cctest/test-flags.cc
test/cctest/testcfg.py [new file with mode: 0644]
test/mjsunit/debug-script.js
test/mjsunit/function-source.js
test/mjsunit/mirror-object.js
test/mjsunit/regexp-multiline-stack-trace.js
test/mjsunit/regress/regress-1341167.js [new file with mode: 0644]
test/mjsunit/testcfg.py
test/mozilla/mozilla.status [new file with mode: 0644]
test/mozilla/testcfg.py [new file with mode: 0644]
tools/test.py

index 13e9dce..199afc4 100644 (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 PostprocessOptions(options):
+  # Adjust architecture if the simulator option has been set
+  if (options['simulator'] != 'none') and (options['arch'] != options['simulator']):
+    if 'arch' in ARGUMENTS:
+      # Print a warning if arch has explicitly been set
+      print "Warning: forcing architecture to match simulator (%s)" % options['simulator']
+    options['arch'] = options['simulator']
+
+
 def BuildSpecific(env, mode):
-  context = BuildContext(os=env['os'], arch=env['processor'],
-      toolchain=env['toolchain'], snapshot=env['snapshot'],
-      library=env['library'], samples=SplitList(env['sample']),
-      mode=mode)
+  options = {'mode': mode}
+  for option in SIMPLE_OPTIONS:
+    options[option] = env[option]
+  PostprocessOptions(options)
+
+  context = BuildContext(options, samples=SplitList(env['sample']))
 
-  library_flags = context.AddRelevantFlags({}, LIBRARY_FLAGS)
+  library_flags = context.AddRelevantFlags(os.environ, LIBRARY_FLAGS)
   v8_flags = context.AddRelevantFlags(library_flags, V8_EXTRA_FLAGS)
   jscre_flags = context.AddRelevantFlags(library_flags, JSCRE_EXTRA_FLAGS)
   dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS)
   cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS)  
-  sample_flags = context.AddRelevantFlags({}, SAMPLE_FLAGS)
+  sample_flags = context.AddRelevantFlags(os.environ, SAMPLE_FLAGS)
 
   context.flags = {
     'v8': v8_flags,
@@ -351,9 +418,9 @@ def BuildSpecific(env, mode):
   )
   
   # Link the object files into a library.
-  if context.library == 'static':
+  if context.options['library'] == 'static':
     library = env.StaticLibrary(library_name, object_files)
-  elif context.library == 'shared':
+  elif context.options['library'] == 'shared':
     # There seems to be a glitch in the way scons decides where to put
     # PDB files when compiling using MSVC so we specify it manually.
     # This should not affect any other platforms.
index be64d23..083f2c4 100644 (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();
 
index d468395..8f3c032 100644 (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;
index 73b979a..8ab60f3 100644 (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]));
-    }
-  }
-}
index a5a919a..135af67 100644 (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'],
index 2646448..a09f7d2 100644 (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));
index fbe8cce..6bc900a 100644 (file)
@@ -1,29 +1,38 @@
-// Copyright 2007-2008 Google Inc. All Rights Reserved.
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
 // Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
 //
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
 //
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 Google Inc. All Rights Reserved.
 
 #ifndef V8_ASSEMBLER_ARM_INL_H_
 #define V8_ASSEMBLER_ARM_INL_H_
index 2f56efd..de029cd 100644 (file)
@@ -1,29 +1,38 @@
-// Copyright 2006-2008 Google Inc. All Rights Reserved.
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
 // Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
 //
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
 //
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 Google Inc. All Rights Reserved.
 
 #include "v8.h"
 
index 43bedff..f8cdb00 100644 (file)
@@ -1,29 +1,38 @@
-// Copyright 2007-2008 Google Inc. All Rights Reserved.
+// Copyright (c) 1994-2006 Sun Microsystems Inc.
+// All Rights Reserved.
+//
 // Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// - Redistribution in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the
+// distribution.
 //
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
+// - Neither the name of Sun Microsystems or the names of contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
 //
 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The original source code covered by the above license above has been modified
+// significantly by Google Inc.
+// Copyright 2006-2008 Google Inc. All Rights Reserved.
 
 // A light-weight ARM Assembler
 // Generates user mode instructions for the ARM architecture up to version 5
index 6aceafe..0cb688e 100644 (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.
index b51c39b..9f95322 100644 (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 =
index 3f72b03..30c1e4b 100644 (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;
     }
-    default: UNREACHABLE();
-  }
-  __ Ret();
-}
-
 
-class SmiOpStub : public CodeStub {
- public:
-  SmiOpStub(Token::Value op, bool reversed)
-      : op_(op), reversed_(reversed) {}
-
- private:
-  Token::Value op_;
-  bool reversed_;
-
-  Major MajorKey() { return SmiOp; }
-  int MinorKey() {
-    return (op_ == Token::ADD ? 2 : 0) | (reversed_ ? 1 : 0);
-  }
-  void Generate(MacroAssembler* masm);
-  void GenerateShared(MacroAssembler* masm);
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR: {
+      Label slow, exit;
+      // tag check
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(ne, &slow);
+      switch (op_) {
+        case Token::BIT_OR:  __ orr(r0, r0, Operand(r1)); break;
+        case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
+        case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
+        default: UNREACHABLE();
+      }
+      __ b(&exit);
+      __ bind(&slow);
+      __ push(r1);  // restore stack
+      __ push(r0);
+      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
+      switch (op_) {
+        case Token::BIT_OR:  __ InvokeBuiltin("BIT_OR",  1, JUMP_JS); break;
+        case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, JUMP_JS); break;
+        case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, JUMP_JS); break;
+        default: UNREACHABLE();
+      }
+      __ bind(&exit);
+      break;
+    }
 
-  const char* GetName() { return "SmiOpStub"; }
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
+      Label slow, exit;
+      // tag check
+      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ tst(r2, Operand(kSmiTagMask));
+      __ b(ne, &slow);
+      // remove tags from operands (but keep sign)
+      __ mov(r3, Operand(r1, ASR, kSmiTagSize));  // x
+      __ mov(r2, Operand(r0, ASR, kSmiTagSize));  // y
+      // use only the 5 least significant bits of the shift count
+      __ and_(r2, r2, Operand(0x1f));
+      // perform operation
+      switch (op_) {
+        case Token::SAR:
+          __ mov(r3, Operand(r3, ASR, r2));
+          // no checks of result necessary
+          break;
 
-#ifdef DEBUG
-  void Print() {
-    PrintF("SmiOpStub (token %s), (reversed %s)\n",
-           Token::String(op_), reversed_ ? "true" : "false");
-  }
-#endif
-};
+        case Token::SHR:
+          __ mov(r3, Operand(r3, LSR, r2));
+          // check that the *unsigned* result fits in a smi
+          // neither of the two high-order bits can be set:
+          // - 0x80000000: high bit would be lost when smi tagging
+          // - 0x40000000: this number would convert to negative when
+          // smi tagging these two cases can only happen with shifts
+          // by 0 or 1 when handed a valid smi
+          __ and_(r2, r3, Operand(0xc0000000), SetCC);
+          __ b(ne, &slow);
+          break;
 
+        case Token::SHL:
+          __ mov(r3, Operand(r3, LSL, r2));
+          // check that the *signed* result fits in a smi
+          __ add(r2, r3, Operand(0x40000000), SetCC);
+          __ b(mi, &slow);
+          break;
 
-void SmiOpStub::Generate(MacroAssembler* masm) {
-  switch (op_) {
-    case Token::ADD: {
-      if (!reversed_) {
-        __ sub(r0, r0, Operand(r1));  // revert optimistic add
-        __ push(r0);
-        __ push(r1);
-        __ mov(r0, Operand(1));  // set number of arguments
-        __ InvokeBuiltin("ADD", 1, JUMP_JS);
-      } else {
-        __ sub(r0, r0, Operand(r1));  // revert optimistic add
-        __ push(r1);  // reversed
-        __ push(r0);
-        __ mov(r0, Operand(1));  // set number of arguments
-        __ InvokeBuiltin("ADD", 1, JUMP_JS);
+        default: UNREACHABLE();
       }
-      break;
-    }
-    case Token::SUB: {
-      if (!reversed_) {
-        __ push(r0);
-        __ push(r1);
-        __ mov(r0, Operand(1));  // set number of arguments
-        __ InvokeBuiltin("SUB", 1, JUMP_JS);
-      } else {
-        __ push(r1);
-        __ push(r0);
-        __ mov(r0, Operand(1));  // set number of arguments
-        __ InvokeBuiltin("SUB", 1, JUMP_JS);
+      // tag result and store it in r0
+      ASSERT(kSmiTag == 0);  // adjust code below
+      __ mov(r0, Operand(r3, LSL, kSmiTagSize));
+      __ b(&exit);
+      // slow case
+      __ bind(&slow);
+      __ push(r1);  // restore stack
+      __ push(r0);
+      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
+      switch (op_) {
+        case Token::SAR: __ InvokeBuiltin("SAR", 1, JUMP_JS); break;
+        case Token::SHR: __ InvokeBuiltin("SHR", 1, JUMP_JS); break;
+        case Token::SHL: __ InvokeBuiltin("SHL", 1, JUMP_JS); break;
+        default: UNREACHABLE();
       }
+      __ bind(&exit);
       break;
     }
+
     default: UNREACHABLE();
   }
+  __ Ret();
 }
 
+
 void StackCheckStub::Generate(MacroAssembler* masm) {
   Label within_limit;
   __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
@@ -1866,7 +1901,13 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
   switch (op) {
     case Token::ADD:  // fall through.
     case Token::SUB:  // fall through.
-    case Token::MUL: {
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR: {
       __ pop(r0);  // r0 : y
       __ pop(r1);  // r1 : x
       GenericBinaryOpStub stub(op);
@@ -1886,101 +1927,6 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
       break;
     }
 
-    case Token::BIT_OR:
-    case Token::BIT_AND:
-    case Token::BIT_XOR: {
-      Label slow, exit;
-      __ pop(r0);  // get y
-      __ pop(r1);  // get x
-      // tag check
-      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
-      ASSERT(kSmiTag == 0);  // adjust code below
-      __ tst(r2, Operand(kSmiTagMask));
-      __ b(ne, &slow);
-      switch (op) {
-        case Token::BIT_OR:  __ orr(r0, r0, Operand(r1)); break;
-        case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
-        case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
-        default: UNREACHABLE();
-      }
-      __ b(&exit);
-      __ bind(&slow);
-      __ push(r1);  // restore stack
-      __ push(r0);
-      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
-      switch (op) {
-        case Token::BIT_OR:  __ InvokeBuiltin("BIT_OR",  1, CALL_JS); break;
-        case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, CALL_JS); break;
-        case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, CALL_JS); break;
-        default: UNREACHABLE();
-      }
-      __ bind(&exit);
-      break;
-    }
-
-    case Token::SHL:
-    case Token::SHR:
-    case Token::SAR: {
-      Label slow, exit;
-      __ pop(r0);  // get y
-      __ pop(r1);  // get x
-      // tag check
-      __ orr(r2, r1, Operand(r0));  // r2 = x | y;
-      ASSERT(kSmiTag == 0);  // adjust code below
-      __ tst(r2, Operand(kSmiTagMask));
-      __ b(ne, &slow);
-      // remove tags from operands (but keep sign)
-      __ mov(r3, Operand(r1, ASR, kSmiTagSize));
-      __ mov(r2, Operand(r0, ASR, kSmiTagSize));
-      // use only the 5 least significant bits of the shift count
-      __ and_(r2, r2, Operand(0x1f));
-      // perform operation
-      switch (op) {
-        case Token::SAR:
-          __ mov(r3, Operand(r3, ASR, r2));
-          // no checks of result necessary
-          break;
-
-        case Token::SHR:
-          __ mov(r3, Operand(r3, LSR, r2));
-          // check that the *unsigned* result fits in a smi
-          // neither of the two high-order bits can be set:
-          // - 0x80000000: high bit would be lost when smi tagging
-          // - 0x40000000: this number would convert to negative when
-          // smi tagging these two cases can only happen with shifts
-          // by 0 or 1 when handed a valid smi
-          __ and_(r2, r3, Operand(0xc0000000), SetCC);
-          __ b(ne, &slow);
-          break;
-
-        case Token::SHL:
-          __ mov(r3, Operand(r3, LSL, r2));
-          // check that the *signed* result fits in a smi
-          __ add(r2, r3, Operand(0x40000000), SetCC);
-          __ b(mi, &slow);
-          break;
-
-        default: UNREACHABLE();
-      }
-      // tag result and store it in r0
-      ASSERT(kSmiTag == 0);  // adjust code below
-      __ mov(r0, Operand(r3, LSL, kSmiTagSize));
-      __ b(&exit);
-      // slow case
-      __ bind(&slow);
-      __ push(r1);  // restore stack
-      __ push(r0);
-      __ mov(r0, Operand(1));  // 1 argument (not counting receiver).
-      switch (op) {
-        case Token::SAR: __ InvokeBuiltin("SAR", 1, CALL_JS); break;
-        case Token::SHR: __ InvokeBuiltin("SHR", 1, CALL_JS); break;
-        case Token::SHL: __ InvokeBuiltin("SHL", 1, CALL_JS); break;
-        default: UNREACHABLE();
-      }
-      __ bind(&exit);
-      break;
-    }
-
     case Token::COMMA:
       __ pop(r0);
       // simply discard left value
@@ -1995,6 +1941,82 @@ void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
 }
 
 
+class DeferredInlinedSmiOperation: public DeferredCode {
+ public:
+  DeferredInlinedSmiOperation(CodeGenerator* generator, Token::Value op,
+                              int value, bool reversed) :
+      DeferredCode(generator), op_(op), value_(value), reversed_(reversed) {
+    set_comment("[ DeferredInlinedSmiOperation");
+  }
+
+  virtual void Generate() {
+    switch (op_) {
+      case Token::ADD: {
+        if (reversed_) {
+          // revert optimistic add
+          __ sub(r0, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r1, Operand(Smi::FromInt(value_)));  // x
+        } else {
+          // revert optimistic add
+          __ sub(r1, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::SUB: {
+        if (reversed_) {
+          // revert optimistic sub
+          __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r1, Operand(Smi::FromInt(value_)));
+        } else {
+          __ add(r1, r0, Operand(Smi::FromInt(value_)));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::BIT_OR:
+      case Token::BIT_XOR:
+      case Token::BIT_AND: {
+        if (reversed_) {
+          __ mov(r1, Operand(Smi::FromInt(value_)));
+        } else {
+          __ mov(r1, Operand(r0));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        }
+        break;
+      }
+
+      case Token::SHL:
+      case Token::SHR:
+      case Token::SAR: {
+        if (!reversed_) {
+          __ mov(r1, Operand(r0));
+          __ mov(r0, Operand(Smi::FromInt(value_)));
+        } else {
+          UNREACHABLE();  // should have been handled in SmiOperation
+        }
+        break;
+      }
+
+      default:
+        // other cases should have been handled before this point.
+        UNREACHABLE();
+        break;
+    }
+
+    GenericBinaryOpStub igostub(op_);
+    __ CallStub(&igostub);
+  }
+
+ private:
+  Token::Value op_;
+  int value_;
+  bool reversed_;
+};
+
+
 void ArmCodeGenerator::SmiOperation(Token::Value op,
                                     Handle<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;
     }
 
index 3bbf53c..78c56ca 100644 (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);
   }
 
index 883a9c5..432f9ca 100644 (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>,
index cb5e08d..2431460 100644 (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
index 095288d..5f7d557 100644 (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
 };
 
 
index 49460cc..22ef441 100644 (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
index a7e71a7..d81c612 100644 (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.
index cd2fb2a..24d08f5 100644 (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,
index d12b7d3..00b086e 100644 (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:
index ed84ce4..f7978ae 100644 (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));
index 1704c05..a1624a5 100644 (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;
index 8ad0930..e61a4f9 100644 (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
index b48f568..042af9f 100644 (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);
index 7cbe2c5..7546195 100644 (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;
   }
 }
 
index 3cb2752..5fd2323 100644 (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()); }
index f61273e..b4a8b3b 100644 (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());
   }
index 3755f74..d97345e 100644 (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);
index 53604f4..eef295f 100644 (file)
 // (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;
 }
index ee2794c..e3de881 100644 (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_;
 };
 
index 94013d5..5a49f38 100644 (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);
index 99ee19c..7b1b988 100644 (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);
 }
 
 
diff --git a/test/cctest/testcfg.py b/test/cctest/testcfg.py
new file mode 100644 (file)
index 0000000..552fac3
--- /dev/null
@@ -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)
index d4da499..5a5caf1 100644 (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.
index 88b0f48..ddb53b4 100644 (file)
@@ -47,5 +47,3 @@ function g() {
 assertEquals(Debug.scriptSource(f), Debug.scriptSource(g));
 f();
 g();
-
-assertEquals("function print() { [native code] }", print);
index 4dc7363..75962d9 100644 (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');
 
index a4acc8a..cc960cb 100644 (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.
diff --git a/test/mjsunit/regress/regress-1341167.js b/test/mjsunit/regress/regress-1341167.js
new file mode 100644 (file)
index 0000000..5367d23
--- /dev/null
@@ -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);
index 4fcd0a6..bd056d5 100644 (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):
diff --git a/test/mozilla/mozilla.status b/test/mozilla/mozilla.status
new file mode 100644 (file)
index 0000000..2fe1da7
--- /dev/null
@@ -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
diff --git a/test/mozilla/testcfg.py b/test/mozilla/testcfg.py
new file mode 100644 (file)
index 0000000..a43ee0c
--- /dev/null
@@ -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)
index 17b5003..43d7804 100644 (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
+
+
+MAX_SLEEP_TIME = 0.1
+INITIAL_SLEEP_TIME = 0.0001
+SLEEP_TIME_FACTOR = 1.25
 
 
-def Execute(args):
-  if VERBOSE: print " ".join(args)
+def RunProcess(context, **args):
+  if context.verbose: print "#", " ".join(args['args'])
   process = subprocess.Popen(
+    shell = (platform.system() == 'Windows'),
+    **args
+  )
+  exit_code = None
+  sleep_time = INITIAL_SLEEP_TIME
+  while exit_code is None:
+    exit_code = process.poll()
+    time.sleep(sleep_time)
+    sleep_time = sleep_time * SLEEP_TIME_FACTOR
+    if sleep_time > MAX_SLEEP_TIME:
+      sleep_time = MAX_SLEEP_TIME
+  return (process, exit_code)
+
+
+def Execute(args, context):
+  (fd_out, outname) = tempfile.mkstemp()
+  (fd_err, errname) = tempfile.mkstemp()
+  (process, exit_code) = RunProcess(
+    context,
     args = args,
-    stdout = subprocess.PIPE,
-    stderr = subprocess.PIPE
+    stdout = fd_out,
+    stderr = fd_err,
   )
-  exit_code = process.wait()
-  output = process.stdout.read()
-  errors = process.stderr.read()
+  os.close(fd_out)
+  os.close(fd_err)
+  output = file(outname).read()
+  errors = file(errname).read()
+  os.unlink(outname)
+  os.unlink(errname)
   return CommandOutput(exit_code, output, errors)
 
 
-def ExecuteNoCapture(args):
-  if VERBOSE: print " ".join(args)
-  process = subprocess.Popen(args = args)
-  exit_code = process.wait()
+def ExecuteNoCapture(args, context):
+  (process, exit_code) = RunProcess(
+    context,
+    args = args,
+  )
   return CommandOutput(exit_code, "", "")
 
 
@@ -297,6 +344,14 @@ class TestConfiguration(object):
     self.context = context
     self.root = root
 
+  def Contains(self, path, file):
+    if len(path) > len(file):
+      return False
+    for i in xrange(len(path)):
+      if not path[i].match(file[i]):
+        return False
+    return True
+
 
 class TestSuite(object):
 
@@ -346,7 +401,7 @@ class LiteralTestSuite(TestSuite):
     (name, rest) = CarCdr(path)
     result = [ ]
     for test in self.tests:
-      if not name or name == test.GetName():
+      if not name or name.match(test.GetName()):
         result += test.GetBuildRequirements(rest, context)
     return result
 
@@ -355,29 +410,42 @@ class LiteralTestSuite(TestSuite):
     result = [ ]
     for test in self.tests:
       test_name = test.GetName()
-      if not name or name == test_name:
+      if not name or name.match(test_name):
         full_path = current_path + [test_name]
-        result += test.ListTests(full_path, rest, context, mode)
+        result += test.ListTests(full_path, path, context, mode)
     return result
 
 
+PREFIX = {'debug': '_g', 'release': ''}
+
+
 class Context(object):
 
-  def __init__(self, workspace, buildspace, vm):
+  def __init__(self, workspace, buildspace, verbose, vm, timeout):
     self.workspace = workspace
     self.buildspace = buildspace
-    self.vm = vm
-
+    self.verbose = verbose
+    self.vm_root = vm
+    self.timeout = timeout
+
+  def GetVm(self, mode):
+    name = self.vm_root + PREFIX[mode]
+    if platform.system() == 'Windows':
+      return name + '.exe'
+    else:
+      return name
 
 def RunTestCases(all_cases, progress):
-  cases_to_run = [ c for c in all_cases if not SKIP in c.outcomes ]
+  def DoSkip(case):
+    return SKIP in c.outcomes or SLOW in c.outcomes
+  cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
   progress = PROGRESS_INDICATORS[progress](cases_to_run)
   progress.Run()
 
 
-def BuildRequirements(workspace, requirements, mode):
-  command_line = ['scons', '-Y', workspace, 'mode=' + ",".join(mode)] + requirements
-  output = ExecuteNoCapture(command_line)
+def BuildRequirements(context, requirements, mode):
+  command_line = ['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)] + requirements
+  output = ExecuteNoCapture(command_line, context)
   return output.exit_code == 0
 
 
@@ -392,6 +460,7 @@ PASS = 'pass'
 OKAY = 'okay'
 TIMEOUT = 'timeout'
 CRASH = 'crash'
+SLOW = 'slow'
 
 
 class Expression(object):
@@ -424,7 +493,7 @@ class Outcome(Expression):
 
   def GetOutcomes(self, env, defs):
     if self.name in defs:
-      return defs[self.name].get_outcomes(env, defs)
+      return defs[self.name].GetOutcomes(env, defs)
     else:
       return ListSet([self.name])
 
@@ -437,7 +506,7 @@ class ListSet(Set):
 
   def __init__(self, elms):
     self.elms = elms
-  
+
   def __str__(self):
     return "ListSet%s" % str(self.elms)
 
@@ -450,7 +519,7 @@ class ListSet(Set):
     if not isinstance(that, ListSet):
       return that.Union(self)
     return ListSet(self.elms + [ x for x in that.elms if x not in self.elms ])
-  
+
   def IsEmpty(self):
     return len(self.elms) == 0
 
@@ -462,7 +531,7 @@ class Everything(Set):
 
   def Union(self, that):
     return self
-  
+
   def IsEmpty(self):
     return False
 
@@ -474,7 +543,7 @@ class Nothing(Set):
 
   def Union(self, that):
     return that
-  
+
   def IsEmpty(self):
     return True
 
@@ -527,7 +596,7 @@ class Tokenizer(object):
     self.tokens = None
 
   def Current(self, length = 1):
-    if not self.has_more(length): return ""
+    if not self.HasMore(length): return ""
     return self.expr[self.index:self.index+length]
 
   def HasMore(self, length = 1):
@@ -540,7 +609,7 @@ class Tokenizer(object):
     self.tokens.append(token)
 
   def SkipSpaces(self):
-    while self.HasMore() and self.current().isspace():
+    while self.HasMore() and self.Current().isspace():
       self.Advance()
 
   def Tokenize(self):
@@ -552,7 +621,7 @@ class Tokenizer(object):
       if self.Current() == '(':
         self.AddToken('(')
         self.Advance()
-      elif self.current() == ')':
+      elif self.Current() == ')':
         self.AddToken(')')
         self.Advance()
       elif self.Current() == '$':
@@ -670,7 +739,7 @@ def ParseLogicalExpression(scan):
 
 def ParseCondition(expr):
   """Parses a logical expression into an Expression object"""
-  tokens = Tokenizer(expr).tokenize()
+  tokens = Tokenizer(expr).Tokenize()
   if not tokens:
     print "Malformed expression: '%s'" % expr
     return None
@@ -705,8 +774,11 @@ class Configuration(object):
       matches = [ r for r in all_rules if r.Contains(case.path) ]
       outcomes = set([])
       for rule in matches:
-        outcomes = outcomes.Union(rule.GetOutcomes(env, self.defs))
+        outcomes = outcomes.union(rule.GetOutcomes(env, self.defs))
         unused_rules.discard(rule)
+      if not outcomes:
+        outcomes = [PASS]
+      case.outcomes = outcomes
       result.append(ClassifiedTest(case, outcomes))
     return (result, list(unused_rules))
 
@@ -727,7 +799,8 @@ class Rule(object):
   """A single rule that specifies the expected outcome for a single
   test."""
 
-  def __init__(self, path, value):
+  def __init__(self, raw_path, path, value):
+    self.raw_path = raw_path
     self.path = path
     self.value = value
 
@@ -735,24 +808,26 @@ class Rule(object):
     set = self.value.GetOutcomes(env, defs)
     assert isinstance(set, ListSet)
     return set.elms
-  
+
   def Contains(self, path):
     if len(self.path) > len(path):
       return False
     for i in xrange(len(self.path)):
-      if path[i] != self.path[i]:
+      if not self.path[i].match(path[i]):
         return False
     return True
 
 
 HEADER_PATTERN = re.compile(r'\[([^]]+)\]')
-RULE_PATTERN = re.compile(r'\s*(%?)([^: ]*)\s*:(.*)')
+RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
 DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
+PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$')
 
 
 def ReadConfigurationInto(path, sections, defs):
   current_section = Section(Constant(True))
   sections.append(current_section)
+  prefix = []
   for line in utils.ReadLinesFrom(path):
     header_match = HEADER_PATTERN.match(line)
     if header_match:
@@ -764,12 +839,12 @@ def ReadConfigurationInto(path, sections, defs):
       continue
     rule_match = RULE_PATTERN.match(line)
     if rule_match:
-      path = SplitPath(rule_match.group(2).strip())
-      value_str = rule_match.group(3).strip()
+      path = prefix + SplitPath(rule_match.group(1).strip())
+      value_str = rule_match.group(2).strip()
       value = ParseCondition(value_str)
       if not value:
         return False
-      current_section.AddRule(Rule(path, value))
+      current_section.AddRule(Rule(rule_match.group(1), path, value))
       continue
     def_match = DEF_PATTERN.match(line)
     if def_match:
@@ -779,6 +854,10 @@ def ReadConfigurationInto(path, sections, defs):
         return False
       defs[name] = value
       continue
+    prefix_match = PREFIX_PATTERN.match(line)
+    if prefix_match:
+      prefix = SplitPath(prefix_match.group(1).strip())
+      continue
     print "Malformed line: '%s'." % line
     return False
   return True
@@ -800,8 +879,8 @@ def ReadConfiguration(paths):
 
 def BuildOptions():
   result = optparse.OptionParser()
-  result.add_option("-m", "--mode", help="The test mode in which to run",
-      choices=['release', 'debug'])
+  result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)",
+      default='release')
   result.add_option("-v", "--verbose", help="Verbose output",
       default=False, action="store_true")
   result.add_option("-p", "--progress",
@@ -814,27 +893,31 @@ def BuildOptions():
       default=False, action="store_true")
   result.add_option("--report", help="Print a summary of the tests to be run",
       default=False, action="store_true")
+  result.add_option("-s", "--suite", help="A test suite",
+      default=[], action="append")
+  result.add_option("-t", "--timeout", help="Timeout in seconds",
+      default=60, type="int")
   return result
 
 
 def ProcessOptions(options):
   global VERBOSE
   VERBOSE = options.verbose
-  mode = options.mode
-  if mode == 'all': mode = ['release', 'debug']
-  elif not mode: mode = ['release']
-  else: mode = [mode]
-  options.mode = mode
+  options.mode = options.mode.split(',')
+  for mode in options.mode:
+    if not mode in ['debug', 'release']:
+      print "Unknown mode %s" % mode
+      return False
   return True
 
 
 REPORT_TEMPLATE = """\
 Total: %(total)i tests
- * %(skipped)3d tests will be skipped
- * %(nocrash)3d tests are expected to be flaky but not crash
- * %(pass)3d tests are expected to pass
- * %(fail_ok)3d tests are expected to fail that we won't fix
- * %(fail)3d tests are expected to fail that we should fix\
+ * %(skipped)4d tests will be skipped
+ * %(nocrash)4d tests are expected to be flaky but not crash
+ * %(pass)4d tests are expected to pass
+ * %(fail_ok)4d tests are expected to fail that we won't fix
+ * %(fail)4d tests are expected to fail that we should fix\
 """
 
 def PrintReport(cases):
@@ -853,9 +936,28 @@ def PrintReport(cases):
   }
 
 
+class Pattern(object):
+
+  def __init__(self, pattern):
+    self.pattern = pattern
+    self.compiled = None
+
+  def match(self, str):
+    if not self.compiled:
+      pattern = "^" + self.pattern.replace('*', '.*') + "$"
+      self.compiled = re.compile(pattern)
+    return self.compiled.match(str)
+
+  def __str__(self):
+    return self.pattern
+
+
 def SplitPath(s):
   stripped = [ c.strip() for c in s.split('/') ]
-  return [ s for s in stripped if len(s) > 0 ]
+  return [ Pattern(s) for s in stripped if len(s) > 0 ]
+
+
+BUILT_IN_TESTS = ['mjsunit', 'cctest']
 
 
 def Main():
@@ -869,11 +971,12 @@ def Main():
     return 1
 
   workspace = abspath(join(dirname(sys.argv[0]), '..'))
-  tests = ['mjsunit']
-  repositories = [TestRepository(join(workspace, 'test', name)) for name in tests]
+  repositories = [TestRepository(join(workspace, 'test', name)) for name in BUILT_IN_TESTS]
+  repositories += [TestRepository(a) for a in options.suite]
+
   root = LiteralTestSuite(repositories)
   if len(args) == 0:
-    paths = [[]]
+    paths = [SplitPath(t) for t in BUILT_IN_TESTS]
   else:
     paths = [ ]
     for arg in args:
@@ -882,36 +985,45 @@ def Main():
 
   # First build the required targets
   buildspace = abspath('.')
-  context = Context(workspace, buildspace, join(buildspace, 'shell'))
+  context = Context(workspace, buildspace, VERBOSE,
+                    join(buildspace, 'shell'),
+                    options.timeout)
   if not options.no_build:
     reqs = [ ]
     for path in paths:
       reqs += root.GetBuildRequirements(path, context)
     reqs = list(set(reqs))
     if len(reqs) > 0:
-      if not BuildRequirements(workspace, reqs, options.mode):
+      if not BuildRequirements(context, reqs, options.mode):
         return 1
 
   # Then list the tests
-  cases = [ ]
+  all_cases = [ ]
+  all_unused = [ ]
   for path in paths:
     for mode in options.mode:
-      cases += root.ListTests([], path, context, mode)
+      env = {
+        'mode': mode
+      }
+      test_list = root.ListTests([], path, context, mode)
+      (cases, unused_rules) = config.ClassifyTests(test_list, env)
+      all_cases += cases
+      all_unused.append(unused_rules)
 
-  env = { }
-  (cases, unused_rules) = config.ClassifyTests(cases, env)
+#  for rule in unused_rules:
+#    print "Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path])
 
-  for rule in unused_rules:
-    print "Rule for '%s' was not used." % "/".join(rule.path)
-    return 0
-  
   if options.report:
-    PrintReport(cases)
-  
-  if len(cases) == 0:
+    PrintReport(all_cases)
+
+  if len(all_cases) == 0:
     print "No tests to run."
   else:
-    RunTestCases(cases, options.progress)
+    try:
+      RunTestCases(all_cases, options.progress)
+    except KeyboardInterrupt:
+      print "Interrupted"
+      return 1
 
   return 0