2013-11-22: Version 3.23.10

Remove preemption thread and API. (issue 3004)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@17998 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..8fa6b1a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,3 @@
+# Defines the Google C++ style for automatic reformatting.
+# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+BasedOnStyle: Google
diff --git a/ChangeLog b/ChangeLog
index 42ee840..73bfe96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+        2013-11-22: Version 3.23.10
+
+        Remove preemption thread and API.
+        (issue 3004)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-11-21: Version 3.23.9
 
         API: Change AdjustAmountOfExternalAllocatedMemory calls to use int64_t
diff --git a/build/features.gypi b/build/features.gypi
index 08ea11a..85b8a38 100644
--- a/build/features.gypi
+++ b/build/features.gypi
@@ -58,6 +58,9 @@
 
     # Enable compiler warnings when using V8_DEPRECATED apis.
     'v8_deprecation_warnings%': 0,
+
+    # Use the v8 provided v8::Platform implementation.
+    'v8_use_default_platform%': 1,
   },
   'target_defaults': {
     'conditions': [
@@ -85,6 +88,9 @@
       ['v8_enable_i18n_support==1', {
         'defines': ['V8_I18N_SUPPORT',],
       }],
+      ['v8_use_default_platform==1', {
+        'defines': ['V8_USE_DEFAULT_PLATFORM',],
+      }],
       ['v8_compress_startup_data=="bz2"', {
         'defines': [
           'COMPRESS_STARTUP_DATA_BZ2',
diff --git a/include/v8-platform.h b/include/v8-platform.h
new file mode 100644
index 0000000..75fddd5
--- /dev/null
+++ b/include/v8-platform.h
@@ -0,0 +1,86 @@
+// Copyright 2013 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
+// 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.
+
+#ifndef V8_V8_PLATFORM_H_
+#define V8_V8_PLATFORM_H_
+
+#include "v8.h"
+
+namespace v8 {
+
+/**
+ * A Task represents a unit of work.
+ */
+class Task {
+ public:
+  virtual ~Task() {}
+
+  virtual void Run() = 0;
+};
+
+/**
+ * V8 Platform abstraction layer.
+ *
+ * The embedder has to provide an implementation of this interface before
+ * initializing the rest of V8.
+ */
+class Platform {
+ public:
+  /**
+   * This enum is used to indicate whether a task is potentially long running,
+   * or causes a long wait. The embedder might want to use this hint to decide
+   * whether to execute the task on a dedicated thread.
+   */
+  enum ExpectedRuntime {
+    kShortRunningTask,
+    kLongRunningTask
+  };
+
+  /**
+   * Schedules a task to be invoked on a background thread. |expected_runtime|
+   * indicates that the task will run a long time. The Platform implementation
+   * takes ownership of |task|. There is no guarantee about order of execution
+   * of tasks wrt order of scheduling, nor is there a guarantee about the
+   * thread the task will be run on.
+   */
+  virtual void CallOnBackgroundThread(Task* task,
+                                      ExpectedRuntime expected_runtime) = 0;
+
+  /**
+   * Schedules a task to be invoked on a foreground thread wrt a specific
+   * |isolate|. Tasks posted for the same isolate should be execute in order of
+   * scheduling. The definition of "foreground" is opaque to V8.
+   */
+  virtual void CallOnForegroundThread(Isolate* isolate, Task* task) = 0;
+
+ protected:
+  virtual ~Platform() {}
+};
+
+}  // namespace v8
+
+#endif  // V8_V8_PLATFORM_H_
diff --git a/include/v8.h b/include/v8.h
index 6e227dd..e44c0bf 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -105,6 +105,7 @@
 class Object;
 class ObjectOperationDescriptor;
 class ObjectTemplate;
+class Platform;
 class Primitive;
 class RawOperationDescriptor;
 class Signature;
@@ -4798,6 +4799,18 @@
    */
   static bool InitializeICU();
 
+  /**
+   * Sets the v8::Platform to use. This should be invoked before V8 is
+   * initialized.
+   */
+  static void InitializePlatform(Platform* platform);
+
+  /**
+   * Clears all references to the v8::Platform. This should be invoked after
+   * V8 was disposed.
+   */
+  static void ShutdownPlatform();
+
  private:
   V8();
 
@@ -5271,12 +5284,6 @@
 
   ~Locker();
 
-  V8_DEPRECATED("This will be remvoed.",
-                static void StartPreemption(Isolate *isolate, int every_n_ms));
-
-  V8_DEPRECATED("This will be removed",
-                static void StopPreemption(Isolate* isolate));
-
   /**
    * Returns whether or not the locker for a given isolate, is locked by the
    * current thread.
diff --git a/src/api.cc b/src/api.cc
index a448e19..adc3e7a 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -5045,6 +5045,24 @@
 // --- E n v i r o n m e n t ---
 
 
+void v8::V8::InitializePlatform(Platform* platform) {
+#ifdef V8_USE_DEFAULT_PLATFORM
+  FATAL("Can't override v8::Platform when using default implementation");
+#else
+  i::V8::InitializePlatform(platform);
+#endif
+}
+
+
+void v8::V8::ShutdownPlatform() {
+#ifdef V8_USE_DEFAULT_PLATFORM
+  FATAL("Can't override v8::Platform when using default implementation");
+#else
+  i::V8::ShutdownPlatform();
+#endif
+}
+
+
 bool v8::V8::Initialize() {
   i::Isolate* isolate = i::Isolate::UncheckedCurrent();
   if (isolate != NULL && isolate->IsInitialized()) {
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index bc52fa8..322df91 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -40,6 +40,7 @@
 #include "objects-visiting.h"
 #include "platform.h"
 #include "snapshot.h"
+#include "trig-table.h"
 #include "extensions/externalize-string-extension.h"
 #include "extensions/gc-extension.h"
 #include "extensions/statistics-extension.h"
@@ -2635,6 +2636,44 @@
   InitializeExperimentalGlobal();
   if (!InstallExperimentalNatives()) return;
 
+  if (!Serializer::enabled()) {
+    Handle<JSBuiltinsObject> builtins(native_context()->builtins());
+    // Initialize trigonometric lookup tables and constants.
+    // The snapshot cannot contain typed arrays, and we don't need it to.
+    const int table_num_bytes = TrigonometricLookupTable::table_num_bytes();
+    v8::Local<v8::ArrayBuffer> sin_buffer = v8::ArrayBuffer::New(
+        TrigonometricLookupTable::sin_table(), table_num_bytes);
+    v8::Local<v8::ArrayBuffer> cos_buffer = v8::ArrayBuffer::New(
+        TrigonometricLookupTable::cos_x_interval_table(), table_num_bytes);
+    v8::Local<v8::Float64Array> sin_table = v8::Float64Array::New(
+        sin_buffer, 0, TrigonometricLookupTable::table_size());
+    v8::Local<v8::Float64Array> cos_table = v8::Float64Array::New(
+        cos_buffer, 0, TrigonometricLookupTable::table_size());
+
+    ForceSetProperty(builtins,
+                     factory()->InternalizeOneByteString(
+                         STATIC_ASCII_VECTOR("kSinTable")),
+                     Utils::OpenHandle(*sin_table),
+                     NONE);
+    ForceSetProperty(builtins,
+                     factory()->InternalizeOneByteString(
+                         STATIC_ASCII_VECTOR("kCosXIntervalTable")),
+                     Utils::OpenHandle(*cos_table),
+                     NONE);
+    ForceSetProperty(builtins,
+                     factory()->InternalizeOneByteString(
+                         STATIC_ASCII_VECTOR("kSamples")),
+                     factory()->NewHeapNumber(
+                         TrigonometricLookupTable::samples()),
+                     NONE);
+    ForceSetProperty(builtins,
+                     factory()->InternalizeOneByteString(
+                         STATIC_ASCII_VECTOR("kIndexConvert")),
+                     factory()->NewHeapNumber(
+                         TrigonometricLookupTable::samples_over_pi_half()),
+                     NONE);
+  }
+
   // Initially seed the per-context random number generator
   // using the per-isolate random number generator.
   uint32_t* state = reinterpret_cast<uint32_t*>(
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 62e19e1..3d42483 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -511,6 +511,22 @@
                             AllocationSite::kNestedSiteOffset),
                         graph()->GetConstant0());
 
+  // Pretenuring calculation fields.
+  Add<HStoreNamedField>(object,
+                        HObjectAccess::ForAllocationSiteOffset(
+                            AllocationSite::kMementoFoundCountOffset),
+                        graph()->GetConstant0());
+
+  Add<HStoreNamedField>(object,
+                        HObjectAccess::ForAllocationSiteOffset(
+                            AllocationSite::kMementoCreateCountOffset),
+                        graph()->GetConstant0());
+
+  Add<HStoreNamedField>(object,
+                        HObjectAccess::ForAllocationSiteOffset(
+                            AllocationSite::kPretenureDecisionOffset),
+                        graph()->GetConstant0());
+
   // Store an empty fixed array for the code dependency.
   HConstant* empty_fixed_array =
     Add<HConstant>(isolate()->factory()->empty_fixed_array());
@@ -992,16 +1008,10 @@
 
   // Make sure that both arguments are strings if not known in advance.
   if ((flags & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
-    IfBuilder if_leftnotstring(this);
-    if_leftnotstring.IfNot<HIsStringAndBranch>(left);
-    if_leftnotstring.Then();
-    if_leftnotstring.Deopt("Expected string for LHS of string addition");
+    left = BuildCheckString(left);
   }
   if ((flags & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
-    IfBuilder if_rightnotstring(this);
-    if_rightnotstring.IfNot<HIsStringAndBranch>(right);
-    if_rightnotstring.Then();
-    if_rightnotstring.Deopt("Expected string for RHS of string addition");
+    right = BuildCheckString(right);
   }
 
   return BuildStringAdd(left, right, pretenure_flag);
diff --git a/src/d8.cc b/src/d8.cc
index 5b128c0..41b08bc 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1379,43 +1379,6 @@
     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
       options.send_idle_notification = true;
       argv[i] = NULL;
-    } else if (strcmp(argv[i], "--preemption") == 0) {
-#ifdef V8_SHARED
-      printf("D8 with shared library does not support multi-threading\n");
-      return false;
-#else
-      options.use_preemption = true;
-      argv[i] = NULL;
-#endif  // V8_SHARED
-    } else if (strcmp(argv[i], "--nopreemption") == 0) {
-#ifdef V8_SHARED
-      printf("D8 with shared library does not support multi-threading\n");
-      return false;
-#else
-      options.use_preemption = false;
-      argv[i] = NULL;
-#endif  // V8_SHARED
-    } else if (strcmp(argv[i], "--preemption-interval") == 0) {
-#ifdef V8_SHARED
-      printf("D8 with shared library does not support multi-threading\n");
-      return false;
-#else
-      if (++i < argc) {
-        argv[i-1] = NULL;
-        char* end = NULL;
-        options.preemption_interval = strtol(argv[i], &end, 10);  // NOLINT
-        if (options.preemption_interval <= 0
-            || *end != '\0'
-            || errno == ERANGE) {
-          printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
-          return false;
-        }
-        argv[i] = NULL;
-      } else {
-        printf("Missing value for --preemption-interval\n");
-        return false;
-      }
-#endif  // V8_SHARED
     } else if (strcmp(argv[i], "-f") == 0) {
       // Ignore any -f flags for compatibility with other stand-alone
       // JavaScript engines.
@@ -1554,14 +1517,6 @@
         V8::IdleNotification(kLongIdlePauseInMs);
       }
     }
-
-#ifndef V8_SHARED
-    // Start preemption if threads have been created and preemption is enabled.
-    if (threads.length() > 0
-        && options.use_preemption) {
-      Locker::StartPreemption(isolate, options.preemption_interval);
-    }
-#endif  // V8_SHARED
   }
 
 #ifndef V8_SHARED
@@ -1574,11 +1529,6 @@
     thread->Join();
     delete thread;
   }
-
-  if (threads.length() > 0 && options.use_preemption) {
-    Locker lock(isolate);
-    Locker::StopPreemption(isolate);
-  }
 #endif  // V8_SHARED
   return 0;
 }
diff --git a/src/d8.h b/src/d8.h
index 8c1687e..761276e 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -219,8 +219,6 @@
  public:
   ShellOptions() :
 #ifndef V8_SHARED
-     use_preemption(true),
-     preemption_interval(10),
      num_parallel_files(0),
      parallel_files(NULL),
 #endif  // V8_SHARED
@@ -245,8 +243,6 @@
   }
 
 #ifndef V8_SHARED
-  bool use_preemption;
-  int preemption_interval;
   int num_parallel_files;
   char** parallel_files;
 #endif  // V8_SHARED
diff --git a/src/default-platform.cc b/src/default-platform.cc
new file mode 100644
index 0000000..ef3c4eb
--- /dev/null
+++ b/src/default-platform.cc
@@ -0,0 +1,56 @@
+// Copyright 2013 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
+// 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.
+
+#include "v8.h"
+
+#include "default-platform.h"
+
+namespace v8 {
+namespace internal {
+
+
+DefaultPlatform::DefaultPlatform() {}
+
+
+DefaultPlatform::~DefaultPlatform() {}
+
+void DefaultPlatform::CallOnBackgroundThread(Task *task,
+                                             ExpectedRuntime expected_runtime) {
+  // TODO(jochen): implement.
+  task->Run();
+  delete task;
+}
+
+
+void DefaultPlatform::CallOnForegroundThread(v8::Isolate* isolate, Task* task) {
+  // TODO(jochen): implement.
+  task->Run();
+  delete task;
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/default-platform.h b/src/default-platform.h
new file mode 100644
index 0000000..fe1bf8e
--- /dev/null
+++ b/src/default-platform.h
@@ -0,0 +1,55 @@
+// Copyright 2013 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
+// 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.
+
+#ifndef V8_DEFAULT_PLATFORM_H_
+#define V8_DEFAULT_PLATFORM_H_
+
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+class DefaultPlatform : public Platform {
+ public:
+  DefaultPlatform();
+  virtual ~DefaultPlatform();
+
+  // v8::Platform implementation.
+  virtual void CallOnBackgroundThread(
+      Task *task, ExpectedRuntime expected_runtime) V8_OVERRIDE;
+  virtual void CallOnForegroundThread(v8::Isolate *isolate,
+                                      Task *task) V8_OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DefaultPlatform);
+};
+
+
+} }  // namespace v8::internal
+
+
+#endif  // V8_DEFAULT_PLATFORM_H_
diff --git a/src/execution.cc b/src/execution.cc
index 8febbbf..32c616f 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -814,8 +814,6 @@
   // Clear the preempt request flag.
   isolate->stack_guard()->Continue(PREEMPT);
 
-  ContextSwitcher::PreemptionReceived();
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
   if (isolate->debug()->InDebugger()) {
     // If currently in the debugger don't do any actual preemption but record
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 62cb307..1c95885 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -611,10 +611,6 @@
 DEFINE_bool(profile_deserialization, false,
             "Print the time it takes to deserialize the snapshot.")
 
-// v8.cc
-DEFINE_bool(preemption, false,
-            "activate a 100ms timer that switches between V8 threads")
-
 // Regexp
 DEFINE_bool(regexp_optimization, true, "generate optimized regexp code")
 
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index b7b7f22..7e74d86 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -1526,6 +1526,15 @@
                        AllocationSite::kTransitionInfoOffset);
   SetInternalReference(site, entry, "nested_site", site->nested_site(),
                        AllocationSite::kNestedSiteOffset);
+  SetInternalReference(site, entry, "memento_found_count",
+                       site->memento_found_count(),
+                       AllocationSite::kMementoFoundCountOffset);
+  SetInternalReference(site, entry, "memento_create_count",
+                       site->memento_create_count(),
+                       AllocationSite::kMementoCreateCountOffset);
+  SetInternalReference(site, entry, "pretenure_decision",
+                       site->pretenure_decision(),
+                       AllocationSite::kPretenureDecisionOffset);
   SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
                        AllocationSite::kDependentCodeOffset);
 }
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index f7b3100..fd93ce3 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1273,17 +1273,14 @@
 }
 
 
-HValue* HGraphBuilder::BuildCheckString(
-    HValue* object, const char* failure_reason) {
-  if (!object->type().IsString()) {
-    ASSERT(!object->IsConstant() ||
-           !HConstant::cast(object)->HasStringValue());
-    IfBuilder if_isstring(this);
-    if_isstring.If<HIsStringAndBranch>(object);
-    if_isstring.Then();
-    if_isstring.ElseDeopt(failure_reason);
+HValue* HGraphBuilder::BuildCheckString(HValue* string) {
+  if (!string->type().IsString()) {
+    ASSERT(!string->IsConstant() ||
+           !HConstant::cast(string)->HasStringValue());
+    BuildCheckHeapObject(string);
+    return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
   }
-  return object;
+  return string;
 }
 
 
@@ -8657,14 +8654,12 @@
       (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
     // Validate type feedback for left argument.
     if (left_type->Is(Type::String())) {
-      left = BuildCheckString(
-          left, "Expected string for LHS of binary operation");
+      left = BuildCheckString(left);
     }
 
     // Validate type feedback for right argument.
     if (right_type->Is(Type::String())) {
-      right = BuildCheckString(
-          right, "Expected string for RHS of binary operation");
+      right = BuildCheckString(right);
     }
 
     // Convert left argument as necessary.
diff --git a/src/hydrogen.h b/src/hydrogen.h
index a117c55..d11fbc0 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1256,7 +1256,7 @@
 
   HValue* BuildCheckHeapObject(HValue* object);
   HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
-  HValue* BuildCheckString(HValue* object, const char* failure_reason);
+  HValue* BuildCheckString(HValue* string);
   HValue* BuildWrapReceiver(HValue* object, HValue* function);
 
   // Building common constructs
diff --git a/src/isolate.cc b/src/isolate.cc
index 7250246..2acc59a 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -1549,7 +1549,6 @@
       write_iterator_(NULL),
       global_handles_(NULL),
       eternal_handles_(NULL),
-      context_switcher_(NULL),
       thread_manager_(NULL),
       fp_stubs_generated_(false),
       has_installed_extensions_(false),
@@ -1690,10 +1689,6 @@
 
     delete deoptimizer_data_;
     deoptimizer_data_ = NULL;
-    if (FLAG_preemption) {
-      v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
-      v8::Locker::StopPreemption(reinterpret_cast<v8::Isolate*>(this));
-    }
     builtins_.TearDown();
     bootstrapper_->TearDown();
 
@@ -1805,8 +1800,6 @@
   delete write_iterator_;
   write_iterator_ = NULL;
 
-  delete context_switcher_;
-  context_switcher_ = NULL;
   delete thread_manager_;
   thread_manager_ = NULL;
 
@@ -2038,11 +2031,6 @@
     }
   }
 
-  if (FLAG_preemption) {
-    v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
-    v8::Locker::StartPreemption(reinterpret_cast<v8::Isolate*>(this), 100);
-  }
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
   debug_->SetUp(create_heap_objects);
 #endif
diff --git a/src/isolate.h b/src/isolate.h
index ed568b7..f280ee8 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -58,7 +58,6 @@
 class CodeTracer;
 class CompilationCache;
 class ContextSlotCache;
-class ContextSwitcher;
 class Counters;
 class CpuFeatures;
 class CpuProfiler;
@@ -919,12 +918,6 @@
 
   ThreadManager* thread_manager() { return thread_manager_; }
 
-  ContextSwitcher* context_switcher() { return context_switcher_; }
-
-  void set_context_switcher(ContextSwitcher* switcher) {
-    context_switcher_ = switcher;
-  }
-
   StringTracker* string_tracker() { return string_tracker_; }
 
   unibrow::Mapping<unibrow::Ecma262UnCanonicalize>* jsregexp_uncanonicalize() {
@@ -1293,7 +1286,6 @@
   ConsStringIteratorOp* write_iterator_;
   GlobalHandles* global_handles_;
   EternalHandles* eternal_handles_;
-  ContextSwitcher* context_switcher_;
   ThreadManager* thread_manager_;
   RuntimeState runtime_state_;
   bool fp_stubs_generated_;
diff --git a/src/math.js b/src/math.js
index 2df0ec2..c163d9a 100644
--- a/src/math.js
+++ b/src/math.js
@@ -79,7 +79,8 @@
 
 // ECMA 262 - 15.8.2.7
 function MathCos(x) {
-  return MathCosImpl(x);
+  x = MathAbs(x);  // Convert to number and get rid of -0.
+  return TrigonometricInterpolation(x, 1);
 }
 
 // ECMA 262 - 15.8.2.8
@@ -179,7 +180,9 @@
 
 // ECMA 262 - 15.8.2.16
 function MathSin(x) {
-  return MathSinImpl(x);
+  x = x * 1;  // Convert to number and deal with -0.
+  if (%_IsMinusZero(x)) return x;
+  return TrigonometricInterpolation(x, 0);
 }
 
 // ECMA 262 - 15.8.2.17
@@ -189,7 +192,7 @@
 
 // ECMA 262 - 15.8.2.18
 function MathTan(x) {
-  return MathSinImpl(x) / MathCosImpl(x);
+  return MathSin(x) / MathCos(x);
 }
 
 // Non-standard extension.
@@ -198,119 +201,73 @@
 }
 
 
-var MathSinImpl = function(x) {
-  InitTrigonometricFunctions();
-  return MathSinImpl(x);
-}
+var kInversePiHalf      = 0.636619772367581343;      // 2 / pi
+var kInversePiHalfS26   = 9.48637384723993156e-9;    // 2 / pi / (2^26)
+var kS26                = 1 << 26;
+var kTwoStepThreshold   = 1 << 27;
+// pi / 2 rounded up
+var kPiHalf             = 1.570796326794896780;      // 0x192d4454fb21f93f
+// We use two parts for pi/2 to emulate a higher precision.
+// pi_half_1 only has 26 significant bits for mantissa.
+// Note that pi_half > pi_half_1 + pi_half_2
+var kPiHalf1            = 1.570796325802803040;      // 0x00000054fb21f93f
+var kPiHalf2            = 9.920935796805404252e-10;  // 0x3326a611460b113e
 
+var kSamples;            // Initialized to a number during genesis.
+var kIndexConvert;       // Initialized to kSamples / (pi/2) during genesis.
+var kSinTable;           // Initialized to a Float64Array during genesis.
+var kCosXIntervalTable;  // Initialized to a Float64Array during genesis.
 
-var MathCosImpl = function(x) {
-  InitTrigonometricFunctions();
-  return MathCosImpl(x);
-}
-
-
-var InitTrigonometricFunctions;
-
-
-// Define constants and interpolation functions.
-// Also define the initialization function that populates the lookup table
-// and then wires up the function definitions.
-function SetupTrigonometricFunctions() {
-  var samples = 1800;   // Table size.  Do not change arbitrarily.
-  var inverse_pi_half      = 0.636619772367581343;      // 2 / pi
-  var inverse_pi_half_s_26 = 9.48637384723993156e-9;    // 2 / pi / (2^26)
-  var s_26 = 1 << 26;
-  var two_step_threshold   = 1 << 27;
-  var index_convert        = 1145.915590261646418;      // samples / (pi / 2)
-  // pi / 2 rounded up
-  var pi_half              = 1.570796326794896780;      // 0x192d4454fb21f93f
-  // We use two parts for pi/2 to emulate a higher precision.
-  // pi_half_1 only has 26 significant bits for mantissa.
-  // Note that pi_half > pi_half_1 + pi_half_2
-  var pi_half_1            = 1.570796325802803040;      // 0x00000054fb21f93f
-  var pi_half_2            = 9.920935796805404252e-10;  // 0x3326a611460b113e
-  var table_sin;
-  var table_cos_interval;
-
-  // This implements sine using the following algorithm.
-  // 1) Multiplication takes care of to-number conversion.
-  // 2) Reduce x to the first quadrant [0, pi/2].
-  //    Conveniently enough, in case of +/-Infinity, we get NaN.
-  //    Note that we try to use only 26 instead of 52 significant bits for
-  //    mantissa to avoid rounding errors when multiplying.  For very large
-  //    input we therefore have additional steps.
-  // 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
-  // 4) Do a table lookup for the closest samples to the left and right of x.
-  // 5) Find the derivatives at those sampling points by table lookup:
-  //    dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
-  // 6) Use cubic spline interpolation to approximate sin(x).
-  // 7) Negate the result if x was in the 3rd or 4th quadrant.
-  // 8) Get rid of -0 by adding 0.
-  var Interpolation = function(x, phase) {
-    if (x < 0 || x > pi_half) {
-      var multiple;
-      while (x < -two_step_threshold || x > two_step_threshold) {
-        // Let's assume this loop does not terminate.
-        // All numbers x in each loop forms a set S.
-        // (1) abs(x) > 2^27 for all x in S.
-        // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
-        // (3) multiple is rounded down in 2^26 steps, so the rounding error is
-        //     at most max(ulp, 2^26).
-        // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
-        //     (1-pi/4)x
-        // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
-        //     Note that this difference cannot be simply rounded off.
-        // Set S cannot exist since (5) violates (1).  Loop must terminate.
-        multiple = MathFloor(x * inverse_pi_half_s_26) * s_26;
-        x = x - multiple * pi_half_1 - multiple * pi_half_2;
-      }
-      multiple = MathFloor(x * inverse_pi_half);
-      x = x - multiple * pi_half_1 - multiple * pi_half_2;
-      phase += multiple;
+// This implements sine using the following algorithm.
+// 1) Multiplication takes care of to-number conversion.
+// 2) Reduce x to the first quadrant [0, pi/2].
+//    Conveniently enough, in case of +/-Infinity, we get NaN.
+//    Note that we try to use only 26 instead of 52 significant bits for
+//    mantissa to avoid rounding errors when multiplying.  For very large
+//    input we therefore have additional steps.
+// 3) Replace x by (pi/2-x) if x was in the 2nd or 4th quadrant.
+// 4) Do a table lookup for the closest samples to the left and right of x.
+// 5) Find the derivatives at those sampling points by table lookup:
+//    dsin(x)/dx = cos(x) = sin(pi/2-x) for x in [0, pi/2].
+// 6) Use cubic spline interpolation to approximate sin(x).
+// 7) Negate the result if x was in the 3rd or 4th quadrant.
+// 8) Get rid of -0 by adding 0.
+function TrigonometricInterpolation(x, phase) {
+  if (x < 0 || x > kPiHalf) {
+    var multiple;
+    while (x < -kTwoStepThreshold || x > kTwoStepThreshold) {
+      // Let's assume this loop does not terminate.
+      // All numbers x in each loop forms a set S.
+      // (1) abs(x) > 2^27 for all x in S.
+      // (2) abs(multiple) != 0 since (2^27 * inverse_pi_half_s26) > 1
+      // (3) multiple is rounded down in 2^26 steps, so the rounding error is
+      //     at most max(ulp, 2^26).
+      // (4) so for x > 2^27, we subtract at most (1+pi/4)x and at least
+      //     (1-pi/4)x
+      // (5) The subtraction results in x' so that abs(x') <= abs(x)*pi/4.
+      //     Note that this difference cannot be simply rounded off.
+      // Set S cannot exist since (5) violates (1).  Loop must terminate.
+      multiple = MathFloor(x * kInversePiHalfS26) * kS26;
+      x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
     }
-    var double_index = x * index_convert;
-    if (phase & 1) double_index = samples - double_index;
-    var index = double_index | 0;
-    var t1 = double_index - index;
-    var t2 = 1 - t1;
-    var y1 = table_sin[index];
-    var y2 = table_sin[index + 1];
-    var dy = y2 - y1;
-    return (t2 * y1 + t1 * y2 +
-                t1 * t2 * ((table_cos_interval[index] - dy) * t2 +
-                           (dy - table_cos_interval[index + 1]) * t1))
-           * (1 - (phase & 2)) + 0;
+    multiple = MathFloor(x * kInversePiHalf);
+    x = x - multiple * kPiHalf1 - multiple * kPiHalf2;
+    phase += multiple;
   }
-
-  var MathSinInterpolation = function(x) {
-    x = x * 1;  // Convert to number and deal with -0.
-    if (%_IsMinusZero(x)) return x;
-    return Interpolation(x, 0);
-  }
-
-  // Cosine is sine with a phase offset.
-  var MathCosInterpolation = function(x) {
-    x = MathAbs(x);  // Convert to number and get rid of -0.
-    return Interpolation(x, 1);
-  };
-
-  %SetInlineBuiltinFlag(Interpolation);
-  %SetInlineBuiltinFlag(MathSinInterpolation);
-  %SetInlineBuiltinFlag(MathCosInterpolation);
-
-  InitTrigonometricFunctions = function() {
-    table_sin = new global.Float64Array(samples + 2);
-    table_cos_interval = new global.Float64Array(samples + 2);
-    %PopulateTrigonometricTable(table_sin, table_cos_interval, samples);
-    MathSinImpl = MathSinInterpolation;
-    MathCosImpl = MathCosInterpolation;
-  }
+  var double_index = x * kIndexConvert;
+  if (phase & 1) double_index = kSamples - double_index;
+  var index = double_index | 0;
+  var t1 = double_index - index;
+  var t2 = 1 - t1;
+  var y1 = kSinTable[index];
+  var y2 = kSinTable[index + 1];
+  var dy = y2 - y1;
+  return (t2 * y1 + t1 * y2 +
+              t1 * t2 * ((kCosXIntervalTable[index] - dy) * t2 +
+                         (dy - kCosXIntervalTable[index + 1]) * t1))
+         * (1 - (phase & 2)) + 0;
 }
 
-SetupTrigonometricFunctions();
-
-
 // -------------------------------------------------------------------
 
 function SetUpMath() {
@@ -387,6 +344,7 @@
   %SetInlineBuiltinFlag(MathSin);
   %SetInlineBuiltinFlag(MathCos);
   %SetInlineBuiltinFlag(MathTan);
+  %SetInlineBuiltinFlag(TrigonometricInterpolation);
 }
 
 SetUpMath();
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index bc5d62a..43d83bd 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -3037,22 +3037,44 @@
 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
   Register arguments = ToRegister(instr->arguments());
   Register result = ToRegister(instr->result());
-  if (instr->length()->IsConstantOperand() &&
-      instr->index()->IsConstantOperand()) {
-    int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+  // There are two words between the frame pointer and the last argument.
+  // Subtracting from length accounts for one of them add one more.
+  if (instr->length()->IsConstantOperand()) {
     int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
-    int index = (const_length - const_index) + 1;
-    __ lw(result, MemOperand(arguments, index * kPointerSize));
+    if (instr->index()->IsConstantOperand()) {
+      int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+      int index = (const_length - const_index) + 1;
+      __ lw(result, MemOperand(arguments, index * kPointerSize));
+    } else {
+      Register index = ToRegister(instr->index());
+      __ li(at, Operand(const_length + 1));
+      __ Subu(result, at, index);
+      __ sll(at, result, kPointerSizeLog2);
+      __ Addu(at, arguments, at);
+      __ lw(result, MemOperand(at));
+    }
+  } else if (instr->index()->IsConstantOperand()) {
+    Register length = ToRegister(instr->length());
+    int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
+    int loc = const_index - 1;
+    if (loc != 0) {
+      __ Subu(result, length, Operand(loc));
+      __ sll(at, result, kPointerSizeLog2);
+      __ Addu(at, arguments, at);
+      __ lw(result, MemOperand(at));
+    } else {
+      __ sll(at, length, kPointerSizeLog2);
+      __ Addu(at, arguments, at);
+      __ lw(result, MemOperand(at));
+    }
   } else {
     Register length = ToRegister(instr->length());
     Register index = ToRegister(instr->index());
-    // There are two words between the frame pointer and the last argument.
-    // Subtracting from length accounts for one of them, add one more.
-    __ subu(length, length, index);
-    __ Addu(length, length, Operand(1));
-    __ sll(length, length, kPointerSizeLog2);
-    __ Addu(at, arguments, Operand(length));
-    __ lw(result, MemOperand(at, 0));
+    __ Subu(result, length, index);
+    __ Addu(result, result, 1);
+    __ sll(at, result, kPointerSizeLog2);
+    __ Addu(at, arguments, at);
+    __ lw(result, MemOperand(at));
   }
 }
 
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index abdc3e6..5dbef8d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -2472,15 +2472,8 @@
 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
   info()->MarkAsRequiresFrame();
   LOperand* args = UseRegister(instr->arguments());
-  LOperand* length;
-  LOperand* index;
-  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
-    length = UseRegisterOrConstant(instr->length());
-    index = UseOrConstant(instr->index());
-  } else {
-    length = UseTempRegister(instr->length());
-    index = UseRegisterAtStart(instr->index());
-  }
+  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
   return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
 }
 
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 2e8c0ad..7064ea9 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1314,6 +1314,9 @@
   set_transition_info(Smi::FromInt(0));
   SetElementsKind(GetInitialFastElementsKind());
   set_nested_site(Smi::FromInt(0));
+  set_memento_create_count(Smi::FromInt(0));
+  set_memento_found_count(Smi::FromInt(0));
+  set_pretenure_decision(Smi::FromInt(0));
   set_dependent_code(DependentCode::cast(GetHeap()->empty_fixed_array()),
                      SKIP_WRITE_BARRIER);
 }
@@ -3874,33 +3877,14 @@
 
 
 int Code::major_key() {
-  ASSERT(kind() == STUB ||
-         kind() == HANDLER ||
-         kind() == BINARY_OP_IC ||
-         kind() == COMPARE_IC ||
-         kind() == COMPARE_NIL_IC ||
-         kind() == STORE_IC ||
-         kind() == LOAD_IC ||
-         kind() == KEYED_LOAD_IC ||
-         kind() == KEYED_CALL_IC ||
-         kind() == TO_BOOLEAN_IC);
+  ASSERT(has_major_key());
   return StubMajorKeyField::decode(
       READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
 }
 
 
 void Code::set_major_key(int major) {
-  ASSERT(kind() == STUB ||
-         kind() == HANDLER ||
-         kind() == BINARY_OP_IC ||
-         kind() == COMPARE_IC ||
-         kind() == COMPARE_NIL_IC ||
-         kind() == LOAD_IC ||
-         kind() == KEYED_LOAD_IC ||
-         kind() == STORE_IC ||
-         kind() == KEYED_STORE_IC ||
-         kind() == KEYED_CALL_IC ||
-         kind() == TO_BOOLEAN_IC);
+  ASSERT(has_major_key());
   ASSERT(0 <= major && major < 256);
   int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
   int updated = StubMajorKeyField::update(previous, major);
@@ -3908,6 +3892,21 @@
 }
 
 
+bool Code::has_major_key() {
+  return kind() == STUB ||
+      kind() == HANDLER ||
+      kind() == BINARY_OP_IC ||
+      kind() == COMPARE_IC ||
+      kind() == COMPARE_NIL_IC ||
+      kind() == LOAD_IC ||
+      kind() == KEYED_LOAD_IC ||
+      kind() == STORE_IC ||
+      kind() == KEYED_STORE_IC ||
+      kind() == KEYED_CALL_IC ||
+      kind() == TO_BOOLEAN_IC;
+}
+
+
 bool Code::is_pregenerated() {
   return (kind() == STUB && IsPregeneratedField::decode(flags()));
 }
@@ -4552,6 +4551,10 @@
 
 ACCESSORS(AllocationSite, transition_info, Object, kTransitionInfoOffset)
 ACCESSORS(AllocationSite, nested_site, Object, kNestedSiteOffset)
+ACCESSORS_TO_SMI(AllocationSite, memento_found_count, kMementoFoundCountOffset)
+ACCESSORS_TO_SMI(AllocationSite, memento_create_count,
+                 kMementoCreateCountOffset)
+ACCESSORS_TO_SMI(AllocationSite, pretenure_decision, kPretenureDecisionOffset)
 ACCESSORS(AllocationSite, dependent_code, DependentCode,
           kDependentCodeOffset)
 ACCESSORS(AllocationSite, weak_next, Object, kWeakNextOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 5260193..9f1b939 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -1125,6 +1125,12 @@
   dependent_code()->ShortPrint(out);
   PrintF(out, "\n - nested site: ");
   nested_site()->ShortPrint(out);
+  PrintF(out, "\n - memento found count: ");
+  memento_found_count()->ShortPrint(out);
+  PrintF(out, "\n - memento create count: ");
+  memento_create_count()->ShortPrint(out);
+  PrintF(out, "\n - pretenure decision: ");
+  pretenure_decision()->ShortPrint(out);
   PrintF(out, "\n - transition_info: ");
   if (transition_info()->IsSmi()) {
     ElementsKind kind = GetElementsKind();
diff --git a/src/objects.cc b/src/objects.cc
index c874ee3..2b38b1d 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -33,6 +33,7 @@
 #include "arguments.h"
 #include "bootstrapper.h"
 #include "codegen.h"
+#include "code-stubs.h"
 #include "cpu-profiler.h"
 #include "debug.h"
 #include "deoptimizer.h"
@@ -11135,6 +11136,10 @@
 
 void Code::Disassemble(const char* name, FILE* out) {
   PrintF(out, "kind = %s\n", Kind2String(kind()));
+  if (has_major_key()) {
+    PrintF(out, "major_key = %s\n",
+           CodeStub::MajorName(CodeStub::GetMajorKey(this), true));
+  }
   if (is_inline_cache_stub()) {
     PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
     PrintExtraICState(out, kind(), needs_extended_extra_ic_state(kind()) ?
diff --git a/src/objects.h b/src/objects.h
index 352edaa..cf4c80b 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5141,6 +5141,7 @@
   // [major_key]: For kind STUB or BINARY_OP_IC, the major key.
   inline int major_key();
   inline void set_major_key(int value);
+  inline bool has_major_key();
 
   // For kind STUB or ICs, tells whether or not a code object was generated by
   // the optimizing compiler (but it may not be an optimized function).
@@ -8110,6 +8111,9 @@
   // walked in a particular order. So [[1, 2], 1, 2] will have one
   // nested_site, but [[1, 2], 3, [4]] will have a list of two.
   DECL_ACCESSORS(nested_site, Object)
+  DECL_ACCESSORS(memento_found_count, Smi)
+  DECL_ACCESSORS(memento_create_count, Smi)
+  DECL_ACCESSORS(pretenure_decision, Smi)
   DECL_ACCESSORS(dependent_code, DependentCode)
   DECL_ACCESSORS(weak_next, Object)
 
@@ -8177,7 +8181,13 @@
 
   static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
   static const int kNestedSiteOffset = kTransitionInfoOffset + kPointerSize;
-  static const int kDependentCodeOffset = kNestedSiteOffset + kPointerSize;
+  static const int kMementoFoundCountOffset = kNestedSiteOffset + kPointerSize;
+  static const int kMementoCreateCountOffset =
+      kMementoFoundCountOffset + kPointerSize;
+  static const int kPretenureDecisionOffset =
+      kMementoCreateCountOffset + kPointerSize;
+  static const int kDependentCodeOffset =
+      kPretenureDecisionOffset + kPointerSize;
   static const int kWeakNextOffset = kDependentCodeOffset + kPointerSize;
   static const int kSize = kWeakNextOffset + kPointerSize;
 
diff --git a/src/runtime.cc b/src/runtime.cc
index f546629..c11a005 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7848,35 +7848,6 @@
 }
 
 
-RUNTIME_FUNCTION(MaybeObject*, Runtime_PopulateTrigonometricTable) {
-  HandleScope scope(isolate);
-  ASSERT(args.length() == 3);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sin_table, 0);
-  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, cos_table, 1);
-  CONVERT_SMI_ARG_CHECKED(samples, 2);
-  RUNTIME_ASSERT(sin_table->type() == kExternalDoubleArray);
-  RUNTIME_ASSERT(cos_table->type() == kExternalDoubleArray);
-  double* sin_buffer = reinterpret_cast<double*>(
-      JSArrayBuffer::cast(sin_table->buffer())->backing_store());
-  double* cos_buffer = reinterpret_cast<double*>(
-      JSArrayBuffer::cast(cos_table->buffer())->backing_store());
-
-  static const double pi_half = 3.1415926535897932 / 2;
-  double interval = pi_half / samples;
-  for (int i = 0; i < samples + 1; i++) {
-    double sample = sin(i * interval);
-    sin_buffer[i] = sample;
-    cos_buffer[samples - i] = sample * interval;
-  }
-
-  // Fill this to catch out of bound accesses when calculating Math.sin(pi/2).
-  sin_buffer[samples + 1] = sin(pi_half + interval);
-  cos_buffer[samples + 1] = cos(pi_half + interval) * interval;
-
-  return isolate->heap()->undefined_value();
-}
-
-
 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 2);
diff --git a/src/runtime.h b/src/runtime.h
index 4872ab5..0e09200 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -190,7 +190,6 @@
   F(Math_sin, 1, 1) \
   F(Math_sqrt, 1, 1) \
   F(Math_tan, 1, 1) \
-  F(PopulateTrigonometricTable, 3, 1) \
   \
   /* Regular expressions */ \
   F(RegExpCompile, 3, 1) \
diff --git a/src/trig-table.h b/src/trig-table.h
new file mode 100644
index 0000000..081c038
--- /dev/null
+++ b/src/trig-table.h
@@ -0,0 +1,61 @@
+// Copyright 2013 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
+// 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.
+
+#ifndef V8_TRIG_TABLE_H_
+#define V8_TRIG_TABLE_H_
+
+
+namespace v8 {
+namespace internal {
+
+class TrigonometricLookupTable : public AllStatic {
+ public:
+  // Casting away const-ness to use as argument for typed array constructor.
+  static void* sin_table() {
+    return const_cast<double*>(&kSinTable[0]);
+  }
+
+  static void* cos_x_interval_table() {
+    return const_cast<double*>(&kCosXIntervalTable[0]);
+  }
+
+  static double samples_over_pi_half() { return kSamplesOverPiHalf; }
+  static int samples() { return kSamples; }
+  static int table_num_bytes() { return kTableSize * sizeof(*kSinTable); }
+  static int table_size() { return kTableSize; }
+
+ private:
+  static const double kSinTable[];
+  static const double kCosXIntervalTable[];
+  static const int kSamples;
+  static const int kTableSize;
+  static const double kSamplesOverPiHalf;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_TRIG_TABLE_H_
diff --git a/src/v8.cc b/src/v8.cc
index 17007a2..c56c82a 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -32,6 +32,9 @@
 #include "elements.h"
 #include "bootstrapper.h"
 #include "debug.h"
+#ifdef V8_USE_DEFAULT_PLATFORM
+#include "default-platform.h"
+#endif
 #include "deoptimizer.h"
 #include "frames.h"
 #include "heap-profiler.h"
@@ -52,6 +55,7 @@
 
 List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL;
 v8::ArrayBuffer::Allocator* V8::array_buffer_allocator_ = NULL;
+v8::Platform* V8::platform_ = NULL;
 
 
 bool V8::Initialize(Deserializer* des) {
@@ -100,6 +104,12 @@
   call_completed_callbacks_ = NULL;
 
   Sampler::TearDown();
+
+#ifdef V8_USE_DEFAULT_PLATFORM
+  DefaultPlatform* platform = static_cast<DefaultPlatform*>(platform_);
+  platform_ = NULL;
+  delete platform;
+#endif
 }
 
 
@@ -179,6 +189,9 @@
     FLAG_max_new_space_size = (1 << (kPageSizeBits - 10)) * 2;
   }
 
+#ifdef V8_USE_DEFAULT_PLATFORM
+  platform_ = new DefaultPlatform;
+#endif
   Sampler::SetUp();
   CPU::SetUp();
   OS::PostSetUp();
@@ -194,4 +207,23 @@
   CallOnce(&init_once, &InitializeOncePerProcessImpl);
 }
 
+
+void V8::InitializePlatform(v8::Platform* platform) {
+  ASSERT(!platform_);
+  ASSERT(platform);
+  platform_ = platform;
+}
+
+
+void V8::ShutdownPlatform() {
+  ASSERT(platform_);
+  platform_ = NULL;
+}
+
+
+v8::Platform* V8::GetCurrentPlatform() {
+  ASSERT(platform_);
+  return platform_;
+}
+
 } }  // namespace v8::internal
diff --git a/src/v8.h b/src/v8.h
index 01362ab..6f2633a 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -50,6 +50,7 @@
 
 // Basic includes
 #include "../include/v8.h"
+#include "../include/v8-platform.h"
 #include "v8globals.h"
 #include "v8checks.h"
 #include "allocation.h"
@@ -111,6 +112,10 @@
     array_buffer_allocator_ = allocator;
   }
 
+  static void InitializePlatform(v8::Platform* platform);
+  static void ShutdownPlatform();
+  static v8::Platform* GetCurrentPlatform();
+
  private:
   static void InitializeOncePerProcessImpl();
   static void InitializeOncePerProcess();
@@ -119,6 +124,8 @@
   static List<CallCompletedCallback>* call_completed_callbacks_;
   // Allocator for external array buffers.
   static v8::ArrayBuffer::Allocator* array_buffer_allocator_;
+  // v8::Platform to use.
+  static v8::Platform* platform_;
 };
 
 
diff --git a/src/v8threads.cc b/src/v8threads.cc
index cc4f439..1de9d4f 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -133,18 +133,6 @@
 }
 
 
-void Locker::StartPreemption(v8::Isolate* isolate, int every_n_ms) {
-  v8::internal::ContextSwitcher::StartPreemption(
-      reinterpret_cast<i::Isolate*>(isolate), every_n_ms);
-}
-
-
-void Locker::StopPreemption(v8::Isolate* isolate) {
-  v8::internal::ContextSwitcher::StopPreemption(
-      reinterpret_cast<i::Isolate*>(isolate));
-}
-
-
 namespace internal {
 
 
@@ -419,63 +407,5 @@
 }
 
 
-ContextSwitcher::ContextSwitcher(Isolate* isolate, int every_n_ms)
-  : Thread("v8:CtxtSwitcher"),
-    keep_going_(true),
-    sleep_ms_(every_n_ms),
-    isolate_(isolate) {
-}
-
-
-// Set the scheduling interval of V8 threads. This function starts the
-// ContextSwitcher thread if needed.
-void ContextSwitcher::StartPreemption(Isolate* isolate, int every_n_ms) {
-  ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
-  if (isolate->context_switcher() == NULL) {
-    // If the ContextSwitcher thread is not running at the moment start it now.
-    isolate->set_context_switcher(new ContextSwitcher(isolate, every_n_ms));
-    isolate->context_switcher()->Start();
-  } else {
-    // ContextSwitcher thread is already running, so we just change the
-    // scheduling interval.
-    isolate->context_switcher()->sleep_ms_ = every_n_ms;
-  }
-}
-
-
-// Disable preemption of V8 threads. If multiple threads want to use V8 they
-// must cooperatively schedule amongst them from this point on.
-void ContextSwitcher::StopPreemption(Isolate* isolate) {
-  ASSERT(Locker::IsLocked(reinterpret_cast<v8::Isolate*>(isolate)));
-  if (isolate->context_switcher() != NULL) {
-    // The ContextSwitcher thread is running. We need to stop it and release
-    // its resources.
-    isolate->context_switcher()->keep_going_ = false;
-    // Wait for the ContextSwitcher thread to exit.
-    isolate->context_switcher()->Join();
-    // Thread has exited, now we can delete it.
-    delete(isolate->context_switcher());
-    isolate->set_context_switcher(NULL);
-  }
-}
-
-
-// Main loop of the ContextSwitcher thread: Preempt the currently running V8
-// thread at regular intervals.
-void ContextSwitcher::Run() {
-  while (keep_going_) {
-    OS::Sleep(sleep_ms_);
-    isolate()->stack_guard()->Preempt();
-  }
-}
-
-
-// Acknowledge the preemption by the receiving thread.
-void ContextSwitcher::PreemptionReceived() {
-  // There is currently no accounting being done for this. But could be in the
-  // future, which is why we leave this in.
-}
-
-
 }  // namespace internal
 }  // namespace v8
