New version of v8 from bleeding edge at revision 3649
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index ba7224b..4368eb8 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -199,9 +199,7 @@
       'conditions': [
         # The ARM assembler assumes the host is 32 bits, so force building
         # 32-bit host tools.
-        # TODO(piman): This assumes that the host is ia32 or amd64. Fixing the
-        # code would be better
-        ['target_arch=="arm" and _toolset=="host"', {
+        ['target_arch=="arm" and host_arch=="x64" and _toolset=="host"', {
           'cflags': ['-m32'],
           'ldflags': ['-m32'],
         }]
@@ -428,9 +426,7 @@
           'conditions': [
             # The ARM assembler assumes the host is 32 bits, so force building
             # 32-bit host tools.
-            # TODO(piman): This assumes that the host is ia32 or amd64. Fixing
-            # the code would be better
-            ['_toolset=="host"', {
+            ['host_arch=="x64" and _toolset=="host"', {
               'cflags': ['-m32'],
               'ldflags': ['-m32'],
             }]
@@ -598,9 +594,7 @@
       'conditions': [
         # The ARM assembler assumes the host is 32 bits, so force building
         # 32-bit host tools.
-        # TODO(piman): This assumes that the host is ia32 or amd64. Fixing
-        # the code would be better
-        ['target_arch=="arm" and _toolset=="host"', {
+        ['target_arch=="arm" and host_arch=="x64" and _toolset=="host"', {
           'cflags': ['-m32'],
           'ldflags': ['-m32'],
         }]
diff --git a/tools/jsmin.py b/tools/jsmin.py
index fd1abe4..646bf14 100644
--- a/tools/jsmin.py
+++ b/tools/jsmin.py
@@ -230,7 +230,9 @@
       # A regexp that matches a literal string surrounded by 'double quotes'.
       single_quoted_string = r"'(?:[^'\\]|\\.)*'"
       # A regexp that matches a regexp literal surrounded by /slashes/.
-      slash_quoted_regexp = r"/(?:[^/\\]|\\.)+/"
+      # Don't allow a regexp to have a ) before the first ( since that's a
+      # syntax error and it's probably just two unrelated slashes.
+      slash_quoted_regexp = r"/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\([^/\\]|\\.)*/"
       # Replace multiple spaces with a single space.
       line = re.sub("|".join([double_quoted_string,
                               single_quoted_string,
diff --git a/tools/presubmit.py b/tools/presubmit.py
index 3f27c00..04952e0 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -221,7 +221,7 @@
 
 
 COPYRIGHT_HEADER_PATTERN = re.compile(
-    r'Copyright [\d-]*200[8-9] the V8 project authors. All rights reserved.')
+    r'Copyright [\d-]*20[0-1][0-9] the V8 project authors. All rights reserved.')
 
 class SourceProcessor(SourceFileProcessor):
   """
diff --git a/tools/profile.js b/tools/profile.js
index db4b542..d41f5cd 100644
--- a/tools/profile.js
+++ b/tools/profile.js
@@ -163,6 +163,16 @@
 
 
 /**
+ * Retrieves a code entry by an address.
+ *
+ * @param {number} addr Entry address.
+ */
+devtools.profiler.Profile.prototype.findEntry = function(addr) {
+  return this.codeMap_.findEntry(addr);
+};
+
+
+/**
  * Records a tick event. Stack must contain a sequence of
  * addresses starting with the program counter value.
  *
@@ -345,6 +355,14 @@
 
 
 /**
+ * Returns raw node name (without type decoration).
+ */
+devtools.profiler.Profile.DynamicCodeEntry.prototype.getRawName = function() {
+  return this.name;
+};
+
+
+/**
  * Constructs a call graph.
  *
  * @constructor
diff --git a/tools/stats-viewer.py b/tools/stats-viewer.py
index bd6a8fb..14b2147 100755
--- a/tools/stats-viewer.py
+++ b/tools/stats-viewer.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+#
 # Copyright 2008 the V8 project authors. All rights reserved.
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
@@ -35,6 +37,7 @@
 
 import mmap
 import os
+import re
 import struct
 import sys
 import time
@@ -49,8 +52,9 @@
 COUNTER_LABELS = {"t": "%i ms.", "c": "%i"}
 
 
-# The magic number used to check if a file is not a counters file
+# The magic numbers used to check if a file is not a counters file
 COUNTERS_FILE_MAGIC_NUMBER = 0xDEADFACE
+CHROME_COUNTERS_FILE_MAGIC_NUMBER = 0x13131313
 
 
 class StatsViewer(object):
@@ -92,17 +96,31 @@
     something goes wrong print an informative message and exit the
     program."""
     if not os.path.exists(self.data_name):
-      print "File %s doesn't exist." % self.data_name
-      sys.exit(1)
+      maps_name = "/proc/%s/maps" % self.data_name
+      if not os.path.exists(maps_name):
+        print "\"%s\" is neither a counter file nor a PID." % self.data_name
+        sys.exit(1)
+      maps_file = open(maps_name, "r")
+      try:
+        m = re.search(r"/dev/shm/\S*", maps_file.read())
+        if m is not None and os.path.exists(m.group(0)):
+          self.data_name = m.group(0)
+        else:
+          print "Can't find counter file in maps for PID %s." % self.data_name
+          sys.exit(1)
+      finally:
+        maps_file.close()
     data_file = open(self.data_name, "r")
     size = os.fstat(data_file.fileno()).st_size
     fileno = data_file.fileno()
     self.shared_mmap = mmap.mmap(fileno, size, access=mmap.ACCESS_READ)
     data_access = SharedDataAccess(self.shared_mmap)
-    if data_access.IntAt(0) != COUNTERS_FILE_MAGIC_NUMBER:
-      print "File %s is not stats data." % self.data_name
-      sys.exit(1)
-    return CounterCollection(data_access)
+    if data_access.IntAt(0) == COUNTERS_FILE_MAGIC_NUMBER:
+      return CounterCollection(data_access)
+    elif data_access.IntAt(0) == CHROME_COUNTERS_FILE_MAGIC_NUMBER:
+      return ChromeCounterCollection(data_access)
+    print "File %s is not stats data." % self.data_name
+    sys.exit(1)
 
   def CleanUp(self):
     """Cleans up the memory mapped file if necessary."""
@@ -356,6 +374,72 @@
     return 4 + self.max_name_size
 
 
+class ChromeCounter(object):
+  """A pointer to a single counter withing a binary counters file."""
+
+  def __init__(self, data, name_offset, value_offset):
+    """Create a new instance.
+
+    Args:
+      data: the shared data access object containing the counter
+      name_offset: the byte offset of the start of this counter's name
+      value_offset: the byte offset of the start of this counter's value
+    """
+    self.data = data
+    self.name_offset = name_offset
+    self.value_offset = value_offset
+
+  def Value(self):
+    """Return the integer value of this counter."""
+    return self.data.IntAt(self.value_offset)
+
+  def Name(self):
+    """Return the ascii name of this counter."""
+    result = ""
+    index = self.name_offset
+    current = self.data.ByteAt(index)
+    while current:
+      result += chr(current)
+      index += 1
+      current = self.data.ByteAt(index)
+    return result
+
+
+class ChromeCounterCollection(object):
+  """An overlay over a counters file that provides access to the
+  individual counters contained in the file."""
+
+  _HEADER_SIZE = 4 * 4
+  _NAME_SIZE = 32
+
+  def __init__(self, data):
+    """Create a new instance.
+
+    Args:
+      data: the shared data access object
+    """
+    self.data = data
+    self.max_counters = data.IntAt(8)
+    self.max_threads = data.IntAt(12)
+    self.counter_names_offset = \
+        self._HEADER_SIZE + self.max_threads * (self._NAME_SIZE + 2 * 4)
+    self.counter_values_offset = \
+        self.counter_names_offset + self.max_counters * self._NAME_SIZE
+
+  def CountersInUse(self):
+    """Return the number of counters in active use."""
+    for i in xrange(self.max_counters):
+      if self.data.ByteAt(self.counter_names_offset + i * self._NAME_SIZE) == 0:
+        return i
+    return self.max_counters
+
+  def Counter(self, i):
+    """Return the i'th counter."""
+    return ChromeCounter(self.data,
+                         self.counter_names_offset + i * self._NAME_SIZE,
+                         self.counter_values_offset + i * self.max_threads * 4)
+
+
 def Main(data_file):
   """Run the stats counter.
 
@@ -367,6 +451,6 @@
 
 if __name__ == "__main__":
   if len(sys.argv) != 2:
-    print "Usage: stats-viewer.py <stats data>"
+    print "Usage: stats-viewer.py <stats data>|<test_shell pid>"
     sys.exit(1)
   Main(sys.argv[1])
diff --git a/tools/test.py b/tools/test.py
index 75b4f61..f17e9b1 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -639,10 +639,7 @@
       name = name + '.exe'
     return name
 
-def RunTestCases(all_cases, progress, tasks):
-  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) ]
+def RunTestCases(cases_to_run, progress, tasks):
   progress = PROGRESS_INDICATORS[progress](cases_to_run)
   return progress.Run(tasks)
 
@@ -1335,13 +1332,16 @@
     PrintReport(all_cases)
 
   result = None
-  if len(all_cases) == 0:
+  def DoSkip(case):
+    return SKIP in case.outcomes or SLOW in case.outcomes
+  cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
+  if len(cases_to_run) == 0:
     print "No tests to run."
     return 0
   else:
     try:
       start = time.time()
-      if RunTestCases(all_cases, options.progress, options.j):
+      if RunTestCases(cases_to_run, options.progress, options.j):
         result = 0
       else:
         result = 1
@@ -1355,7 +1355,7 @@
     # test output.
     print
     sys.stderr.write("--- Total time: %s ---\n" % FormatTime(duration))
-    timed_tests = [ t.case for t in all_cases if not t.case.duration is None ]
+    timed_tests = [ t.case for t in cases_to_run if not t.case.duration is None ]
     timed_tests.sort(lambda a, b: a.CompareTime(b))
     index = 1
     for entry in timed_tests[:20]:
diff --git a/tools/tickprocessor-driver.js b/tools/tickprocessor-driver.js
index dc67796..4201e43 100644
--- a/tools/tickprocessor-driver.js
+++ b/tools/tickprocessor-driver.js
@@ -44,10 +44,16 @@
 };
 
 var params = processArguments(arguments);
+var snapshotLogProcessor;
+if (params.snapshotLogFileName) {
+  snapshotLogProcessor = new SnapshotLogProcessor();
+  snapshotLogProcessor.processLogFile(params.snapshotLogFileName);
+}
 var tickProcessor = new TickProcessor(
   new (entriesProviders[params.platform])(params.nm),
   params.separateIc,
   params.ignoreUnknown,
-  params.stateFilter);
+  params.stateFilter,
+  snapshotLogProcessor);
 tickProcessor.processLogFile(params.logFileName);
 tickProcessor.printStatistics();
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index fd23987..c566c22 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -53,14 +53,79 @@
 
 
 function inherits(childCtor, parentCtor) {
-  function tempCtor() {};
-  tempCtor.prototype = parentCtor.prototype;
-  childCtor.prototype = new tempCtor();
+  childCtor.prototype.__proto__ = parentCtor.prototype;
+};
+
+
+function SnapshotLogProcessor() {
+  devtools.profiler.LogReader.call(this, {
+      'code-creation': {
+          parsers: [null, this.createAddressParser('code'), parseInt, null],
+          processor: this.processCodeCreation, backrefs: true },
+      'code-move': { parsers: [this.createAddressParser('code'),
+          this.createAddressParser('code-move-to')],
+          processor: this.processCodeMove, backrefs: true },
+      'code-delete': { parsers: [this.createAddressParser('code')],
+          processor: this.processCodeDelete, backrefs: true },
+      'snapshot-pos': { parsers: [this.createAddressParser('code'), parseInt],
+          processor: this.processSnapshotPosition, backrefs: true }});
+
+  Profile.prototype.handleUnknownCode = function(operation, addr) {
+    var op = devtools.profiler.Profile.Operation;
+    switch (operation) {
+      case op.MOVE:
+        print('Snapshot: Code move event for unknown code: 0x' +
+              addr.toString(16));
+        break;
+      case op.DELETE:
+        print('Snapshot: Code delete event for unknown code: 0x' +
+              addr.toString(16));
+        break;
+    }
+  };
+
+  this.profile_ = new Profile();
+  this.serializedEntries_ = [];
+}
+inherits(SnapshotLogProcessor, devtools.profiler.LogReader);
+
+
+SnapshotLogProcessor.prototype.processCodeCreation = function(
+    type, start, size, name) {
+  var entry = this.profile_.addCode(
+      this.expandAlias(type), name, start, size);
+};
+
+
+SnapshotLogProcessor.prototype.processCodeMove = function(from, to) {
+  this.profile_.moveCode(from, to);
+};
+
+
+SnapshotLogProcessor.prototype.processCodeDelete = function(start) {
+  this.profile_.deleteCode(start);
+};
+
+
+SnapshotLogProcessor.prototype.processSnapshotPosition = function(addr, pos) {
+  this.serializedEntries_[pos] = this.profile_.findEntry(addr);
+};
+
+
+SnapshotLogProcessor.prototype.processLogFile = function(fileName) {
+  var contents = readFile(fileName);
+  this.processLogChunk(contents);
+};
+
+
+SnapshotLogProcessor.prototype.getSerializedEntryName = function(pos) {
+  var entry = this.serializedEntries_[pos];
+  return entry ? entry.getRawName() : null;
 };
 
 
 function TickProcessor(
-    cppEntriesProvider, separateIc, ignoreUnknown, stateFilter) {
+    cppEntriesProvider, separateIc, ignoreUnknown, stateFilter, snapshotLogProcessor) {
   devtools.profiler.LogReader.call(this, {
       'shared-library': { parsers: [null, parseInt, parseInt],
           processor: this.processSharedLibrary },
@@ -72,6 +137,8 @@
           processor: this.processCodeMove, backrefs: true },
       'code-delete': { parsers: [this.createAddressParser('code')],
           processor: this.processCodeDelete, backrefs: true },
+      'snapshot-pos': { parsers: [this.createAddressParser('code'), parseInt],
+          processor: this.processSnapshotPosition, backrefs: true },
       'tick': { parsers: [this.createAddressParser('code'),
           this.createAddressParser('stack'), parseInt, 'var-args'],
           processor: this.processTick, backrefs: true },
@@ -95,6 +162,8 @@
   this.cppEntriesProvider_ = cppEntriesProvider;
   this.ignoreUnknown_ = ignoreUnknown;
   this.stateFilter_ = stateFilter;
+  this.snapshotLogProcessor_ = snapshotLogProcessor;
+  this.deserializedEntriesNames_ = [];
   var ticks = this.ticks_ =
     { total: 0, unaccounted: 0, excluded: 0, gc: 0 };
 
@@ -202,6 +271,7 @@
 
 TickProcessor.prototype.processCodeCreation = function(
     type, start, size, name) {
+  name = this.deserializedEntriesNames_[start] || name;
   var entry = this.profile_.addCode(
       this.expandAlias(type), name, start, size);
 };
@@ -217,6 +287,14 @@
 };
 
 
+TickProcessor.prototype.processSnapshotPosition = function(addr, pos) {
+  if (this.snapshotLogProcessor_) {
+    this.deserializedEntriesNames_[addr] =
+      this.snapshotLogProcessor_.getSerializedEntryName(pos);
+  }
+};
+
+
 TickProcessor.prototype.includeTick = function(vmState) {
   return this.stateFilter_ == null || this.stateFilter_ == vmState;
 };
@@ -648,7 +726,9 @@
     '--mac': ['platform', 'mac',
         'Specify that we are running on Mac OS X platform'],
     '--nm': ['nm', 'nm',
-        'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)']
+        'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)'],
+    '--snapshot-log': ['snapshotLogFileName', 'snapshot.log',
+        'Specify snapshot log file to use (e.g. --snapshot-log=snapshot.log)']
   };
   this.argsDispatch_['--js'] = this.argsDispatch_['-j'];
   this.argsDispatch_['--gc'] = this.argsDispatch_['-g'];
@@ -660,6 +740,7 @@
 
 ArgumentsProcessor.DEFAULTS = {
   logFileName: 'v8.log',
+  snapshotLogFileName: null,
   platform: 'unix',
   stateFilter: null,
   ignoreUnknown: false,