Update V8 to r3431 as required by WebKit r51976.

Change-Id: I567392c3f8c0a0d5201a4249611ac4ccf468cd5b
diff --git a/tools/presubmit.py b/tools/presubmit.py
index c4f7853..3f27c00 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -28,9 +28,11 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+import md5
 import optparse
 import os
 from os.path import abspath, join, dirname, basename, exists
+import pickle
 import re
 import sys
 import subprocess
@@ -93,6 +95,50 @@
 """.split()
 
 
+class FileContentsCache(object):
+
+  def __init__(self, sums_file_name):
+    self.sums = {}
+    self.sums_file_name = sums_file_name
+
+  def Load(self):
+    try:
+      sums_file = None
+      try:
+        sums_file = open(self.sums_file_name, 'r')
+        self.sums = pickle.load(sums_file)
+      except IOError:
+        # File might not exist, this is OK.
+        pass
+    finally:
+      if sums_file:
+        sums_file.close()
+
+  def Save(self):
+    try:
+      sums_file = open(self.sums_file_name, 'w')
+      pickle.dump(self.sums, sums_file)
+    finally:
+      sums_file.close()
+
+  def FilterUnchangedFiles(self, files):
+    changed_or_new = []
+    for file in files:
+      try:
+        handle = open(file, "r")
+        file_sum = md5.new(handle.read()).digest()
+        if not file in self.sums or self.sums[file] != file_sum:
+          changed_or_new.append(file)
+          self.sums[file] = file_sum
+      finally:
+        handle.close()
+    return changed_or_new
+
+  def RemoveFile(self, file):
+    if file in self.sums:
+      self.sums.pop(file)
+
+
 class SourceFileProcessor(object):
   """
   Utility class that can run through a directory structure, find all relevant
@@ -108,7 +154,7 @@
     return True
 
   def IgnoreDir(self, name):
-    return name.startswith('.') or name == 'data'
+    return name.startswith('.') or name == 'data' or name == 'sputniktests'
 
   def IgnoreFile(self, name):
     return name.startswith('.')
@@ -137,7 +183,7 @@
               or (name == 'third_party'))
 
   IGNORE_LINT = ['flag-definitions.h']
-  
+
   def IgnoreFile(self, name):
     return (super(CppLintProcessor, self).IgnoreFile(name)
               or (name in CppLintProcessor.IGNORE_LINT))
@@ -146,13 +192,32 @@
     return ['src', 'public', 'samples', join('test', 'cctest')]
 
   def ProcessFiles(self, files, path):
+    good_files_cache = FileContentsCache('.cpplint-cache')
+    good_files_cache.Load()
+    files = good_files_cache.FilterUnchangedFiles(files)
+    if len(files) == 0:
+      print 'No changes in files detected. Skipping cpplint check.'
+      return True
+
     filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
     command = ['cpplint.py', '--filter', filt] + join(files)
     local_cpplint = join(path, "tools", "cpplint.py")
     if exists(local_cpplint):
       command = ['python', local_cpplint, '--filter', filt] + join(files)
-    process = subprocess.Popen(command)
-    return process.wait() == 0
+
+    process = subprocess.Popen(command, stderr=subprocess.PIPE)
+    LINT_ERROR_PATTERN = re.compile(r'^(.+)[:(]\d+[:)]')
+    while True:
+      out_line = process.stderr.readline()
+      if out_line == '' and process.poll() != None:
+        break
+      sys.stderr.write(out_line)
+      m = LINT_ERROR_PATTERN.match(out_line)
+      if m:
+        good_files_cache.RemoveFile(m.group(1))
+
+    good_files_cache.Save()
+    return process.returncode == 0
 
 
 COPYRIGHT_HEADER_PATTERN = re.compile(