diff --git a/src/v8threads.h b/src/v8threads.h
index 1edacfc..a20700a 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -139,34 +139,6 @@
 };
 
 
-// The ContextSwitcher thread is used to schedule regular preemptions to
-// multiple running V8 threads. Generally it is necessary to call
-// StartPreemption if there is more than one thread running. If not, a single
-// JavaScript can take full control of V8 and not allow other threads to run.
-class ContextSwitcher: public Thread {
- public:
-  // Set the preemption interval for the ContextSwitcher thread.
-  static void StartPreemption(Isolate* isolate, int every_n_ms);
-
-  // Stop sending preemption requests to threads.
-  static void StopPreemption(Isolate* isolate);
-
-  // Preempted thread needs to call back to the ContextSwitcher to acknowledge
-  // the handling of a preemption request.
-  static void PreemptionReceived();
-
- private:
-  ContextSwitcher(Isolate* isolate, int every_n_ms);
-
-  Isolate* isolate() const { return isolate_; }
-
-  void Run();
-
-  bool keep_going_;
-  int sleep_ms_;
-  Isolate* isolate_;
-};
-
 } }  // namespace v8::internal
 
 #endif  // V8_V8THREADS_H_
diff --git a/src/version.cc b/src/version.cc
index 8ee0430..c76c1b2 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     23
-#define BUILD_NUMBER      9
+#define BUILD_NUMBER      10
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 2df0a89..761b402 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -14478,116 +14478,6 @@
 }
 
 
-class ApplyInterruptTest {
- public:
-  ApplyInterruptTest() : block_(0) {}
-  ~ApplyInterruptTest() {}
-  void RunTest() {
-    gc_count_ = 0;
-    gc_during_apply_ = 0;
-    apply_success_ = false;
-    gc_success_ = false;
-    GCThread gc_thread(this);
-    gc_thread.Start();
-    v8::Isolate* isolate = CcTest::isolate();
-    v8::Locker::StartPreemption(isolate, 1);
-
-    LongRunningApply();
-    {
-      v8::Unlocker unlock(isolate);
-      gc_thread.Join();
-    }
-    v8::Locker::StopPreemption(isolate);
-    CHECK(apply_success_);
-    CHECK(gc_success_);
-  }
-
- private:
-  // Number of garbage collections required.
-  static const int kRequiredGCs = 2;
-
-  class GCThread : public i::Thread {
-   public:
-    explicit GCThread(ApplyInterruptTest* test)
-        : Thread("GCThread"), test_(test) {}
-    virtual void Run() {
-      test_->CollectGarbage();
-    }
-   private:
-     ApplyInterruptTest* test_;
-  };
-
-  void CollectGarbage() {
-    block_.Wait();
-    while (gc_during_apply_ < kRequiredGCs) {
-      {
-        v8::Locker lock(CcTest::isolate());
-        v8::Isolate::Scope isolate_scope(CcTest::isolate());
-        CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
-        gc_count_++;
-      }
-      i::OS::Sleep(1);
-    }
-    gc_success_ = true;
-  }
-
-  void LongRunningApply() {
-    block_.Signal();
-    int rounds = 0;
-    while (gc_during_apply_ < kRequiredGCs) {
-      int gc_before = gc_count_;
-      {
-        const char* c_source =
-            "function do_very_little(bar) {"
-            "  this.foo = bar;"
-            "}"
-            "for (var i = 0; i < 100000; i++) {"
-            "  do_very_little.apply(this, ['bar']);"
-            "}";
-        Local<String> source = String::New(c_source);
-        Local<Script> script = Script::Compile(source);
-        Local<Value> result = script->Run();
-        // Check that no exception was thrown.
-        CHECK(!result.IsEmpty());
-      }
-      int gc_after = gc_count_;
-      gc_during_apply_ += gc_after - gc_before;
-      rounds++;
-    }
-    apply_success_ = true;
-  }
-
-  i::Semaphore block_;
-  int gc_count_;
-  int gc_during_apply_;
-  bool apply_success_;
-  bool gc_success_;
-};
-
-
-// Test that nothing bad happens if we get a preemption just when we were
-// about to do an apply().
-TEST(ApplyInterruption) {
-  v8::Locker lock(CcTest::isolate());
-  v8::V8::Initialize();
-  v8::HandleScope scope(CcTest::isolate());
-  Local<Context> local_env;
-  {
-    LocalContext env;
-    local_env = env.local();
-  }
-
-  // Local context should still be live.
-  CHECK(!local_env.IsEmpty());
-  local_env->Enter();
-
-  // Should complete without problems.
-  ApplyInterruptTest().RunTest();
-
-  local_env->Exit();
-}
-
-
 // Verify that we can clone an object
 TEST(ObjectClone) {
   LocalContext env;
diff --git a/test/cctest/test-threads.cc b/test/cctest/test-threads.cc
index 4709961..c43c420 100644
--- a/test/cctest/test-threads.cc
+++ b/test/cctest/test-threads.cc
@@ -33,28 +33,6 @@
 #include "cctest.h"
 
 
-TEST(Preemption) {
-  v8::Isolate* isolate = CcTest::isolate();
-  v8::Locker locker(isolate);
-  v8::V8::Initialize();
-  v8::HandleScope scope(isolate);
-  v8::Handle<v8::Context> context = v8::Context::New(isolate);
-  v8::Context::Scope context_scope(context);
-
-  v8::Locker::StartPreemption(isolate, 100);
-
-  v8::Handle<v8::Script> script = v8::Script::Compile(
-      v8::String::New("var count = 0; var obj = new Object(); count++;\n"));
-
-  script->Run();
-
-  v8::Locker::StopPreemption(isolate);
-  v8::internal::OS::Sleep(500);  // Make sure the timer fires.
-
-  script->Run();
-}
-
-
 enum Turn {
   FILL_CACHE,
   CLEAN_CACHE,
diff --git a/test/cctest/test-weaktypedarrays.cc b/test/cctest/test-weaktypedarrays.cc
index fe1ef04..dc7dc75 100644
--- a/test/cctest/test-weaktypedarrays.cc
+++ b/test/cctest/test-weaktypedarrays.cc
@@ -89,7 +89,7 @@
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
 
-  CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+  int start = CountArrayBuffersInWeakList(isolate->heap());
   {
     v8::HandleScope s1(context->GetIsolate());
     v8::Handle<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(256);
@@ -99,12 +99,12 @@
 
       Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
       Handle<JSArrayBuffer> iab2 = v8::Utils::OpenHandle(*ab2);
-      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
       CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1));
       CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2));
     }
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
     {
       HandleScope scope2(isolate);
       Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
@@ -114,7 +114,7 @@
   }
 
   isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-  CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+  CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap()));
 }
 
 
@@ -122,11 +122,12 @@
   v8::V8::Initialize();
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
+  int start = CountArrayBuffersInWeakList(isolate->heap());
 
   for (int i = 1; i <= 3; i++) {
     // Create 3 array buffers, make i-th of them garbage,
     // validate correct state of array buffer weak list.
-    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap()));
     {
       v8::HandleScope scope(context->GetIsolate());
 
@@ -142,7 +143,7 @@
         v8::Handle<v8::ArrayBuffer> ab3 =
             v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab3"));
 
-        CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()));
+        CHECK_EQ(3, CountArrayBuffersInWeakList(isolate->heap()) - start);
         CHECK(HasArrayBufferInWeakList(isolate->heap(),
               *v8::Utils::OpenHandle(*ab1)));
         CHECK(HasArrayBufferInWeakList(isolate->heap(),
@@ -156,7 +157,7 @@
       CompileRun(source.start());
       isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
       {
         v8::HandleScope s2(context->GetIsolate());
@@ -174,7 +175,7 @@
     }
 
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
-    CHECK_EQ(0, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap()));
   }
 }
 
@@ -266,6 +267,7 @@
   LocalContext context;
   Isolate* isolate = GetIsolateFrom(&context);
   v8::HandleScope scope(context->GetIsolate());
+  int start = CountArrayBuffersInWeakList(isolate->heap());
   CompileRun("var ab = new ArrayBuffer(2048);");
   for (int i = 1; i <= 3; i++) {
     // Create 3 typed arrays, make i-th of them garbage,
@@ -273,7 +275,7 @@
     v8::HandleScope s0(context->GetIsolate());
     i::ScopedVector<char> source(2048);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s1(context->GetIsolate());
@@ -292,7 +294,7 @@
           v8::Handle<TypedArray>::Cast(CompileRun("ta2"));
       v8::Handle<TypedArray> ta3 =
           v8::Handle<TypedArray>::Cast(CompileRun("ta3"));
-      CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+      CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
       Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
       CHECK_EQ(3, CountViews(*iab));
       CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1)));
@@ -304,7 +306,7 @@
     CompileRun(source.start());
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s2(context->GetIsolate());
@@ -324,7 +326,7 @@
     CompileRun("ta1 = null; ta2 = null; ta3 = null;");
     isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
 
-    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()));
+    CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
 
     {
       v8::HandleScope s3(context->GetIsolate());
diff --git a/tools/generate-trig-table.py b/tools/generate-trig-table.py
new file mode 100644
index 0000000..14d4472
--- /dev/null
+++ b/tools/generate-trig-table.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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
+# 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.
+
+# This is a utility for populating the lookup table for the
+# approximation of trigonometric functions.
+
+import sys, math
+
+SAMPLES = 1800
+
+TEMPLATE = """\
+// Copyright 2013 Google Inc. All Rights Reserved.
+
+// This file was generated from a python script.
+
+#include "v8.h"
+#include "trig-table.h"
+
+namespace v8 {
+namespace internal {
+
+  const double TrigonometricLookupTable::kSinTable[] =
+      { %(sine_table)s };
+  const double TrigonometricLookupTable::kCosXIntervalTable[] =
+      { %(cosine_table)s };
+  const int TrigonometricLookupTable::kSamples = %(samples)i;
+  const int TrigonometricLookupTable::kTableSize = %(table_size)i;
+  const double TrigonometricLookupTable::kSamplesOverPiHalf =
+      %(samples_over_pi_half)s;
+
+} }  // v8::internal
+"""
+
+def main():
+  pi_half = math.pi / 2
+  interval = pi_half / SAMPLES
+  sin = []
+  cos_times_interval = []
+  table_size = SAMPLES + 2
+
+  for i in range(0, table_size):
+    sample = i * interval
+    sin.append(repr(math.sin(sample)))
+    cos_times_interval.append(repr(math.cos(sample) * interval))
+
+  output_file = sys.argv[1]
+  output = open(str(output_file), "w")
+  output.write(TEMPLATE % {
+    'sine_table': ','.join(sin),
+    'cosine_table': ','.join(cos_times_interval),
+    'samples': SAMPLES,
+    'table_size': table_size,
+    'samples_over_pi_half': repr(SAMPLES / pi_half)
+  })
+
+if __name__ == "__main__":
+  main()
+
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index d5c33c6..65d5fb8 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -140,6 +140,7 @@
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+        '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
         '<(INTERMEDIATE_DIR)/snapshot.cc',
       ],
       'actions': [
@@ -182,6 +183,7 @@
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
         '<(SHARED_INTERMEDIATE_DIR)/experimental-libraries.cc',
+        '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
         '../../src/snapshot-empty.cc',
       ],
       'conditions': [
@@ -200,9 +202,38 @@
         }],
       ]
     },
+    { 'target_name': 'generate_trig_table',
+      'type': 'none',
+      'conditions': [
+        ['want_separate_host_toolset==1', {
+          'toolsets': ['host', 'target'],
+        }, {
+          'toolsets': ['target'],
+        }],
+      ],
+      'actions': [
+        {
+          'action_name': 'generate',
+          'inputs': [
+            '../../tools/generate-trig-table.py',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/trig-table.cc',
+          ],
+          'action': [
+            'python',
+            '../../tools/generate-trig-table.py',
+            '<@(_outputs)',
+          ],
+        },
+      ]
+    },
     {
       'target_name': 'v8_base.<(v8_target_arch)',
       'type': 'static_library',
+      'dependencies': [
+        'generate_trig_table',
+      ],
       'variables': {
         'optimize': 'max',
       },
@@ -280,6 +311,8 @@
         '../../src/debug-agent.h',
         '../../src/debug.cc',
         '../../src/debug.h',
+        '../../src/default-platform.cc',
+        '../../src/default-platform.h',
         '../../src/deoptimizer.cc',
         '../../src/deoptimizer.h',
         '../../src/disasm.h',
@@ -886,6 +919,12 @@
             '<(icu_gyp_path):icudata',
           ],
         }],
+        ['v8_use_default_platform==0', {
+          'sources!': [
+            '../../src/default-platform.cc',
+            '../../src/default-platform.h',
+          ],
+        }],
       ],
     },
     {
diff --git a/tools/push-to-trunk/auto_roll.py b/tools/push-to-trunk/auto_roll.py
index 9547301..cb990cd 100755
--- a/tools/push-to-trunk/auto_roll.py
+++ b/tools/push-to-trunk/auto_roll.py
@@ -29,7 +29,6 @@
 import optparse
 import re
 import sys
-import urllib2
 
 from common_includes import *
 
@@ -40,8 +39,7 @@
 
 
 class Preparation(Step):
-  def __init__(self):
-    Step.__init__(self, "Preparation.")
+  MESSAGE = "Preparation."
 
   def RunStep(self):
     self.InitialEnvironmentChecks()
@@ -49,8 +47,7 @@
 
 
 class FetchLatestRevision(Step):
-  def __init__(self):
-    Step.__init__(self, "Fetching latest V8 revision.")
+  MESSAGE = "Fetching latest V8 revision."
 
   def RunStep(self):
     log = self.Git("svn log -1 --oneline").strip()
@@ -61,25 +58,15 @@
 
 
 class FetchLKGR(Step):
-  def __init__(self):
-    Step.__init__(self, "Fetching V8 LKGR.")
+  MESSAGE = "Fetching V8 LKGR."
 
   def RunStep(self):
     lkgr_url = "https://v8-status.appspot.com/lkgr"
-    try:
-      # pylint: disable=E1121
-      url_fh = urllib2.urlopen(lkgr_url, None, 60)
-    except urllib2.URLError:
-      self.Die("URLException while fetching %s" % lkgr_url)
-    try:
-      self.Persist("lkgr", url_fh.read())
-    finally:
-      url_fh.close()
+    self.Persist("lkgr", self.ReadURL(lkgr_url))
 
 
 class PushToTrunk(Step):
-  def __init__(self):
-    Step.__init__(self, "Pushing to trunk if possible.")
+  MESSAGE = "Pushing to trunk if possible."
 
   def RunStep(self):
     self.RestoreIfUnset("latest")
@@ -94,6 +81,18 @@
             % (latest, lkgr))
 
 
+def RunAutoRoll(config,
+                options,
+                side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
+  step_classes = [
+    Preparation,
+    FetchLatestRevision,
+    FetchLKGR,
+    PushToTrunk,
+  ]
+  RunScript(step_classes, config, options, side_effect_handler)
+
+
 def BuildOptions():
   result = optparse.OptionParser()
   result.add_option("-s", "--step", dest="s",
@@ -105,15 +104,7 @@
 def Main():
   parser = BuildOptions()
   (options, args) = parser.parse_args()
-
-  step_classes = [
-    Preparation,
-    FetchLatestRevision,
-    FetchLKGR,
-    PushToTrunk,
-  ]
-
-  RunScript(step_classes, CONFIG, options, DEFAULT_SIDE_EFFECT_HANDLER)
+  RunAutoRoll(CONFIG, options)
 
 if __name__ == "__main__":
   sys.exit(Main())
diff --git a/tools/push-to-trunk/common_includes.py b/tools/push-to-trunk/common_includes.py
index b6f9761..eaa3d20 100644
--- a/tools/push-to-trunk/common_includes.py
+++ b/tools/push-to-trunk/common_includes.py
@@ -31,6 +31,7 @@
 import subprocess
 import sys
 import textwrap
+import urllib2
 
 PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME"
 TEMP_BRANCH = "TEMP_BRANCH"
@@ -69,6 +70,10 @@
 
 
 def Fill80(line):
+  # Replace tabs and remove surrounding space.
+  line = re.sub(r"\t", r"        ", line.strip())
+
+  # Format with 8 characters indentation and line width 80.
   return textwrap.fill(line, width=80, initial_indent="        ",
                        subsequent_indent="        ")
 
@@ -96,7 +101,7 @@
   for (title, body, author) in commit_messages:
     # TODO(machenbach): Reload the commit description from rietveld in order to
     # catch late changes.
-    title = title.rstrip()
+    title = title.strip()
     if auto_format:
       # Only add commits that set the LOG flag correctly.
       log_exp = r"^[ \t]*LOG[ \t]*=[ \t]*(?:Y(?:ES)?)|TRUE"
@@ -114,7 +119,7 @@
     # indentation afterwards.
 
     # Add the commit's title line.
-    result += "%s\n" % title
+    result += "%s\n" % Fill80(title)
     added_titles.add(title)
 
     # Add bug references.
@@ -122,7 +127,7 @@
 
     # Append the commit's author for reference if not in auto-format mode.
     if not auto_format:
-      result += "%s\n" % author.rstrip()
+      result += "%s\n" % Fill80("(%s)" % author.strip())
 
     result += "\n"
   return result
@@ -192,40 +197,35 @@
   def ReadLine(self):
     return sys.stdin.readline().strip()
 
+  def ReadURL(self, url):
+    # pylint: disable=E1121
+    url_fh = urllib2.urlopen(url, None, 60)
+    try:
+      return url_fh.read()
+    finally:
+      url_fh.close()
+
 DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler()
 
 
 class Step(object):
-  def __init__(self, text="", requires=None):
+  def __init__(self, text, requires, number, config, state, options, handler):
     self._text = text
-    self._number = -1
-    self._options = None
     self._requires = requires
-    self._side_effect_handler = DEFAULT_SIDE_EFFECT_HANDLER
-
-  def SetNumber(self, number):
     self._number = number
-
-  def SetConfig(self, config):
     self._config = config
-
-  def SetState(self, state):
     self._state = state
-
-  def SetOptions(self, options):
     self._options = options
-
-  def SetSideEffectHandler(self, handler):
     self._side_effect_handler = handler
+    assert self._number >= 0
+    assert self._config is not None
+    assert self._state is not None
+    assert self._side_effect_handler is not None
 
   def Config(self, key):
     return self._config[key]
 
   def Run(self):
-    assert self._number >= 0
-    assert self._config is not None
-    assert self._state is not None
-    assert self._side_effect_handler is not None
     if self._requires:
       self.RestoreIfUnset(self._requires)
       if not self._state[self._requires]:
@@ -251,6 +251,9 @@
     return self._side_effect_handler.Command(os.environ["EDITOR"], args,
                                              pipe=False)
 
+  def ReadURL(self, url):
+    return self._side_effect_handler.ReadURL(url)
+
   def Die(self, msg=""):
     if msg != "":
       print "Error: %s" % msg
@@ -399,8 +402,7 @@
 
 
 class UploadStep(Step):
-  def __init__(self):
-    Step.__init__(self, "Upload for code review.")
+  MESSAGE = "Upload for code review."
 
   def RunStep(self):
     if self._options.r:
@@ -418,24 +420,35 @@
       self.Die("'git cl upload' failed, please try again.")
 
 
+def MakeStep(step_class=Step, number=0, state=None, config=None,
+             options=None, side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
+    # Allow to pass in empty dictionaries.
+    state = state if state is not None else {}
+    config = config if config is not None else {}
+
+    try:
+      message = step_class.MESSAGE
+    except AttributeError:
+      message = step_class.__name__
+    try:
+      requires = step_class.REQUIRES
+    except AttributeError:
+      requires = None
+
+    return step_class(message, requires, number=number, config=config,
+                      state=state, options=options,
+                      handler=side_effect_handler)
+
+
 def RunScript(step_classes,
               config,
               options,
               side_effect_handler=DEFAULT_SIDE_EFFECT_HANDLER):
   state = {}
   steps = []
-  number = 0
-
-  for step_class in step_classes:
-    # TODO(machenbach): Factory methods.
-    step = step_class()
-    step.SetNumber(number)
-    step.SetConfig(config)
-    step.SetOptions(options)
-    step.SetState(state)
-    step.SetSideEffectHandler(side_effect_handler)
-    steps.append(step)
-    number += 1
+  for (number, step_class) in enumerate(step_classes):
+    steps.append(MakeStep(step_class, number, state, config,
+                          options, side_effect_handler))
 
   for step in steps[options.s:]:
     step.Run()
diff --git a/tools/push-to-trunk/push_to_trunk.py b/tools/push-to-trunk/push_to_trunk.py
index 7278323..24dfb67 100755
--- a/tools/push-to-trunk/push_to_trunk.py
+++ b/tools/push-to-trunk/push_to_trunk.py
@@ -53,8 +53,7 @@
 
 
 class Preparation(Step):
-  def __init__(self):
-    Step.__init__(self, "Preparation.")
+  MESSAGE = "Preparation."
 
   def RunStep(self):
     self.InitialEnvironmentChecks()
@@ -64,8 +63,7 @@
 
 
 class FreshBranch(Step):
-  def __init__(self):
-    Step.__init__(self, "Create a fresh branch.")
+  MESSAGE = "Create a fresh branch."
 
   def RunStep(self):
     args = "checkout -b %s svn/bleeding_edge" % self.Config(BRANCHNAME)
@@ -74,8 +72,7 @@
 
 
 class DetectLastPush(Step):
-  def __init__(self):
-    Step.__init__(self, "Detect commit ID of last push to trunk.")
+  MESSAGE = "Detect commit ID of last push to trunk."
 
   def RunStep(self):
     last_push = (self._options.l or
@@ -92,8 +89,7 @@
 
 
 class PrepareChangeLog(Step):
-  def __init__(self):
-    Step.__init__(self, "Prepare raw ChangeLog entry.")
+  MESSAGE = "Prepare raw ChangeLog entry."
 
   def RunStep(self):
     self.RestoreIfUnset("last_push")
@@ -115,9 +111,9 @@
     # Cache raw commit messages.
     commit_messages = [
       [
-        self.Git("log -1 %s --format=\"%%w(80,8,8)%%s\"" % commit),
+        self.Git("log -1 %s --format=\"%%s\"" % commit),
         self.Git("log -1 %s --format=\"%%B\"" % commit),
-        self.Git("log -1 %s --format=\"%%w(80,8,8)(%%an)\"" % commit),
+        self.Git("log -1 %s --format=\"%%an\"" % commit),
       ] for commit in commits.splitlines()
     ]
 
@@ -137,8 +133,7 @@
 
 
 class EditChangeLog(Step):
-  def __init__(self):
-    Step.__init__(self, "Edit ChangeLog entry.")
+  MESSAGE = "Edit ChangeLog entry."
 
   def RunStep(self):
     print ("Please press <Return> to have your EDITOR open the ChangeLog "
@@ -152,14 +147,10 @@
     handle, new_changelog = tempfile.mkstemp()
     os.close(handle)
 
-    # (1) Strip comments, (2) eliminate tabs, (3) fix too little and (4) too
-    # much indentation, and (5) eliminate trailing whitespace.
+    # Strip comments and reformat with correct indentation.
     changelog_entry = FileToText(self.Config(CHANGELOG_ENTRY_FILE)).rstrip()
     changelog_entry = StripComments(changelog_entry)
-    changelog_entry = MSub(r"\t", r"        ", changelog_entry)
-    changelog_entry = MSub(r"^ {1,7}([^ ])", r"        \1", changelog_entry)
-    changelog_entry = MSub(r"^ {9,80}([^ ])", r"        \1", changelog_entry)
-    changelog_entry = MSub(r" +$", r"", changelog_entry)
+    changelog_entry = "\n".join(map(Fill80, changelog_entry.splitlines()))
 
     if changelog_entry == "":
       self.Die("Empty ChangeLog entry.")
@@ -174,8 +165,7 @@
 
 
 class IncrementVersion(Step):
-  def __init__(self):
-    Step.__init__(self, "Increment version number.")
+  MESSAGE = "Increment version number."
 
   def RunStep(self):
     self.RestoreIfUnset("build")
@@ -197,8 +187,7 @@
 
 
 class CommitLocal(Step):
-  def __init__(self):
-    Step.__init__(self, "Commit to local branch.")
+  MESSAGE = "Commit to local branch."
 
   def RunStep(self):
     self.RestoreVersionIfUnset("new_")
@@ -212,8 +201,7 @@
 
 
 class CommitRepository(Step):
-  def __init__(self):
-    Step.__init__(self, "Commit to the repository.")
+  MESSAGE = "Commit to the repository."
 
   def RunStep(self):
     self.WaitForLGTM()
@@ -227,9 +215,8 @@
 
 
 class StragglerCommits(Step):
-  def __init__(self):
-    Step.__init__(self, "Fetch straggler commits that sneaked in since this "
-                        "script was started.")
+  MESSAGE = ("Fetch straggler commits that sneaked in since this script was "
+             "started.")
 
   def RunStep(self):
     if self.Git("svn fetch") is None:
@@ -242,8 +229,7 @@
 
 
 class SquashCommits(Step):
-  def __init__(self):
-    Step.__init__(self, "Squash commits into one.")
+  MESSAGE = "Squash commits into one."
 
   def RunStep(self):
     # Instead of relying on "git rebase -i", we'll just create a diff, because
@@ -285,8 +271,7 @@
 
 
 class NewBranch(Step):
-  def __init__(self):
-    Step.__init__(self, "Create a new branch from trunk.")
+  MESSAGE = "Create a new branch from trunk."
 
   def RunStep(self):
     if self.Git("checkout -b %s svn/trunk" % self.Config(TRUNKBRANCH)) is None:
@@ -295,8 +280,7 @@
 
 
 class ApplyChanges(Step):
-  def __init__(self):
-    Step.__init__(self, "Apply squashed changes.")
+  MESSAGE = "Apply squashed changes."
 
   def RunStep(self):
     self.ApplyPatch(self.Config(PATCH_FILE))
@@ -304,8 +288,7 @@
 
 
 class SetVersion(Step):
-  def __init__(self):
-    Step.__init__(self, "Set correct version for trunk.")
+  MESSAGE = "Set correct version for trunk."
 
   def RunStep(self):
     self.RestoreVersionIfUnset()
@@ -326,8 +309,7 @@
 
 
 class CommitTrunk(Step):
-  def __init__(self):
-    Step.__init__(self, "Commit to local trunk branch.")
+  MESSAGE = "Commit to local trunk branch."
 
   def RunStep(self):
     self.Git("add \"%s\"" % self.Config(VERSION_FILE))
@@ -337,8 +319,7 @@
 
 
 class SanityCheck(Step):
-  def __init__(self):
-    Step.__init__(self, "Sanity check.")
+  MESSAGE = "Sanity check."
 
   def RunStep(self):
     if not self.Confirm("Please check if your local checkout is sane: Inspect "
@@ -348,8 +329,7 @@
 
 
 class CommitSVN(Step):
-  def __init__(self):
-    Step.__init__(self, "Commit to SVN.")
+  MESSAGE = "Commit to SVN."
 
   def RunStep(self):
     result = self.Git("svn dcommit 2>&1")
@@ -374,8 +354,7 @@
 
 
 class TagRevision(Step):
-  def __init__(self):
-    Step.__init__(self, "Tag the new revision.")
+  MESSAGE = "Tag the new revision."
 
   def RunStep(self):
     self.RestoreVersionIfUnset()
@@ -387,8 +366,7 @@
 
 
 class CheckChromium(Step):
-  def __init__(self):
-    Step.__init__(self, "Ask for chromium checkout.")
+  MESSAGE = "Ask for chromium checkout."
 
   def Run(self):
     chrome_path = self._options.c
@@ -404,8 +382,8 @@
 
 
 class SwitchChromium(Step):
-  def __init__(self):
-    Step.__init__(self, "Switch to Chromium checkout.", requires="chrome_path")
+  MESSAGE = "Switch to Chromium checkout."
+  REQUIRES = "chrome_path"
 
   def RunStep(self):
     v8_path = os.getcwd()
@@ -421,9 +399,8 @@
 
 
 class UpdateChromiumCheckout(Step):
-  def __init__(self):
-    Step.__init__(self, "Update the checkout and create a new branch.",
-                  requires="chrome_path")
+  MESSAGE = "Update the checkout and create a new branch."
+  REQUIRES = "chrome_path"
 
   def RunStep(self):
     os.chdir(self._state["chrome_path"])
@@ -439,8 +416,8 @@
 
 
 class UploadCL(Step):
-  def __init__(self):
-    Step.__init__(self, "Create and upload CL.", requires="chrome_path")
+  MESSAGE = "Create and upload CL."
+  REQUIRES = "chrome_path"
 
   def RunStep(self):
     os.chdir(self._state["chrome_path"])
@@ -474,8 +451,8 @@
 
 
 class SwitchV8(Step):
-  def __init__(self):
-    Step.__init__(self, "Returning to V8 checkout.", requires="chrome_path")
+  MESSAGE = "Returning to V8 checkout."
+  REQUIRES = "chrome_path"
 
   def RunStep(self):
     self.RestoreIfUnset("v8_path")
@@ -483,8 +460,7 @@
 
 
 class CleanUp(Step):
-  def __init__(self):
-    Step.__init__(self, "Done!")
+  MESSAGE = "Done!"
 
   def RunStep(self):
     self.RestoreVersionIfUnset()
diff --git a/tools/push-to-trunk/test_scripts.py b/tools/push-to-trunk/test_scripts.py
index 42b26cf..5e2340e 100644
--- a/tools/push-to-trunk/test_scripts.py
+++ b/tools/push-to-trunk/test_scripts.py
@@ -34,6 +34,7 @@
 from common_includes import *
 import push_to_trunk
 from push_to_trunk import *
+import auto_roll
 
 
 TEST_CONFIG = {
@@ -67,18 +68,18 @@
 
   def testMakeChangeLogBodySimple(self):
     commits = [
-          ["        Title text 1",
+          ["Title text 1",
            "Title text 1\n\nBUG=\n",
-           "        author1@chromium.org"],
-          ["        Title text 2",
+           "author1@chromium.org"],
+          ["Title text 2",
            "Title text 2\n\nBUG=1234\n",
-           "        author2@chromium.org"],
+           "author2@chromium.org"],
         ]
     self.assertEquals("        Title text 1\n"
-                      "        author1@chromium.org\n\n"
+                      "        (author1@chromium.org)\n\n"
                       "        Title text 2\n"
                       "        (Chromium issue 1234)\n"
-                      "        author2@chromium.org\n\n",
+                      "        (author2@chromium.org)\n\n",
                       MakeChangeLogBody(commits))
 
   def testMakeChangeLogBodyEmpty(self):
@@ -86,18 +87,18 @@
 
   def testMakeChangeLogBodyAutoFormat(self):
     commits = [
-          ["        Title text 1",
+          ["Title text 1",
            "Title text 1\nLOG=y\nBUG=\n",
-           "        author1@chromium.org"],
-          ["        Title text 2",
+           "author1@chromium.org"],
+          ["Title text 2",
            "Title text 2\n\nBUG=1234\n",
-           "        author2@chromium.org"],
-          ["        Title text 3",
+           "author2@chromium.org"],
+          ["Title text 3",
            "Title text 3\n\nBUG=1234\nLOG = Yes\n",
-           "        author3@chromium.org"],
-          ["        Title text 3",
+           "author3@chromium.org"],
+          ["Title text 3",
            "Title text 4\n\nBUG=1234\nLOG=\n",
-           "        author4@chromium.org"],
+           "author4@chromium.org"],
         ]
     self.assertEquals("        Title text 1\n\n"
                       "        Title text 3\n"
@@ -178,6 +179,51 @@
                                                 "BUG=1234567890123456789\n"
                                                 "BUG=1234567890\n"))
 
+
+class SimpleMock(object):
+  def __init__(self, name):
+    self._name = name
+    self._recipe = []
+    self._index = -1
+
+  def Expect(self, recipe):
+    self._recipe = recipe
+
+  def Call(self, *args):
+    self._index += 1
+    try:
+      expected_call = self._recipe[self._index]
+    except IndexError:
+      raise Exception("Calling %s %s" % (name, " ".join(args)))
+
+    # Pack expectations without arguments into a list.
+    if not isinstance(expected_call, list):
+      expected_call = [expected_call]
+
+    # The number of arguments in the expectation must match the actual
+    # arguments.
+    if len(args) > len(expected_call):
+      raise Exception("When calling %s with arguments, the expectations "
+                      "must consist of at least as many arguments.")
+
+    # Compare expected and actual arguments.
+    for (expected_arg, actual_arg) in zip(expected_call, args):
+      if expected_arg != actual_arg:
+        raise Exception("Expected: %s - Actual: %s"
+                        % (expected_arg, actual_arg))
+
+    # The expectation list contains a mandatory return value and an optional
+    # callback for checking the context at the time of the call.
+    if len(expected_call) == len(args) + 2:
+      expected_call[len(args) + 1]()
+    return expected_call[len(args)]
+
+  def AssertFinished(self):
+    if self._index < len(self._recipe) -1:
+      raise Exception("Called %s too seldom: %d vs. %d"
+                      % (self._name, self._index, len(self._recipe)))
+
+
 class ScriptTest(unittest.TestCase):
   def MakeEmptyTempFile(self):
     handle, name = tempfile.mkstemp()
@@ -199,26 +245,12 @@
     return name
 
   def MakeStep(self, step_class=Step, state=None):
-    state = state or {}
-    step = step_class()
-    step.SetConfig(TEST_CONFIG)
-    step.SetState(state)
-    step.SetNumber(0)
-    step.SetSideEffectHandler(self)
-    return step
+    """Convenience wrapper."""
+    return MakeStep(step_class=step_class, number=0, state=state,
+                    config=TEST_CONFIG, options=None, side_effect_handler=self)
 
   def GitMock(self, cmd, args="", pipe=True):
-    self._git_index += 1
-    try:
-      git_invocation = self._git_recipe[self._git_index]
-    except IndexError:
-      raise Exception("Calling git %s" % args)
-    if git_invocation[0] != args:
-      raise Exception("Expected: %s - Actual: %s" % (git_invocation[0], args))
-    if len(git_invocation) == 3:
-      # Run optional function checking the context during this git command.
-      git_invocation[2]()
-    return git_invocation[1]
+    return self._git_mock.Call(args)
 
   def LogMock(self, cmd, args=""):
     print "Log: %s %s" % (cmd, args)
@@ -232,17 +264,27 @@
     return ScriptTest.MOCKS[cmd](self, cmd, args)
 
   def ReadLine(self):
-    self._rl_index += 1
-    try:
-      return self._rl_recipe[self._rl_index]
-    except IndexError:
-      raise Exception("Calling readline too often")
+    return self._rl_mock.Call()
+
+  def ReadURL(self, url):
+    return self._url_mock.Call(url)
+
+  def ExpectGit(self, *args):
+    """Convenience wrapper."""
+    self._git_mock.Expect(*args)
+
+  def ExpectReadline(self, *args):
+    """Convenience wrapper."""
+    self._rl_mock.Expect(*args)
+
+  def ExpectReadURL(self, *args):
+    """Convenience wrapper."""
+    self._url_mock.Expect(*args)
 
   def setUp(self):
-    self._git_recipe = []
-    self._git_index = -1
-    self._rl_recipe = []
-    self._rl_index = -1
+    self._git_mock = SimpleMock("git")
+    self._rl_mock = SimpleMock("readline")
+    self._url_mock = SimpleMock("readurl")
     self._tmp_files = []
 
   def tearDown(self):
@@ -253,12 +295,9 @@
       if os.path.exists(name):
         os.remove(name)
 
-    if self._git_index < len(self._git_recipe) -1:
-      raise Exception("Called git too seldom: %d vs. %d" %
-                      (self._git_index, len(self._git_recipe)))
-    if self._rl_index < len(self._rl_recipe) -1:
-      raise Exception("Too little input: %d vs. %d" %
-                      (self._rl_index, len(self._rl_recipe)))
+    self._git_mock.AssertFinished()
+    self._rl_mock.AssertFinished()
+    self._url_mock.AssertFinished()
 
   def testPersistRestore(self):
     self.MakeStep().Persist("test1", "")
@@ -270,12 +309,12 @@
     self.assertTrue(Command("git", "--version").startswith("git version"))
 
   def testGitMock(self):
-    self._git_recipe = [["--version", "git version 1.2.3"], ["dummy", ""]]
+    self.ExpectGit([["--version", "git version 1.2.3"], ["dummy", ""]])
     self.assertEquals("git version 1.2.3", self.MakeStep().Git("--version"))
     self.assertEquals("", self.MakeStep().Git("dummy"))
 
   def testCommonPrepareDefault(self):
-    self._git_recipe = [
+    self.ExpectGit([
       ["status -s -uno", ""],
       ["status -s -b -uno", "## some_branch"],
       ["svn fetch", ""],
@@ -283,33 +322,33 @@
       ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""],
       ["checkout -b %s" % TEST_CONFIG[TEMP_BRANCH], ""],
       ["branch", ""],
-    ]
-    self._rl_recipe = ["Y"]
+    ])
+    self.ExpectReadline(["Y"])
     self.MakeStep().CommonPrepare()
     self.MakeStep().PrepareBranch()
     self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
 
   def testCommonPrepareNoConfirm(self):
-    self._git_recipe = [
+    self.ExpectGit([
       ["status -s -uno", ""],
       ["status -s -b -uno", "## some_branch"],
       ["svn fetch", ""],
       ["branch", "  branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]],
-    ]
-    self._rl_recipe = ["n"]
+    ])
+    self.ExpectReadline(["n"])
     self.MakeStep().CommonPrepare()
     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
     self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
 
   def testCommonPrepareDeleteBranchFailure(self):
-    self._git_recipe = [
+    self.ExpectGit([
       ["status -s -uno", ""],
       ["status -s -b -uno", "## some_branch"],
       ["svn fetch", ""],
       ["branch", "  branch1\n* %s" % TEST_CONFIG[TEMP_BRANCH]],
       ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], None],
-    ]
-    self._rl_recipe = ["Y"]
+    ])
+    self.ExpectReadline(["Y"])
     self.MakeStep().CommonPrepare()
     self.assertRaises(Exception, self.MakeStep().PrepareBranch)
     self.assertEquals("some_branch", self.MakeStep().Restore("current_branch"))
@@ -357,21 +396,18 @@
     TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
     TEST_CONFIG[CHANGELOG_ENTRY_FILE] = self.MakeEmptyTempFile()
 
-    self._git_recipe = [
+    self.ExpectGit([
       ["log 1234..HEAD --format=%H", "rev1\nrev2\nrev3"],
-      ["log -1 rev1 --format=\"%w(80,8,8)%s\"", "        Title text 1"],
+      ["log -1 rev1 --format=\"%s\"", "Title text 1"],
       ["log -1 rev1 --format=\"%B\"", "Title\n\nBUG=\nLOG=y\n"],
-      ["log -1 rev1 --format=\"%w(80,8,8)(%an)\"",
-       "        author1@chromium.org"],
-      ["log -1 rev2 --format=\"%w(80,8,8)%s\"", "        Title text 2"],
+      ["log -1 rev1 --format=\"%an\"", "author1@chromium.org"],
+      ["log -1 rev2 --format=\"%s\"", "Title text 2"],
       ["log -1 rev2 --format=\"%B\"", "Title\n\nBUG=123\nLOG= \n"],
-      ["log -1 rev2 --format=\"%w(80,8,8)(%an)\"",
-       "        author2@chromium.org"],
-      ["log -1 rev3 --format=\"%w(80,8,8)%s\"", "        Title text 3"],
+      ["log -1 rev2 --format=\"%an\"", "author2@chromium.org"],
+      ["log -1 rev3 --format=\"%s\"", "Title text 3"],
       ["log -1 rev3 --format=\"%B\"", "Title\n\nBUG=321\nLOG=true\n"],
-      ["log -1 rev3 --format=\"%w(80,8,8)(%an)\"",
-       "        author3@chromium.org"],
-    ]
+      ["log -1 rev3 --format=\"%an\"", "author3@chromium.org"],
+    ])
 
     self.MakeStep().Persist("last_push", "1234")
     self.MakeStep(PrepareChangeLog).Run()
@@ -394,15 +430,15 @@
 # All lines starting with # will be stripped\\.
 #
 #       Title text 1
-#       author1@chromium\\.org
+#       \\(author1@chromium\\.org\\)
 #
 #       Title text 2
 #       \\(Chromium issue 123\\)
-#       author2@chromium\\.org
+#       \\(author2@chromium\\.org\\)
 #
 #       Title text 3
 #       \\(Chromium issue 321\\)
-#       author3@chromium\\.org
+#       \\(author3@chromium\\.org\\)
 #
 #"""
 
@@ -419,9 +455,9 @@
     TextToFile("  New  \n\tLines  \n", TEST_CONFIG[CHANGELOG_ENTRY_FILE])
     os.environ["EDITOR"] = "vi"
 
-    self._rl_recipe = [
+    self.ExpectReadline([
       "",  # Open editor.
-    ]
+    ])
 
     self.MakeStep(EditChangeLog).Run()
 
@@ -432,9 +468,9 @@
     TEST_CONFIG[VERSION_FILE] = self.MakeTempVersionFile()
     self.MakeStep().Persist("build", "5")
 
-    self._rl_recipe = [
+    self.ExpectReadline([
       "Y",  # Increment build number.
-    ]
+    ])
 
     self.MakeStep(IncrementVersion).Run()
 
@@ -470,9 +506,9 @@
       f.write("        Performance and stability improvements on all "
               "platforms.\n")
 
-    self._git_recipe = [
+    self.ExpectGit([
       ["diff svn/trunk hash1", "patch content"],
-    ]
+    ])
 
     self.MakeStep().Persist("prepare_commit_hash", "hash1")
     self.MakeStep().Persist("date", "1999-11-11")
@@ -505,7 +541,7 @@
       self.assertTrue(re.search(r"Version 3.22.5", cl))
       self.assertTrue(re.search(r"        Log text 1", cl))
       self.assertTrue(re.search(r"        \(issue 321\)", cl))
-      self.assertFalse(re.search(r"        author1@chromium\.org", cl))
+      self.assertFalse(re.search(r"        \(author1@chromium\.org\)", cl))
 
       # Make sure all comments got stripped.
       self.assertFalse(re.search(r"^#", cl, flags=re.M))
@@ -528,7 +564,7 @@
       self.assertTrue(re.search(r"#define IS_CANDIDATE_VERSION\s+0", version))
 
     force_flag = " -f" if force else ""
-    self._git_recipe = [
+    self.ExpectGit([
       ["status -s -uno", ""],
       ["status -s -b -uno", "## some_branch\n"],
       ["svn fetch", ""],
@@ -540,10 +576,9 @@
       ["log -1 --format=%H ChangeLog", "1234\n"],
       ["log -1 1234", "Last push ouput\n"],
       ["log 1234..HEAD --format=%H", "rev1\n"],
-      ["log -1 rev1 --format=\"%w(80,8,8)%s\"", "        Log text 1.\n"],
+      ["log -1 rev1 --format=\"%s\"", "Log text 1.\n"],
       ["log -1 rev1 --format=\"%B\"", "Text\nLOG=YES\nBUG=v8:321\nText\n"],
-      ["log -1 rev1 --format=\"%w(80,8,8)(%an)\"",
-       "        author1@chromium.org\n"],
+      ["log -1 rev1 --format=\"%an\"", "author1@chromium.org\n"],
       [("commit -a -m \"Prepare push to trunk.  "
         "Now working on version 3.22.6.\""),
        " 2 files changed\n",
@@ -575,8 +610,8 @@
       ["branch -D %s" % TEST_CONFIG[TEMP_BRANCH], ""],
       ["branch -D %s" % TEST_CONFIG[BRANCHNAME], ""],
       ["branch -D %s" % TEST_CONFIG[TRUNKBRANCH], ""],
-    ]
-    self._rl_recipe = [
+    ])
+    self.ExpectReadline([
       "Y",  # Confirm last push.
       "",  # Open editor.
       "Y",  # Increment build number.
@@ -585,13 +620,13 @@
       "LGTM",  # Enter LGTM for V8 CL.
       "Y",  # Sanity check.
       "reviewer@chromium.org",  # Chromium reviewer.
-    ]
+    ])
     if force:
       # TODO(machenbach): The lgtm for the prepare push is just temporary.
       # There should be no user input in "force" mode.
-      self._rl_recipe = [
+      self.ExpectReadline([
         "LGTM",  # Enter LGTM for V8 CL.
-      ]
+      ])
 
     class Options( object ):
       pass
@@ -622,3 +657,32 @@
 
   def testPushToTrunkForced(self):
     self._PushToTrunk(force=True)
+
+  def testAutoRoll(self):
+    TEST_CONFIG[DOT_GIT_LOCATION] = self.MakeEmptyTempFile()
+
+    # TODO(machenbach): Get rid of the editor check in automatic mode.
+    os.environ["EDITOR"] = "vi"
+
+    self.ExpectReadURL([
+      ["https://v8-status.appspot.com/lkgr", "100"],
+    ])
+
+    self.ExpectGit([
+      ["status -s -uno", ""],
+      ["status -s -b -uno", "## some_branch\n"],
+      ["svn fetch", ""],
+      ["svn log -1 --oneline", "r101 | Text"],
+    ])
+
+    # TODO(machenbach): Make a convenience wrapper for this.
+    class Options( object ):
+      pass
+
+    options = Options()
+    options.s = 0
+
+    auto_roll.RunAutoRoll(TEST_CONFIG, options, self)
+
+    self.assertEquals("100", self.MakeStep().Restore("lkgr"))
+    self.assertEquals("101", self.MakeStep().Restore("latest"))